/* * TEXTURE.C Version 1.0 by Lee Lorenz llorenz@delphi.com * * First, Please excuse this mess. * * Next, Welcome to high-speed image processing... My desire was to * rotate/scale a bitmap in real-time, and this was the result. * There were plenty of "examples" of texture mapping, in obfuscated * highly optimized assembly, but even the "C" and Pascal examples left * alot to be desired; after all, I wanted to have more freedom to display * images, and didn't want to bother with the trigonometry. With the simple * idea of "shooting" a line (Bresenham-style) through a source bitmap, I * developed this technique contained in DrawTexture. It may not be original, * but I haven't seen it used anywhere else. It can even be augmented with * anti-aliasing for image processing. I release this program and technique * into the public domain, and I hope to create a highly optimized 386 * assembler version for my personal library. Please try to credit me when * possible, if this shows you anything new or interesting, and you use it * in any distributed program (Freeware/shareware/commercial). * * What this program does: * Draws a bitmap into any 4-sided polygon. First vector is upper-left * second is upper-right, third is lower-right, and last is lower-left. * * Limitations: * Don't try to use a "Horizontally convex" polygon. * Undefined results with intersected polygons * * What remains to be done: * 1. A good intersection-detection routine. * 2. A quick 2-D rotation/scaling transform for the corners. I want to * be able to "spin" the bitmap/sprite about a point. * 3. Possible, slower alternative to scan "horizontal convex" polygons * and intersected polygons * */ #include #include #include #include #include #include #include #include #include #include int YZSize; struct { char filename[80]; int sizex; int sizey; unsigned char *buff; unsigned char *pal; } slots[64]; struct text_s { unsigned char *Buffer; int XSize,YSize; } MyMap; struct quad_s { int x[4],y[4]; } MyPoly; void DrawTexture(struct quad_s *poly,struct text_s *Texture,int debug); void OrderPoly(struct quad_s *poly,unsigned char *order); /* This routine eliminates intersections by swapping corners * if an intersection exists... * "adjacent" segments, by nature, cannot intersect, therefore we only * need to check opposite segments (AB,CD & DA,BC) * Actually, in retrospect, the poly cannot have "horizontal convexity" * That is, the scan algorithm cannot handle more than one chunk, Our * test, there for is for opposite corners _NOT_ to be next to one another * when ordered... */ void UnIntersectQuad(struct quad_s *poly) { unsigned char work_order[4]; int i; OrderPoly(poly,work_order); /* Top Convexity/intersection */ switch(work_order[0]) { case 0: /* Test to insure 2 is not adjacent */ if(work_order[1]==2) { /* Swap 1 and 2 */ i=poly->x[1]; poly->x[1]=poly->x[2]; poly->x[2]=i; i=poly->y[1]; poly->y[1]=poly->y[2]; poly->y[2]=i; } break; case 1: /* Test to insure 3 is not adjacent */ if(work_order[1]==3) { /* Swap 0 and 3 */ i=poly->x[0]; poly->x[0]=poly->x[3]; poly->x[3]=i; i=poly->y[0]; poly->y[0]=poly->y[3]; poly->y[3]=i; } break; case 2: /* Test to insure 0 is not adjacent */ if(work_order[1]==0) { /* Swap 1 and 2 */ i=poly->x[1]; poly->x[1]=poly->x[2]; poly->x[2]=i; i=poly->y[1]; poly->y[1]=poly->y[2]; poly->y[2]=i; } break; case 3: /* Test to insure 1 is not adjacent */ if(work_order[1]==1) { /* Swap 0 and 3 */ i=poly->x[0]; poly->x[0]=poly->x[3]; poly->x[3]=i; i=poly->y[0]; poly->y[0]=poly->y[3]; poly->y[3]=i; } break; } OrderPoly(poly,work_order); /* BOTTOM Convexity/intersection */ switch(work_order[3]) { case 0: /* Test to insure 2 is not adjacent */ if(work_order[2]==2) { /* Swap 1 and 2 */ i=poly->x[1]; poly->x[1]=poly->x[2]; poly->x[2]=i; i=poly->y[1]; poly->y[1]=poly->y[2]; poly->y[2]=i; } break; case 1: /* Test to insure 3 is not adjacent */ if(work_order[2]==3) { /* Swap 0 and 3 */ i=poly->x[0]; poly->x[0]=poly->x[3]; poly->x[3]=i; i=poly->y[0]; poly->y[0]=poly->y[3]; poly->y[3]=i; } break; case 2: /* Test to insure 0 is not adjacent */ if(work_order[2]==0) { /* Swap 1 and 2 */ i=poly->x[1]; poly->x[1]=poly->x[2]; poly->x[2]=i; i=poly->y[1]; poly->y[1]=poly->y[2]; poly->y[2]=i; } break; case 3: /* Test to insure 1 is not adjacent */ if(work_order[2]==1) { /* Swap 0 and 3 */ i=poly->x[0]; poly->x[0]=poly->x[3]; poly->x[3]=i; i=poly->y[0]; poly->y[0]=poly->y[3]; poly->y[3]=i; } break; } /* Now for intersection test... */ } int LoadSlot(int sl,char *fname); void setcolor(unsigned char c,unsigned char r,unsigned char g,unsigned char b); int lastlength,lastdelta; unsigned char *ScreenPtr; struct Pal_s { unsigned char Red; unsigned char Blue; unsigned char Green; }; /* This algorithm is based on the calculation of the third side of a triangle given the known two sides are connected by a right angle. This formula is: a^2+b^2=c^2. a and b are the absolute X-Y deltas. The first calcluation of c then becomes a, and Z delta becomes b, and we do it again. While we _HAVE_ to calculate the squares, it is not needed to calc the roots. i.e. Deltas of 1+1+5=7, 1+2+4=7, but distance is less on second... 27 21 Thus, we simply add the squares of all of the absolute deltas. */ int FindBestMatch(struct Pal_s *Pal,int r,int g,int b) { int Distance,i,j,k,R,G,B; k=12288; j=0; for(i=0;i<256;i++) { R=abs(Pal[i].Red-r); R*=R; G=abs(Pal[i].Green-g); G*=G; B=abs(Pal[i].Blue-b); B*=B; Distance=R+G+B; if(Distancex[0],Poly->y[0],Poly->x[1],Poly->y[1],c); GrLine(Poly->x[1],Poly->y[1],Poly->x[2],Poly->y[2],c); GrLine(Poly->x[2],Poly->y[2],Poly->x[3],Poly->y[3],c); GrLine(Poly->x[3],Poly->y[3],Poly->x[0],Poly->y[0],c); GrPlot(Poly->x[0],Poly->y[0],c); } unsigned char Order[4]; int WhiteColor,RedColor,BlackColor,GrayColor; int rcount,lcount,rva[8],rvb[8],lva[8],lvb[8],rcnt[8],lcnt[0]; #define ROTATIONS 30 /* I wish DJGPP had a decent random macro!!!! * I'll get a 32-bit version done soon */ #define RAND(x) (rand()%x) int NewDir(int x,int y,int olddir); int UpdateX(int x,int direction); int UpdateY(int y,int direction); void main(void) { long DeltaX,DeltaY,XSize,YSize; int i,j,k,NewY; GrContext ScrCtx; unsigned char *RPtr; unsigned char *BuffPtr; for(i=0;i<64;i++) { slots[i].filename[0]=0; slots[i].pal=NULL; slots[i].buff=NULL; slots[i].sizex=0; slots[i].sizey=0; } GrSetMode(GR_default_graphics); LoadSlot(0,"bnbtitle.gif"); MyMap.Buffer=slots[0].buff; MyMap.XSize=slots[0].sizex; MyMap.YSize=slots[0].sizey; for(i=0;i<256;i++) { slots[0].pal[i*3]/=4; slots[0].pal[(i*3)+1]/=4; slots[0].pal[(i*3)+2]/=4; setcolor(i, slots[0].pal[i*3], slots[0].pal[(i*3)+1], slots[0].pal[(i*3)+2]); } WhiteColor=FindBestMatch((struct Pal_s *)slots[0].pal,63,63,63); RedColor=FindBestMatch((struct Pal_s *)slots[0].pal,63,13,13); BlackColor=FindBestMatch((struct Pal_s *)slots[0].pal,0,0,0); GrayColor=FindBestMatch((struct Pal_s *)slots[0].pal,30,30,30); GrSaveContext(&ScrCtx); ScreenPtr=ScrCtx.gc_baseaddr; RPtr=ScreenPtr; XSize=slots[0].sizex*65536; YSize=slots[0].sizey*65536; DeltaX=XSize/GrSizeX(); DeltaY=YSize/GrSizeY(); j=0; DeltaX=XSize/(GrSizeX()); RPtr=ScreenPtr; j=0; memset(RPtr,0,GrSizeX()*GrSizeY()); DeltaX=XSize/GrSizeX(); RPtr=ScreenPtr; memset(ScreenPtr,BlackColor,GrSizeX()*GrSizeY()); MyPoly.x[0]=GrSizeX()/10; MyPoly.x[1]=GrSizeX()-(GrSizeX()/15); MyPoly.x[2]=GrSizeX()-(GrSizeX()/5); MyPoly.x[3]=GrSizeX()/12; MyPoly.y[0]=GrSizeY()/20; MyPoly.y[1]=GrSizeY()/10; MyPoly.y[2]=GrSizeY()-(GrSizeY()/15); MyPoly.y[3]=GrSizeY()-(GrSizeY()/25); DrawPoly(&MyPoly,WhiteColor); DrawTexture(&MyPoly,&MyMap,0); while(!kbhit()) { rand(); for(i=0;i=GrMaxY()) { return(1); } return(RAND(3)+1); } } else { if(x>=GrMaxX()) { if(y<=0) { return(5); } else { if(y>=GrMaxY()) { return(7); } return(RAND(3)+5); } } else { if(y<=0) { return(RAND(3)+3); } else { if(y>=GrMaxY()) { olddir=RAND(3); if(olddir==2) olddir=7; return(olddir); } return(olddir); } } } } /* * Convenience function... update the X-Co-ord given a direction */ int UpdateX(int x,int direction) { switch(direction) { case 0: /* UP */ case 4: return(x); break; case 1: /* UP-RIGHT */ case 2: case 3: return(x+1); break; case 5: case 6: case 7: return(x-1); break; } } /* * Convenience function... update the Y-Co-ord given a direction */ int UpdateY(int y,int direction) { switch(direction) { case 2: case 6: return(y); break; case 0: /* UP */ case 1: /* UP-RIGHT */ case 7: return(y-1); break; case 3: case 4: case 5: return(y+1); break; } } /* * Program the RAMDAC 256-color palette. Seems like I'm _ALWAYS_ re-inventing * this one! */ void setcolor(unsigned char c,unsigned char r,unsigned char g,unsigned char b) { disable(); outportb(0x3c8,c); inportb(0x80); outportb(0x3c9,r); inportb(0x80); outportb(0x3c9,g); inportb(0x80); outportb(0x3c9,b); enable(); } /* * Fragment from my game/sprite system. Wraps a call to load a gif. * Sorry, but these routines will have to be replaced if you want to * directly compile it. Your best bet is to track down "GIFLIB" which * contains libraries and source for encoding/decoding gifs. It can * be converted to 32-Bit without toooo much pain (I managed it...) */ int LoadSlot(int sl,char *fname) { GifFileType GifFile; unsigned char *ptr1; unsigned char *ptr2; if(LoadGif(7,fname,&ptr1,(GifColorType **)&ptr2,&GifFile)) { return(-1); } /* Load was successful... */ if(slots[sl].pal) { free(slots[sl].pal); } if(slots[sl].buff) { free(slots[sl].buff); } strcpy(slots[sl].filename,fname); slots[sl].buff=ptr1; slots[sl].pal=ptr2; slots[sl].sizex=GifFile.SWidth; slots[sl].sizey=GifFile.SHeight; return(0); } /* * Return an array of vector IDs sorted by Y value */ void OrderPoly(struct quad_s *poly,unsigned char *order) { int i,j,x,y; for(i=0;i<4;i++) { order[i]=(unsigned char)i; } for(i=0;i<3;i++) { for(j=(i+1);j<4;j++) { if(poly->y[order[j]]y[order[i]]) { x=order[i]; order[i]=order[j]; order[j]=x; } } } } /* * General purpose linear conversion routine * I use a more complex version at work that reduces precision to prevent * overflows. */ long lconvert(long a,long b,long c) { if(b) { return((a*c)/b); } return(0); } /* * Return an arbitrary X point on a given line */ int XPoint(int x1,int y1,int x2,int y2,int ny) { int z; x2-=x1; y2-=y1; ny-=y1; z=lconvert(x2,y2,ny); return(z+x1); } /* * Return an arbitrary Y point on a given line */ int YPoint(int x1,int y1,int x2,int y2,int nx) { int z; x2-=x1; y2-=y1; nx-=x1; z=lconvert(y2,x2,nx); return(z+y1); } /* * Returns a floating point version of a 16.16 signed fixed point number */ float fixed2float(long z) { int sign; unsigned long whole,fraction; float result; sign=0; if(z<0) { sign=1; z=0-z; } whole=z>>16; fraction=z&0x0ffff; result=(float)(fraction); result/=65536.0; result+=(float)(whole); if(sign) result=0.0-result; return(result); } /* * What we do, is for each Screen Y, we draw a line of texture * * * This routine cannot handle "horizontal convexity", that is, when we * get two chunks to draw on the same scan line. The program will freak out, * so "UnIntersectQuad" is used to "remove" the convexity... normally, you * would just avoid this situation. Likewise, the routine doesn't like * intersections too much, but surprisingly, the program won't blow any * serious chunks, as long as the convexity is taken care of. Images can * be flipped, by re-ordering the corners of your polygon. * Polygon Co-ordinates can range from -32768 to 32767, as I use SIGNED * 16.16bit fixed point numbers. * * */ void DrawTexture(struct quad_s *poly,struct text_s *Texture,int debug) { long i,j,k,ysize; long LeftVectorA,LeftVectorB,RightVectorA,RightVectorB; long YCheck,LeftSegment,RightSegment,m,n,o,p,q,OSize; long LeftDelta,LeftStartX,RightDelta; long L_Size,R_Size,LeftBDeltaX,LeftBDeltaY; long RightBDeltaX,RightBDeltaY,RightXPos,RightYPos; long LeftXPos,LeftYPos,LeftCount,RightCount,LeftX,RightX; unsigned char *screenptr; lcount=rcount=1; OrderPoly(poly,Order); /* Order now holds points from top to bottom */ ysize=poly->y[Order[3]]-poly->y[Order[0]]; /* Total screen Y Size */ YZSize=ysize; if(ysize<3) /* Don't even try if too small */ return; YCheck=poly->y[Order[3]]; /* 'Lowest' Y+some amount */ /* Now, load data for first two segments... */ screenptr=ScreenPtr; i=GrSizeX()*poly->y[Order[0]]; screenptr+=i; i=0; j=0; k=0; m=(Order[0]+1)%4; n=(Order[0]+3)%4; while(i==j && k<3) { YCheck+=20; i=XPoint(poly->x[Order[0]],poly->y[Order[0]], poly->x[m],poly->y[m],YCheck); j=XPoint(poly->x[Order[0]],poly->y[Order[0]], poly->x[n],poly->y[n],YCheck); k++; } if(k==3) { /* Either, invalid, or flat line! */ i=poly->x[m]; j=poly->x[n]; if(i==j) return; /* Invalid polygon... */ } LeftVectorA=Order[0]; RightVectorA=Order[0]; if(iy[LeftVectorB]-poly->y[LeftVectorA]; RightCount=poly->y[RightVectorB]-poly->y[RightVectorA]; L_Size=LeftCount; R_Size=RightCount; i=poly->x[LeftVectorB]-poly->x[LeftVectorA]; LeftDelta=lconvert(i,LeftCount,65536); j=poly->x[RightVectorB]-poly->x[RightVectorA]; RightDelta=lconvert(j,RightCount,65536); LeftX=poly->x[LeftVectorA]*65536; RightX=LeftX; } else { LeftVectorB=n; RightVectorB=m; LeftCount=poly->y[LeftVectorB]-poly->y[LeftVectorA]; RightCount=poly->y[RightVectorB]-poly->y[RightVectorA]; L_Size=LeftCount; R_Size=RightCount; i=poly->x[LeftVectorB]-poly->x[LeftVectorA]; LeftDelta=lconvert(i,LeftCount,65536); j=poly->x[RightVectorB]-poly->x[RightVectorA]; RightDelta=lconvert(j,RightCount,65536); LeftX=poly->x[LeftVectorA]*65536; RightX=LeftX; } switch((LeftVectorA<<2)|LeftVectorB) { case 0: /* A-A Impossible */ case 2: /* A-C Impossible */ case 5: /* B-B Impossible */ case 7: /* B-D Impossible */ case 8: /* C-A Impossible */ case 10: /* C-C Impossible */ case 13: /* D-B impossible */ case 15: /* D-D Impossible */ break; case 1: /* A-B */ LeftBDeltaX=lconvert(Texture->XSize,L_Size,65536); LeftBDeltaY=0; LeftXPos=0; LeftYPos=0; break; case 3: /* A-D */ LeftBDeltaY=lconvert(Texture->YSize,L_Size,65536); LeftBDeltaX=0; LeftXPos=0; LeftYPos=0; break; case 4: /* B-A */ LeftBDeltaX=-lconvert(Texture->XSize,L_Size,65536); LeftBDeltaY=0; LeftXPos=Texture->XSize-1; LeftYPos=0; break; case 6: /* B-C */ LeftBDeltaY=lconvert(Texture->YSize,L_Size,65536); LeftBDeltaX=0; LeftXPos=Texture->XSize-1; LeftYPos=0; break; case 9: /* C-B */ LeftBDeltaY=-lconvert(Texture->YSize,L_Size,65536); LeftBDeltaX=0; LeftXPos=Texture->XSize-1; LeftYPos=Texture->YSize-1; break; case 11: /* C-D */ LeftBDeltaX=-lconvert(Texture->XSize,L_Size,65536); LeftBDeltaY=0; LeftXPos=Texture->XSize-1; LeftYPos=Texture->YSize-1; break; case 12: /* D-A */ LeftBDeltaY=-lconvert(Texture->YSize,L_Size,65536); LeftBDeltaX=0; LeftXPos=0; LeftYPos=Texture->YSize-1; break; case 14: /* D-C */ LeftBDeltaX=lconvert(Texture->XSize,L_Size,65536); LeftBDeltaY=0; LeftXPos=0; LeftYPos=Texture->YSize-1; break; } switch((RightVectorA<<2)|RightVectorB) { case 0: /* A-A Impossible */ case 2: /* A-C Impossible */ case 5: /* B-B Impossible */ case 7: /* B-D Impossible */ case 8: /* C-A Impossible */ case 10: /* C-C Impossible */ case 13: /* D-B impossible */ case 15: /* D-D Impossible */ break; case 1: /* A-B */ RightBDeltaX=lconvert(Texture->XSize,R_Size,65536); RightBDeltaY=0; RightXPos=0; RightYPos=0; break; case 3: /* A-D */ RightBDeltaY=lconvert(Texture->YSize,R_Size,65536); RightBDeltaX=0; RightXPos=0; RightYPos=0; break; case 4: /* B-A */ RightBDeltaX=-lconvert(Texture->XSize,R_Size,65536); RightBDeltaY=0; RightXPos=Texture->XSize-1; RightYPos=0; break; case 6: /* B-C */ RightBDeltaY=lconvert(Texture->YSize,R_Size,65536); RightBDeltaX=0; RightXPos=Texture->XSize-1; RightYPos=0; break; case 9: /* C-B */ RightBDeltaY=-lconvert(Texture->YSize,R_Size,65536); RightBDeltaX=0; RightXPos=Texture->XSize-1; RightYPos=Texture->YSize-1; break; case 11: /* C-D */ RightBDeltaX=-lconvert(Texture->XSize,R_Size,65536); RightBDeltaY=0; RightXPos=Texture->XSize-1; RightYPos=Texture->YSize-1; break; case 12: /* D-A */ RightBDeltaY=-lconvert(Texture->YSize,R_Size,65536); RightBDeltaX=0; RightXPos=0; RightYPos=Texture->YSize-1; break; case 14: /* D-C */ RightBDeltaX=lconvert(Texture->XSize,R_Size,65536); RightBDeltaY=0; RightXPos=0; RightYPos=Texture->YSize-1; break; } LeftXPos*=65536; LeftYPos*=65536; RightXPos*=65536; RightYPos*=65536; lva[0]=LeftVectorA; lvb[0]=LeftVectorB; rva[0]=RightVectorA; rvb[0]=RightVectorB; lcnt[0]=LeftCount; rcnt[0]=RightCount; for(i=0;iy[Order[0]]+i; if(m>GrMaxY()) break; if(!LeftCount) { /* Get next Left Vector */ j=LeftVectorB; k=(LeftVectorB+1)%4; if(k==LeftVectorA) { k=(LeftVectorB+3)%4; } LeftVectorA=j; LeftVectorB=k; LeftX=poly->x[LeftVectorA]*65536; LeftCount=poly->y[LeftVectorB]-poly->y[LeftVectorA]; lva[lcount]=LeftVectorA; lvb[lcount]=LeftVectorB; lcnt[lcount]=LeftCount; lcount++; j=poly->x[LeftVectorB]-poly->x[LeftVectorA]; L_Size=LeftCount; LeftDelta=lconvert(j,LeftCount,65536); switch((LeftVectorA<<2)|LeftVectorB) { case 0: /* A-A Impossible */ case 2: /* A-C Impossible */ case 5: /* B-B Impossible */ case 7: /* B-D Impossible */ case 8: /* C-A Impossible */ case 10: /* C-C Impossible */ case 13: /* D-B impossible */ case 15: /* D-D Impossible */ break; case 1: /* A-B */ LeftBDeltaX=lconvert(Texture->XSize,L_Size,65536); LeftBDeltaY=0; LeftXPos=0; LeftYPos=0; break; case 3: /* A-D */ LeftBDeltaY=lconvert(Texture->YSize,L_Size,65536); LeftBDeltaX=0; LeftXPos=0; LeftYPos=0; break; case 4: /* B-A */ LeftBDeltaX=-lconvert(Texture->XSize,L_Size,65536); LeftBDeltaY=0; LeftXPos=Texture->XSize-1; LeftYPos=0; break; case 6: /* B-C */ LeftBDeltaY=lconvert(Texture->YSize,L_Size,65536); LeftBDeltaX=0; LeftXPos=Texture->XSize-1; LeftYPos=0; break; case 9: /* C-B */ LeftBDeltaY=-lconvert(Texture->YSize,L_Size,65536); LeftBDeltaX=0; LeftXPos=Texture->XSize-1; LeftYPos=Texture->YSize-1; break; case 11: /* C-D */ LeftBDeltaX=-lconvert(Texture->XSize,L_Size,65536); LeftBDeltaY=0; LeftXPos=Texture->XSize-1; LeftYPos=Texture->YSize-1; break; case 12: /* D-A */ LeftBDeltaY=-lconvert(Texture->YSize,L_Size,65536); LeftBDeltaX=0; LeftXPos=0; LeftYPos=Texture->YSize-1; break; case 14: /* D-C */ LeftBDeltaX=lconvert(Texture->XSize,L_Size,65536); LeftBDeltaY=0; LeftXPos=0; LeftYPos=Texture->YSize-1; break; } LeftXPos*=65536; LeftYPos*=65536; } if(!RightCount) { /* Get next Right Vector */ j=RightVectorB; k=(RightVectorB+1)%4; if(k==RightVectorA) { k=(RightVectorB+3)%4; } RightVectorA=j; RightVectorB=k; RightX=poly->x[RightVectorA]*65536; RightCount=poly->y[RightVectorB]-poly->y[RightVectorA]; R_Size=RightCount; rva[rcount]=RightVectorA; rvb[rcount]=RightVectorB; rcnt[rcount]=RightCount; rcount++; j=poly->x[RightVectorB]-poly->x[RightVectorA]; RightDelta=lconvert(j,RightCount,65536); switch((RightVectorA<<2)|RightVectorB) { case 0: /* A-A Impossible */ case 2: /* A-C Impossible */ case 5: /* B-B Impossible */ case 7: /* B-D Impossible */ case 8: /* C-A Impossible */ case 10: /* C-C Impossible */ case 13: /* D-B impossible */ case 15: /* D-D Impossible */ break; case 1: /* A-B */ RightBDeltaX=lconvert(Texture->XSize,R_Size,65536); RightBDeltaY=0; RightXPos=0; RightYPos=0; break; case 3: /* A-D */ RightBDeltaY=lconvert(Texture->YSize,R_Size,65536); RightBDeltaX=0; RightXPos=0; RightYPos=0; break; case 4: /* B-A */ RightBDeltaX=-lconvert(Texture->XSize,R_Size,65536); RightBDeltaY=0; RightXPos=Texture->XSize-1; RightYPos=0; break; case 6: /* B-C */ RightBDeltaY=lconvert(Texture->YSize,R_Size,65536); RightBDeltaX=0; RightXPos=Texture->XSize-1; RightYPos=0; break; case 9: /* C-B */ RightBDeltaY=-lconvert(Texture->YSize,R_Size,65536); RightBDeltaX=0; RightXPos=Texture->XSize-1; RightYPos=Texture->YSize-1; break; case 11: /* C-D */ RightBDeltaX=-lconvert(Texture->XSize,R_Size,65536); RightBDeltaY=0; RightXPos=Texture->XSize-1; RightYPos=Texture->YSize-1; break; case 12: /* D-A */ RightBDeltaY=-lconvert(Texture->YSize,R_Size,65536); RightBDeltaX=0; RightXPos=0; RightYPos=Texture->YSize-1; break; case 14: /* D-C */ RightBDeltaX=lconvert(Texture->XSize,R_Size,65536); RightBDeltaY=0; RightXPos=0; RightYPos=Texture->YSize-1; break; } RightXPos*=65536; RightYPos*=65536; } /* Now, We can shoot our row... */ j=(LeftXPos/65536); j+=((LeftYPos/65536)*Texture->XSize); /* j=offset into bitmap... */ k=(RightX-LeftX)/65536; /* Size of line... */ if(m<0) k=0; /* Skip if above screen */ m=LeftX/65536; n=RightX/65536; if((n<0)||(m>GrMaxX())) { k=0; /* No line to be draw... */ } if(k) { OSize=k; p=LeftXPos; q=LeftYPos; o=LeftX/65536; if(m<0) { if((m+k)>0) /* Clip Left Boundary */ { m=-m; p+=(((RightXPos-LeftXPos)/k)*m); q+=(((RightYPos-LeftYPos)/k)*m); o+=m; } else k=0; } if(n>GrMaxX()) /* Clip Right boundary */ { n-=GrMaxX(); k-=n; } } /* This is the "inner" loop. Clipping has already been done. "p" is our fixed point bitmap X position "q" is our fixed point bitmap Y position "m" is our starting screen X position */ if(k>2) { m=(RightXPos-LeftXPos)/OSize; n=(RightYPos-LeftYPos)/OSize; /* m and n equal deltas for bitmap ray */ if(debug) { if(getch()==' ') { GrSetMode(GR_default_text); printf("XInc= %f YInc=%f OSize=%d",fixed2float(m), fixed2float(n),OSize); printf("ScreenPos=%d P=%f Q=%f\n",o, fixed2float(p),fixed2float(q)); printf("LeftX=%f RightX=%f ",fixed2float(LeftXPos), fixed2float(RightXPos)); printf("LeftY=%f RightY=%f ",fixed2float(LeftYPos), fixed2float(RightYPos)); printf("(%c-%c)/(%c-%c)\n", LeftVectorA+'A',LeftVectorB+'A',RightVectorA+'A', RightVectorB+'A'); printf( "L_Size=%d R_Size=%d LeftCount=%d RightCount=%d\n", L_Size,R_Size,LeftCount,RightCount); printf("A(%d,%d) B(%d,%d) C(%d,%d) D(%d,%d)\n", poly->x[0],poly->y[0],poly->x[1],poly->y[1], poly->x[2],poly->y[2],poly->x[3],poly->y[3]); exit(0); } } for(;k;k--,o++) { j=(p/65536); j+=((q/65536)*Texture->XSize); screenptr[o]=Texture->Buffer[j]; p+=m; q+=n; } } /* Ending position in bitmap... */ LeftCount--; RightCount--; RightXPos+=RightBDeltaX; RightYPos+=RightBDeltaY; LeftXPos+=LeftBDeltaX; LeftYPos+=LeftBDeltaY; LeftX+=LeftDelta; RightX+=RightDelta; screenptr+=GrSizeX(); } }