/** * \file rasterize.cpp * * \brief Implementation des Software-Rasterizers * * Für eine detailierte Beschreibung von Rasterizer und * Software-Rasterizer schauen Sie bitte unter \ref rasterize.h * * \author Georg Steffers [gs] * * \date 04.12.2003 * * \version ..2002 [gs]: erste funktionierende Implementation * \version 04.12.2003 [gs]: beginn der Dokumentation via doxygen * \version 16.12.2003 [gs]: * \version 19.12.2003 [gs]: * * \todo (siehe \ref draw_polygon_flat) */ /* * Copyright (C)2003 Georg Steffers * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using namespace std; #include #include #include #include #include #include "geometry/polygon.h" #include "rasterize.h" #define CLIP_MASK_LEFT (0x1<<0) #define CLIP_MASK_RIGHT (0x1<<1) #define CLIP_MASK_BOTTOM (0x1<<2) #define CLIP_MASK_TOP (0x1<<3) rasterizer::rasterizer(unsigned xs, unsigned ys, canvas_imp* ci) { x_size=xs; y_size=ys; sinfo=ci; zbuf=new (double*)[xs]; for(unsigned i=0; ip_screenbuf + (x+(y*x_size))*sinfo->bytes_per_pixel; } void sw_rasterizer::draw_point_at_paddress(unsigned char** p, unsigned long col) const { unsigned long mask = 0xFF; char shift = 0; // farbytes in Little-Endian order in den Puffer for(int i=0; ibytes_per_pixel; i++) { **p = (col & mask) >> shift; (*p)++; mask <<= 8; shift += 8; } } void sw_rasterizer::clear_buffer(void) const { memset(sinfo->p_screenbuf, 0x00, (size_t)x_size*y_size*sinfo->bytes_per_pixel); for(unsigned i=0; ix_size-1; unsigned y_size=this->y_size-1; if(ax<0) clip_mask_a |= CLIP_MASK_LEFT; if(ax>x_size) clip_mask_a |= CLIP_MASK_RIGHT; if(ay>y_size) clip_mask_a |= CLIP_MASK_BOTTOM; if(ay<0) clip_mask_a |= CLIP_MASK_TOP; if(bx<0) clip_mask_b |= CLIP_MASK_LEFT; if(bx>x_size) clip_mask_b |= CLIP_MASK_RIGHT; if(by>y_size) clip_mask_b |= CLIP_MASK_BOTTOM; if(by<0) clip_mask_b |= CLIP_MASK_TOP; if((clip_mask_a & clip_mask_b) != 0) return; double dx=bx-ax; double dy=by-ay; double xinc=dx/dy; double yinc=dy/dx; if(clip_mask_a != 0) { if((clip_mask_a&CLIP_MASK_LEFT)!=0) { ay+=(0-ax)*yinc; ax=0; } else if(clip_mask_a & CLIP_MASK_RIGHT) { ay+=(x_size-ax)*yinc; ax=x_size; } clip_mask_a=0; if(ax<0) clip_mask_a |= CLIP_MASK_LEFT; if(ax>x_size) clip_mask_a |= CLIP_MASK_RIGHT; if(ay>y_size) clip_mask_a |= CLIP_MASK_BOTTOM; if(ay<0) clip_mask_a |= CLIP_MASK_TOP; if(clip_mask_a & CLIP_MASK_TOP) { ax+=(0-ay)*xinc; ay=0; } else if(clip_mask_a & CLIP_MASK_BOTTOM) { ax+=(y_size-ay)*xinc; ay=y_size; } } if(clip_mask_b != 0) { if(clip_mask_b & CLIP_MASK_LEFT) { by+=(0-bx)*yinc; bx=0; } else if(clip_mask_b & CLIP_MASK_RIGHT) { by+=(x_size-bx)*yinc; bx=x_size; } clip_mask_b=0; if(bx<0) clip_mask_b |= CLIP_MASK_LEFT; if(bx>x_size) clip_mask_b |= CLIP_MASK_RIGHT; if(by>y_size) clip_mask_b |= CLIP_MASK_BOTTOM; if(by<0) clip_mask_b |= CLIP_MASK_TOP; if(clip_mask_b & CLIP_MASK_TOP) { bx+=(0-by)*xinc; by=0; } else if(clip_mask_b & CLIP_MASK_BOTTOM) { bx+=(y_size-by)*xinc; by=y_size; } } clip_mask_a=0; if(ax<0) clip_mask_a |= CLIP_MASK_LEFT; if(ax>x_size) clip_mask_a |= CLIP_MASK_RIGHT; if(ay>y_size) clip_mask_a |= CLIP_MASK_BOTTOM; if(ay<0) clip_mask_a |= CLIP_MASK_TOP; clip_mask_b=0; if(bx<0) clip_mask_b |= CLIP_MASK_LEFT; if(bx>x_size) clip_mask_b |= CLIP_MASK_RIGHT; if(by>y_size) clip_mask_b |= CLIP_MASK_BOTTOM; if(by<0) clip_mask_b |= CLIP_MASK_TOP; if((clip_mask_a | clip_mask_b) == (CLIP_MASK_LEFT | CLIP_MASK_TOP) || (clip_mask_a | clip_mask_b) == (CLIP_MASK_LEFT | CLIP_MASK_BOTTOM) || (clip_mask_a | clip_mask_b) == (CLIP_MASK_RIGHT | CLIP_MASK_TOP) || (clip_mask_a | clip_mask_b) == (CLIP_MASK_RIGHT | CLIP_MASK_BOTTOM)) return; /* ----------- */ /* Linie nach Bresenham */ int Ax=(int)ax; int Bx=(int)bx; int Ay=(int)ay; int By=(int)by; int dX = abs(Bx-Ax); int dY = abs(By-Ay); int Xincr=(Ax > Bx)?-1:1; int Yincr=(Ay > By)?-1:1; if (dX >= dY) { int dPr = dY<<1; int dPru = dPr - (dX<<1); int P = dPr - dX; for (; dX>=0; dX--) { draw_point(Ax, Ay, col); if (P > 0) { Ax+=Xincr; Ay+=Yincr; P+=dPru; } else { Ax+=Xincr; P+=dPr; } } } else { int dPr = dX<<1; int dPru = dPr - (dY<<1); int P = dPr - dY; for (; dY>=0; dY--) { draw_point(Ax, Ay, col); if (P > 0) { Ax+=Xincr; Ay+=Yincr; P+=dPru; } else { Ay+=Yincr; P+=dPr; } } } /*------------------*/ } void sw_rasterizer::draw_polygon_wire(const polygon& p, unsigned long col) const { for(unsigned i=0; iclipped[bottom][Y])?i:bottom; } for(unsigned i=1; ip[gr_v2][X] && p[gr_v1][Y]>=p[gr_v2][Y]) || (p[gr_v1][X](gr_v1, gr_v2); double dx21=p[gr_v2][X]-p[gr_v1][X]; double dx10=p[gr_v1][X]-p[gr_v0][X]; double dy21=p[gr_v2][Y]-p[gr_v1][Y]; double dy01=p[gr_v0][Y]-p[gr_v1][Y]; double d_z21=p[gr_v2][Z]-p[gr_v1][Z]; double d_z10=p[gr_v1][Z]-p[gr_v0][Z]; double dx01=p[gr_v0][X]-p[gr_v1][X]; double dy10=p[gr_v1][Y]-p[gr_v0][Y]; double v3_x=p[gr_v0][X]; double v4_y=p[gr_v0][Y]; double v3_y=((dy21*dx01) / dx21) + p[gr_v1][Y]; double v3_z=((d_z21*dx01) / dx21) + p[gr_v1][Z]; double v4_x=((dx21*dy01) / dy21) + p[gr_v1][X]; double v4_z=((d_z21*dy01) / dy21) + p[gr_v1][Z]; // zuallererst müsste ich mal überprüfen ob alle drei Punkte in // einer Linie liegen, also dx01/dy01 == dx02/dy02 ist...da ich aber // noch nicht weiss wie ich diesen Fall behandeln soll ignorier ich // ihn im moment und nehme die entstehenden Fehler in kauf. double d_zdx_denominator=0; double d_zdy_denominator=0; double d_zdx, d_zdy; // zuerst dc/dx ermitteln. (einfach wenn y1==y2) // zu den Bezeichnern: _x == 1/x, _? == 1/? if(p[gr_v0][Y] == p[gr_v1][Y]) d_zdx=(p[gr_v1][Z]-p[gr_v0][Z]) / (p[gr_v1][X]-p[gr_v0][X]); else if(p[gr_v0][Y] == p[gr_v2][Y]) d_zdx=(p[gr_v2][Z]-p[gr_v0][Z]) / (p[gr_v2][X]-p[gr_v0][X]); else if(p[gr_v1][Y] == p[gr_v2][Y]) d_zdx=(p[gr_v2][Z]-p[gr_v1][Z]) / (p[gr_v2][X]-p[gr_v1][X]); else { d_zdx_denominator=(dx21*dy01)+(dx10*dy21); d_zdx=((d_z21*dy01)+(d_z10*dy21))/d_zdx_denominator; } // jetzt dc/dy...(einfach falls es eine Sekrechte gibt.) if(p[gr_v0][X] == p[gr_v1][X]) d_zdy=(p[gr_v1][Z]-p[gr_v0][Z]) / p[gr_v1][Y]-p[gr_v0][Y]; else if(p[gr_v0][X] == p[gr_v2][X]) d_zdy=(p[gr_v2][Z]-p[gr_v0][Z]) / p[gr_v2][Y]-p[gr_v0][Y]; else if(p[gr_v1][X] == p[gr_v2][X]) d_zdy=(p[gr_v2][Z]-p[gr_v1][Z]) / p[gr_v2][Y]-p[gr_v1][Y]; else { d_zdy_denominator=d_zdx_denominator!=0?-d_zdx_denominator: (dy21*dx01)+(dy10*dx21); d_zdy=((d_z21*dx01)+(d_z10*dx21))/d_zdy_denominator; } /* if(!strncmp(p.get_id(), "DEBUG", 29)) { cout << "---Polygon: " << &p << "----------\n"; for(unsigned i=0; i0 und // das linke und rechte x-Increment ermitteln. if((int)ceil(clipped[end_left][Y]) == act_ceily) { do { start_left=end_left; if(start_left == bottom) { return; } end_left=(end_left-1<0)?end_left-1+clipped.card():end_left-1; } while((int)ceil(clipped[end_left][Y]) == act_ceily); act_y=clipped[start_left][Y]; act_ceily=(int)ceil(act_y); x_inc_l=(clipped[end_left][X]-clipped[start_left][X])/ (clipped[end_left][Y]-clipped[start_left][Y]); z_inc_l=x_inc_l*d_zdx; act_x_l=clipped[start_left][X]; // Subpixelkorrektur act_x_l+=((double)act_ceily-act_y)*x_inc_l; act_z_l=clipped[start_left][Z]; act_z_l+=((double)act_ceily-act_y)*z_inc_l; } if((int)ceil(clipped[end_right][Y]) == act_ceily) { do { start_right=end_right; if(start_right == bottom) { return; } end_right=(end_right+1)%clipped.card(); } while((int)ceil(clipped[end_right][Y]) == act_ceily); act_y=clipped[start_right][Y]; act_ceily=(int)ceil(act_y); x_inc_r=(clipped[end_right][X]-clipped[start_right][X])/ (clipped[end_right][Y]-clipped[start_right][Y]); z_inc_r=x_inc_r*d_zdx; act_x_r=clipped[start_right][X]; // Subpixelkorrektur act_x_r+=((double)act_ceily-act_y)*x_inc_r; act_z_r=clipped[start_right][Z]; act_z_r+=((double)act_ceily-act_y)*z_inc_r; } // bis zu welchem der beiden Vertexe (links o. rechts) muss ich? unsigned togo=((int)ceil(clipped[end_left][Y])-act_ceily <= (int)ceil(clipped[end_right][Y])-act_ceily)? end_left:end_right; for(; act_ceily < (int)ceil(clipped[togo][Y]); act_ceily++) { unsigned char* adr=adr_of_point((act_x_l _Z) { draw_point_at_paddress(&adr, col); zbuf[_X+i][act_ceily]=_Z; //} // if(!strncmp(p.get_id(), "DEBUG", 29)) { // printf("%03ld,%03ld,%10.7f ", _X+i, act_ceily, act_row_z); // } act_row_z+=d_zdx; } act_x_l+=x_inc_l; act_x_r+=x_inc_r; act_z_l+=z_inc_l; act_z_l+=d_zdy; act_z_r+=z_inc_r; act_z_r+=d_zdy; // if(!strncmp(p.get_id(), "DEBUG", 29)) { // cout << "\n"; // } } } //} }