// lib2d.c // 2D Yaroze Development Library v1.0.0 // High performance macros & functions // Developed & compiled by Harvey Cotton // Copyright © 1998/1999 // E-mail: harvey.c@lineone.net // ***************************************************************************************************************** Includes #include #include #include "lib2d.h" // *********************************************************************************************************** Look-up tables short FSIN [361]={ 0, 71, 142, 213, 284, 356, 426, 497, 568, 638, 709, 779, 849, 918, 988, 1057, 1125, 1194, 1262, 1329, 1397, 1463, 1530, 1596, 1661, 1726, 1790, 1854, 1918, 1980, 2042, 2104, 2165, 2225, 2284, 2343, 2401, 2459, 2515, 2571, 2626, 2681, 2734, 2787, 2839, 2890, 2940, 2989, 3037, 3084, 3131, 3176, 3221, 3264, 3307, 3348, 3389, 3429, 3467, 3504, 3541, 3576, 3610, 3643, 3675, 3706, 3736, 3765, 3792, 3819, 3844, 3868, 3891, 3912, 3933, 3952, 3970, 3987, 4003, 4017, 4030, 4043, 4053, 4063, 4071, 4078, 4084, 4089, 4092, 4095, 4095, 4095, 4094, 4091, 4087, 4082, 4075, 4067, 4058, 4048, 4037, 4024, 4010, 3995, 3979, 3961, 3943, 3923, 3902, 3879, 3856, 3831, 3805, 3779, 3751, 3721, 3691, 3660, 3627, 3593, 3559, 3523, 3486, 3448, 3409, 3369, 3328, 3286, 3243, 3199, 3154, 3108, 3061, 3013, 2964, 2915, 2864, 2813, 2761, 2707, 2654, 2599, 2543, 2487, 2430, 2372, 2314, 2255, 2195, 2134, 2073, 2011, 1949, 1886, 1822, 1758, 1694, 1629, 1563, 1497, 1430, 1363, 1296, 1228, 1160, 1091, 1022, 953, 884, 814, 744, 674, 603, 533, 462, 391, 320, 249, 178, 106, 35, -35, -106, -178, -249, -320, -391, -462, -533, -603, -674, -744, -814, -884, -953, -1022, -1091, -1160, -1228, -1296, -1363, -1430, -1497, -1563, -1629, -1694, -1758, -1822, -1886, -1949, -2011, -2073, -2134, -2195, -2255, -2314, -2372, -2430, -2487, -2543, -2599, -2654, -2707, -2761, -2813, -2864, -2915, -2964, -3013, -3061, -3108, -3154, -3199, -3243, -3286, -3328, -3369, -3409, -3448, -3486, -3523, -3559, -3593, -3627, -3660, -3691, -3721, -3751, -3779, -3805, -3831, -3856, -3879, -3902, -3923, -3943, -3961, -3979, -3995, -4010, -4024, -4037, -4048, -4058, -4067, -4075, -4082, -4087, -4091, -4094, -4095, -4095, -4095, -4092, -4089, -4084, -4078, -4071, -4063, -4053, -4043, -4030, -4017, -4003, -3987, -3970, -3952, -3933, -3912, -3891, -3868, -3844, -3819, -3792, -3765, -3736, -3706, -3675, -3643, -3610, -3576, -3541, -3504, -3467, -3429, -3389, -3348, -3307, -3264, -3221, -3176, -3131, -3084, -3037, -2989, -2940, -2890, -2839, -2787, -2734, -2681, -2626, -2571, -2515, -2459, -2401, -2343, -2284, -2225, -2165, -2104, -2042, -1980, -1918, -1854, -1790, -1726, -1661, -1596, -1530, -1463, -1397, -1329, -1262, -1194, -1125, -1057, -988, -918, -849, -779, -709, -638, -568, -497, -426, -356, -284, -213, -142, -71}; short FCOS [361]={ 4096, 4095, 4093, 4090, 4086, 4080, 4073, 4065, 4056, 4045, 4034, 4021, 4006, 3991, 3975, 3957, 3938, 3918, 3896, 3874, 3850, 3825, 3799, 3772, 3743, 3714, 3683, 3651, 3619, 3585, 3550, 3514, 3476, 3438, 3399, 3359, 3317, 3275, 3232, 3188, 3142, 3096, 3049, 3001, 2952, 2902, 2851, 2800, 2747, 2694, 2640, 2585, 2529, 2473, 2416, 2358, 2299, 2240, 2180, 2119, 2058, 1996, 1933, 1870, 1806, 1742, 1677, 1612, 1546, 1480, 1413, 1346, 1279, 1211, 1143, 1074, 1005, 936, 866, 796, 726, 656, 586, 515, 444, 373, 302, 231, 160, 89, 17, -53, -124, -195, -267, -338, -409, -480, -550, -621, -691, -761, -831, -901, -970, -1040, -1108, -1177, -1245, -1313, -1380, -1447, -1513, -1579, -1645, -1710, -1774, -1838, -1902, -1965, -2027, -2089, -2150, -2210, -2270, -2329, -2387, -2444, -2501, -2557, -2613, -2667, -2721, -2774, -2826, -2877, -2927, -2977, -3025, -3073, -3119, -3165, -3210, -3254, -3296, -3338, -3379, -3419, -3457, -3495, -3532, -3567, -3602, -3635, -3667, -3699, -3729, -3758, -3785, -3812, -3838, -3862, -3885, -3907, -3928, -3947, -3966, -3983, -3999, -4014, -4027, -4040, -4051, -4061, -4069, -4077, -4083, -4088, -4092, -4094, -4095, -4095, -4094, -4092, -4088, -4083, -4077, -4069, -4061, -4051, -4040, -4027, -4014, -3999, -3983, -3966, -3947, -3928, -3907, -3885, -3862, -3838, -3812, -3785, -3758, -3729, -3699, -3667, -3635, -3602, -3567, -3532, -3495, -3457, -3419, -3379, -3338, -3296, -3254, -3210, -3165, -3119, -3073, -3025, -2977, -2927, -2877, -2826, -2774, -2721, -2667, -2613, -2557, -2501, -2444, -2387, -2329, -2270, -2210, -2150, -2089, -2027, -1965, -1902, -1838, -1774, -1710, -1645, -1579, -1513, -1447, -1380, -1313, -1245, -1177, -1108, -1040, -970, -901, -831, -761, -691, -621, -550, -480, -409, -338, -267, -195, -124, -53, 17, 89, 160, 231, 302, 373, 444, 515, 586, 656, 726, 796, 866, 936, 1005, 1074, 1143, 1211, 1279, 1346, 1413, 1480, 1546, 1612, 1677, 1742, 1806, 1870, 1933, 1996, 2058, 2119, 2180, 2240, 2299, 2358, 2416, 2473, 2529, 2585, 2640, 2694, 2747, 2800, 2851, 2902, 2952, 3001, 3049, 3096, 3142, 3188, 3232, 3275, 3317, 3359, 3399, 3438, 3476, 3514, 3550, 3585, 3619, 3651, 3683, 3714, 3743, 3772, 3799, 3825, 3850, 3874, 3896, 3918, 3938, 3957, 3975, 3991, 4006, 4021, 4034, 4045, 4056, 4065, 4073, 4080, 4086, 4090, 4093, 4095}; short ATAN [256]={ 0, 3, 5, 8, 10, 13, 15, 18, 20, 23, 25, 28, 31, 33, 36, 38, 41, 43, 46, 48, 51, 53, 56, 58, 61, 63, 66, 69, 71, 74, 76, 79, 81, 84, 86, 89, 91, 94, 96, 99, 101, 104, 106, 108, 111, 113, 116, 118, 121, 123, 126, 128, 131, 133, 136, 138, 140, 143, 145, 148, 150, 152, 155, 157, 160, 162, 164, 167, 169, 172, 174, 176, 179, 181, 183, 186, 188, 190, 193, 195, 197, 200, 202, 204, 207, 209, 211, 214, 216, 218, 220, 223, 225, 227, 229, 232, 234, 236, 238, 241, 243, 245, 247, 249, 252, 254, 256, 258, 260, 262, 265, 267, 269, 271, 273, 275, 277, 279, 282, 284, 286, 288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 332, 334, 336, 338, 340, 342, 344, 346, 347, 349, 351, 353, 355, 357, 359, 360, 362, 364, 366, 368, 370, 371, 373, 375, 377, 379, 380, 382, 384, 386, 387, 389, 391, 393, 394, 396, 398, 399, 401, 403, 405, 406, 408, 410, 411, 413, 415, 416, 418, 419, 421, 423, 424, 426, 428, 429, 431, 432, 434, 435, 437, 439, 440, 442, 443, 445, 446, 448, 449, 451, 452, 454, 455, 457, 458, 460, 461, 463, 464, 466, 467, 469, 470, 471, 473, 474, 476, 477, 479, 480, 481, 483, 484, 486, 487, 488, 490, 491, 492, 494, 495, 496, 498, 499, 500, 502, 503, 504, 506, 507, 508, 509, 511}; // ***************************************************************************************************************** Graphics // Initialises everything void InitialiseGraphics (long mode) { // Setup graphics mode SetVideoMode(mode); GsInitGraph(SCREEN_WIDTH,SCREEN_HEIGHT,GsOFSGPU,1,0); GsDISPENV.screen.x=2; GsDISPENV.screen.y=22; if (SCREEN_HEIGHT<480) GsDISPENV.screen.h=SCREEN_HEIGHT; // Initialise ordering table TableHeader[0].length=TableHeader[1].length=ORDERING_TABLE_LENGTH; TableHeader[0].org=TableArray[0]; TableHeader[1].org=TableArray[1]; RenderClear(); // Initialise font FntLoad(960,256); FntOpen(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,0,256); // Initialise control pads GetPadBuf(&bb0,&bb1); } // Detect the appropriate mode by checking psx rom long DetectVideoMode () { if (*(char *)0xbfc7ff52=='E') return MODE_PAL; else return MODE_NTSC; } // Stores the screen and quits out void StoreScreen () { RECT rect; u_long *destination=(u_long*)0x80090000; *(destination+0)=0x00000010; *(destination+1)=0x00000002; *(destination+2)=(SCREEN_WIDTH*SCREEN_HEIGHT/2+3)*4; *(destination+3)=((0 & 0xffff)<<16)|(640 & 0xffff); *(destination+4)=((SCREEN_HEIGHT & 0xffff)<<16)|(SCREEN_WIDTH & 0xffff); rect.x=0; rect.y=0; rect.w=SCREEN_WIDTH; rect.h=SCREEN_HEIGHT; DrawSync(0); StoreImage(&rect,destination+5); printf("\n\nPress [F10][F4] for dsave, to get screen picture\n"); printf("Dsave[0]: filename.tim 80090000 %x\n\n\n",(rect.w*rect.h/2+5)*4); DrawSync(0); VSync(0); exit(0); } // Called before everything is drawn void RenderPrepare () { CurrentBuffer=GsGetActiveBuff(); GsSetWorkBase((PACKET*)PacketMemory[CurrentBuffer]); GsClearOt(0,0,&TableHeader[CurrentBuffer]); } // Called after everything is drawn void RenderFinish () { DrawSync(0); #ifdef DEBUG FntPrint("VSYNC:%d\n",VSync(0)); #else VSync(0); #endif GsSwapDispBuff(); GsSortClear(BG_RED,BG_GREEN,BG_BLUE,&TableHeader[CurrentBuffer]); GsDrawOt(&TableHeader[CurrentBuffer]); FntFlush(-1); } // Wipes screen and ordering tables void RenderClear () { RECT temp={0,0,SCREEN_WIDTH,SCREEN_HEIGHT}; ClearImage(&temp,BG_RED,BG_GREEN,BG_BLUE); GsClearOt(0,0,&TableHeader[0]); GsClearOt(0,0,&TableHeader[1]); GsSortClear(BG_RED,BG_GREEN,BG_BLUE,&TableHeader[0]); GsSortClear(BG_RED,BG_GREEN,BG_BLUE,&TableHeader[1]); DrawSync(0); } // Transfer a texture from memory to video ram int LoadTexture (long address) { GsIMAGE tim; RECT rect; GsGetTimInfo((u_long *)(address+4),&tim); rect.x=tim.px; rect.y=tim.py; rect.w=tim.pw; rect.h=tim.ph; LoadImage(&rect,tim.pixel); if ((tim.pmode>>3)&0x01) { rect.x=tim.cx; rect.y=tim.cy; rect.w=tim.cw; rect.h=tim.ch; LoadImage(&rect,tim.clut); } DrawSync(0); return 1; } // Initialise a sprite void InitialiseSprite (GsSPRITE *sprite,u_long address,long x,long y) { u_long depth1,depth2; GsIMAGE tim; GsGetTimInfo((u_long *)(address+4),&tim); depth2=4>>(depth1=tim.pmode&3); sprite->attribute=depth1<<24; sprite->x=x; sprite->y=y; sprite->w=tim.pw*depth2; sprite->h=tim.ph; sprite->tpage=GetTPage(depth1,0,tim.px,tim.py); sprite->u=tim.px%64; sprite->v=tim.py%256; if (depth1!=2) { sprite->cx=tim.cx; sprite->cy=tim.cy; } sprite->r=sprite->g=sprite->b=128; sprite->mx=(tim.pw*depth2)>>1; sprite->my=tim.ph>>1; sprite->scalex=sprite->scaley=4096; sprite->rotate=0; } // Initialise a sprite with more parameters void InitialiseSprite2 (GsSPRITE *sprite,u_long address,long x,long y,short scale,long rotate,short trans,u_char r,u_char g,u_char b) { InitialiseSprite(sprite,address,x,y); sprite->scalex=sprite->scaley=scale; sprite->rotate=rotate; sprite->attribute+=trans>=0 && trans<=3 ? (1<<30)+(trans<<28) : 0; sprite->r=r; sprite->g=g; sprite->b=b; } // Read pixel from frame long GetPixel (short x,short y) { RECT rect={x,y+(CurrentBuffer?SCREEN_HEIGHT:0),1,1}; register u_long *p=(u_long *)0x1f800000; StoreImage(&rect,p); return *p; } // Write pixel to frame void PutPixel (short x,short y,long colour) { RECT rect={x,y+(CurrentBuffer?SCREEN_HEIGHT:0),1,1}; register u_long *p=(u_long *)0x1f800000; *p=colour; LoadImage(&rect,p); } // Draw a simple rectangle void DrawRectangle (short x0,short y0,short x1,short y1,u_char r,u_char g,u_char b,short priority) { register GsLINE *line=(GsLINE *)0x1f800000; line->attribute=0; line->r=r; line->g=g; line->b=b; line->x0=x0; line->y0=y0; line->x1=x1; line->y1=y0; DrawLine(line,priority); line->y0=y1; line->y1=y1; DrawLine(line,priority); line->y0=y0; line->x1=x0; DrawLine(line,priority); line->x0=x1; line->y0=y0; line->x1=x1; DrawLine(line,priority); } // Draw a filled box with a border void DrawBorderBox (short x,short y,short w,short h,u_char r0,u_char g0,u_char b0,u_char r1,u_char g1,u_char b1,u_char trans,short priority) { register GsBOXF *box=(GsBOXF *)0x1f800000; box->attribute=trans<4 ? 0x40000000+(trans<<28) : 0; box->r=r0; box->g=g0; box->b=b0; // Draw horizontal borders box->w=w-1; box->h=1; box->x=x+1; box->y=y; DrawBox(box,priority); box->y+=h; DrawBox(box,priority); // Draw vertical borders box->w=1; box->h=h+1; box->x=x; box->y=y; DrawBox(box,priority); box->x+=w; DrawBox(box,priority); // Draw interior box->r=r1; box->g=g1; box->b=b1; box->x=x+1; box->y=y+1; box->w=w-1; box->h=h-1; DrawBox(box,priority); } // Draw Gouraud shaded box void DrawGouraudBox (short x,short y,short w,short h,u_char r0,u_char g0,u_char b0,u_char r1,u_char g1,u_char b1,u_char r2,u_char g2,u_char b2,u_char r3,u_char g3,u_char b3,char trans,short priority) { register GsGLINE *line=(GsGLINE *)0x1f800000; register long r0temp=r0<<22, g0temp=g0<<22, b0temp=b0<<22, r1temp=r1<<22, g1temp=g1<<22, b1temp=b1<<22, r0add=((r0-r2)<<22)/h, g0add=((g0-g2)<<22)/h, b0add=((b0-b2)<<22)/h, r1add=((r1-r3)<<22)/h, g1add=((g1-g3)<<22)/h, b1add=((b1-b3)<<22)/h; line->attribute=trans>3 ? 0 : 0x40000000+(trans<<28); line->x0=x; line->x1=x+w; line->r0=r0; line->g0=g0; line->b0=b0; line->r1=r1; line->g1=g1; line->b1=b1; for(line->y0=line->y1=y; line->y0y0=line->y1++) { DrawGradLine(line,priority); line->r0=(r0temp-=r0add)>>22; line->g0=(g0temp-=g0add)>>22; line->b0=(b0temp-=b0add)>>22; line->r1=(r1temp-=r1add)>>22; line->g1=(g1temp-=g1add)>>22; line->b1=(b1temp-=b1add)>>22; } } // ********************************************************************************************************************* Math // Fixed point cosine short FCos (register short x) { return FCOS[x]; } // Fixed point sine short FSin (register short x) { return FSIN[x]; } // Move a vector in a given X direction by a given distance void MoveVectorX (long *x,long *y,register short angle,register long dx) { angle=angle>270 ? angle-270 : angle+90; *x+=(dx*FSIN[angle])>>12; *y-=(dx*FCOS[angle])>>12; } // Move a vector in a given Y direction by a given distance void MoveVectorY (long *x,long *y,register short angle,register long dy) { *x+=(dy*FSIN[angle])>>12; *y-=(dy*FCOS[angle])>>12; } // Move a vector in a given XY direction by a given distance void MoveVectorXY (long *x,long *y,register short angle,register long dx,register long dy) { *x+=(dy*FSIN[angle])>>12; *y-=(dy*FCOS[angle])>>12; angle=angle>270 ? angle-270 : angle+90; *x+=(dx*FSIN[angle])>>12; *y-=(dx*FCOS[angle])>>12; } // Move a vector in a given X direction by a given distance void MoveSVectorX (short *x,short *y,register short angle,register short dx) { angle=angle>270 ? angle-270 : angle+90; *x+=(dx*FSIN[angle])>>12; *y-=(dx*FCOS[angle])>>12; } // Move a vector in a given Y direction by a given distance void MoveSVectorY (short *x,short *y,register short angle,register short dy) { *x+=(dy*FSIN[angle])>>12; *y-=(dy*FCOS[angle])>>12; } // Move a vector in a given XY direction by a given distance void MoveSVectorXY (short *x,short *y,register short angle,register short dx,register short dy) { *x+=(dy*FSIN[angle])>>12; *y-=(dy*FCOS[angle])>>12; angle=angle>270 ? angle-270 : angle+90; *x+=(dx*FSIN[angle])>>12; *y-=(dx*FCOS[angle])>>12; } // Calculate integer square root u_long IntegerSqrt (u_long x) { register short bitmax=0,step=0; register u_long v1=x,v2=0; for(; v1!=0; bitmax++,v1>>=1); for(v1=x>>(bitmax>>1); v1!=v2 && step++<10; v2=x/v1,v1=(v1+v2)>>1); return v1; } // Calculate ATan fast using dx and dy short ATanFast (register long x,register long y) { if (abs(x)>abs(y)) { y=(y<<8)/(!x ? 1 : x); if (y>=0) return ATAN[y&255]+(x<0 ? 2048 : 0); return (x<0 ? 2048 : 4096)-ATAN[(-y)&255]; } else if (abs(x)=0) return (y<0 ? 3072 : 1024)-ATAN[x&255]; return ATAN[(-x)&255]+(y<0 ? 3072 : 1024); } else { if (x<0) { if (y<0) return 2560; else return 1536; } else { if (y<0) return 3584; else return 512; } } } // Calculate the distance between two points u_long Distance (long x1,long y1,long x2,long y2) { register long dx=abs(x1-x2),dy=abs(y1-y2); return IntegerSqrt(dx*dx+dy*dy); } // Approximate distance between 0,0 and x,y with 3.5% error u_long DistanceFast (long x,long y) { long temp; x=abs(x); y=abs(y); temp=x>1)-(temp>>2)+(temp>>4)); } // Adjust an angle to face another angle void AdjustAngle (long *angle1,long step,long x1,long y1,long x2,long y2) { register angle2=Bearing(x1,y1,x2,y2)+1024; angle2=angle2>4096 ? (angle2-4096)*360 : angle2*360; if (*angle1!=angle2) { if ((abs(*angle1-angle2)>8388608 ? abs(abs(*angle1-angle2)-8388608) : abs(*angle1-angle2))<=step) { *angle1=angle2; } else { if (*angle1>angle2) { if (*angle1-angle2<1474560-*angle1+angle2) *angle1-=step; else *angle1+=step; } else { if (angle2-*angle1<1474560-angle2+*angle1) *angle1+=step; else *angle1-=step; } } *angle1=BoundsWrap(*angle1,0,1474560); } } // ****************************************************************************************************** Collision detection // Detection of a point within a polygon short PolygonCollision (short npol,long *xp,long *yp,register long x,register long y) { register long i=0,j=npol-1,c=0; for(; i>8; if (temp==0) temp=1; // Avoid divide by zero if (x1==x2 && x3==x4) x1++; // Avoid parallel horizontal lines if (y1==y2 && y3==y4) y1++; // Avoid parallel vertical lines r=((y1-y3)*(x4-x3)-(x1-x3)*(y4-y3))/temp; s=((y1-y3)*(x2-x1)-(x1-x3)*(y2-y1))/temp; if (r>=0 && r<=256 && s>=0 && s<=256) return 1; return 0; }