heres a gba fixed point affine c routine excluding the gba stuff it should work with windows just fine note the only thing ive excluded from the source is the giant texture array which was a raw 16 bit bmp.
#define SHIFT 8
#define SCALE (1<<SHIFT)
#define TWOPOINTFIVE (0x280<<(SHIFT-8))
typedef struct
{
s32 x;
s32 u;
s32 v;
} EDGE;
s32 zin[360];
s32 coz[360];
typedef struct
{
s32 x,y,z;
} VECTOR;
typedef s32 MATRIX[3][3];
typedef struct
{
u16 face;
s32 z;
} SORTER;
// uv stuff
typedef struct
{
u8 point_index;
s16 u, v;
} VERTEX;
typedef struct
{
VERTEX pt[3];
} FACE;
#define N_FACES 12
#define N_POINTS 8
FACE faces[N_FACES]=
{
{
{{0,0,0},
{2,TEX_X-1,0},
{6,TEX_X-1,TEX_Y-1}},
},
{
{{0,0,0},
{6,TEX_X-1,TEX_Y-1},
{4,0,TEX_Y-1}}
},
{
{{0,0,0},
{1,TEX_X-1,0},
{3,TEX_X-1,TEX_Y-1}}
},
{
{{0,0,0},
{3,TEX_X-1,TEX_Y-1},
{2,0,TEX_Y-1}}
},
{
{{4,0,0},
{6,TEX_X-1,0},
{7,TEX_X-1,TEX_Y-1}}
},
{
{{4,0,0},
{7,TEX_X-1,TEX_Y-1},
{5,0,TEX_Y-1}}
},
{
{{1,0,0},
{0,TEX_X-1,0},
{4,TEX_X-1,TEX_Y-1}}
},
{
{{1,0,0},
{4,TEX_X-1,TEX_Y-1},
{5,0,TEX_Y-1}}
},
{
{{2,0,0},
{3,TEX_X-1,0},
{7,TEX_X-1,TEX_Y-1}}
},
{
{{2,0,0},
{7,TEX_X-1,TEX_Y-1},
{6,0,TEX_Y-1}}
},
{
{{5,0,0},
{1,TEX_X-1,0},
{3,TEX_X-1,TEX_Y-1}}
},
{
{{5,0,0},
{3,TEX_X-1,TEX_Y-1},
{7,0,TEX_Y-1}}
}
};
const VECTOR points[N_POINTS]=
{
{1<<SHIFT,1<<SHIFT,1<<SHIFT},
{1<<SHIFT,1<<SHIFT,-1<<SHIFT},
{1<<SHIFT,-1<<SHIFT,1<<SHIFT},
{1<<SHIFT,-1<<SHIFT,-1<<SHIFT},
{-1<<SHIFT,1<<SHIFT,1<<SHIFT},
{-1<<SHIFT,1<<SHIFT,-1<<SHIFT},
{-1<<SHIFT,-1<<SHIFT,1<<SHIFT},
{-1<<SHIFT,-1<<SHIFT,-1<<SHIFT},
};
VECTOR rotated[N_POINTS];
SORTER sorter[N_FACES];
MATRIX matrix;
u32 count,xbegin,xend;
s32 x_scale = 40<<SHIFT;
s32 y_scale = 40<<SHIFT;
s32 z_scale = 1<<SHIFT;
u16 tilt=0,turn=0,roll=0;
#define SCREENX 160
#define SCREENY 128
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
void plotsprite(u16 xpos,u16 ypos);
u8 gnewframe;
u16 *frameptr;
void filltriangle(FACE *);
void vblFunc();
void setup();
int main(void)
{
u8 swap;
s32 z;
s32 A,B,C,D,E,F,AD,BD;
u16 p,f,j;
ham_Init();
ham_SetBgMode(5);
ham_RotBgEx(2, 0, 0, 0, 0, 0, (256*GFX_MODE5_WIDTH)/GBA_SCREEN_WIDTH, //make width fullscreen
(256*GFX_MODE5_HEIGHT)/GBA_SCREEN_HEIGHT); // make height fullscreen
ham_StartIntHandler(INT_TYPE_VBL,(void *)&vblFunc);
setup();
while(TRUE)
{
if (gnewframe)
{
u8 buffer = ham_GetBGBuffer();
if (buffer==1) frameptr=(u16*)0x6000000;
else frameptr=(u16*)0x600a000;
plotsprite(0,0);
//rem prepare the rotation matrix
if (tilt > 359){tilt = 0;}
if (turn > 359){turn = 0;}
if (roll > 359){roll = 0;}
A=coz[tilt];B=zin[tilt];
C=coz[turn];D=zin[turn];
E=coz[roll];F=zin[roll];
AD=(A*D)>>SHIFT;
BD=(B*D)>>SHIFT;
matrix[0][0]=(C*E)>>SHIFT;
matrix[1][0]=(-C*F)>>SHIFT;
matrix[2][0]=D;
matrix[0][1]=((BD*E)+(A*F))>>SHIFT;
matrix[1][1]=((-BD*F)+(A*E))>>SHIFT;
matrix[2][1]=(-B*C)>>SHIFT;
matrix[0][2]=((-AD*E)+(B*F))>>SHIFT;
matrix[1][2]=((AD*F)+(B*E))>>SHIFT;
matrix[2][2]=(A*C)>>SHIFT;
//rem rotate all the points using the matrix
for (p=0;p<N_POINTS; p++)
{
rotated[p].x = ((matrix[0][0] * points[p].x)>>SHIFT) + ((matrix[0][1] * points[p].y)>>SHIFT) + ((matrix[0][2] * points[p].z)>>SHIFT);
rotated[p].x = (rotated[p].x * x_scale)>>SHIFT;
rotated[p].y = ((matrix[1][0] * points[p].x)>>SHIFT) + ((matrix[1][1] * points[p].y)>>SHIFT) + ((matrix[1][2] * points[p].z)>>SHIFT);
rotated[p].y = (rotated[p].y * y_scale)>>SHIFT;
rotated[p].z = ((matrix[2][0] * points[p].x)>>SHIFT) + ((matrix[2][1] * points[p].y)>>SHIFT) + ((matrix[2][2] * points[p].z)>>SHIFT);
//rem now do the perspective calculation
z = ((1L<<SHIFT)<<SHIFT)/(rotated[p].z + TWOPOINTFIVE);
rotated[p].x = ((SCREENX/2)<<SHIFT) + ((rotated[p].x * z)>>SHIFT);
rotated[p].y = ((SCREENY/2)<<SHIFT) - ((rotated[p].y * z)>>SHIFT);
}
//rem set up the sorting array
for (f=0;f<N_FACES;f++)
{
s32 z0,z1,z2;
u8 p0,p1,p2;
p0 = faces[f].pt[0].point_index;
p1 = faces[f].pt[1].point_index;
p2 = faces[f].pt[2].point_index;
z0 = rotated[p0].z;
z1 = rotated[p1].z;
z2 = rotated[p2].z;
sorter[f].face = f;
//near z
//sorter[f].z = max(z0,max(z1,z2));
//far z
//sorter[f].z = min(z0,min(z1,z2));
//ave z
sorter[f].z = (z0+z1+z2);
}
do
{
swap= 0;
for (j=0;j<N_FACES-1;j++)
{
if (sorter[j+1].z > sorter[j].z)
{
SORTER tmp;
tmp = sorter[j+1];
sorter[j+1]=sorter[j];
sorter[j]=tmp;
swap = 1;
}
}
} while (swap);
for (f=0;f<N_FACES;f++)
{
u16 face;
face = sorter[f].face;
filltriangle(&faces[face]);
//just plot the corners
/*
u16 p0,p1,p2;
p0 = faces[face].pt[0].point_index;
p1 = faces[face].pt[1].point_index;
p2 = faces[face].pt[2].point_index;
ham_PutPixel(rotated[p0].x, rotated[p0].y, 0x7fff);
ham_PutPixel(rotated[p1].x, rotated[p1].y, 0x7fff);
ham_PutPixel(rotated[p2].x, rotated[p2].y, 0x7fff);
*/
}
tilt = tilt+5;
turn = turn+6;
roll = roll+7;
//rem flip and the screens
ham_FlipBGBuffer();
ham_ClearBackBuffer(0);
gnewframe=0;
}
}
return 0;
}
void setup()
{
s32 coza;
for(coza=0;coza<359;coza++)
{
zin[coza] = sin(coza/180.0*3.14159)*SCALE;
coz[coza] = cos(coza/180.0*3.14159)*SCALE;
}
}
void vblFunc()
{
gnewframe=1;
}
void plotsprite(u16 xpos ,u16 ypos)
{
/*
u16 texptr=0;
s16 x,y;
for (y=0;y<SCREENY;y++)
{
for (x=0;x<SCREENX;x++)
{
*frameptr++=bground5[texptr++];
}
frameptr+=SCREENX-SCREENX;
}
u8 buffer = ham_GetBGBuffer();
if (buffer==1) frameptr=(u16*)0x6000000;
else frameptr=(u16*)0x600a000;
*/
u16 *src = bground5;
u16 *dst = frameptr;
u16 x,y;
for (y = 0; y < SCREENY; y++)
{
for (x = 0; x < SCREENX; x++)
*dst++ = *src++;
}
}
#define FSHIFT 16
#define FSCALE (1L<<FSHIFT)
void scan(EDGE *L,EDGE *R, s32 y)
{
s32 x0,x1,u,v,du,dv,dx;
u16 *screenptr16;
if (y<0 || y>=160) return;
if (L->x > R->x)
{
EDGE *t=L;
L=R;
R=t;
}
x0=L->x>>FSHIFT;
x1=R->x>>FSHIFT;
dx = x1-x0;
if (!dx) return;
if (x0>=SCREENY)
return;
else if (x0<0)
x0=0;
if (x1<0)
return;
else if (x1>=SCREENX)
x1=SCREENX;
u=L->u;
v=L->v;
du = (R->u - L->u) / dx;
dv = (R->v - L->v) / dx;
screenptr16 = frameptr + x0 + y * SCREENX;
while (dx--)
{
*screenptr16++ = texture[(u>>FSHIFT)+TEX_X*(v>>FSHIFT)];
u+=du;
v+=dv;
}
}
void filltriangle(FACE *face)
{
s32 xx[3], yy[3];
u8 i0,i1,i2;
s32 dyL, dyT, dyB;
s32 rdyL,rdyT,rdyB;
s32 Y;
s32 dxL, dxT, dxB;
s32 duL, duT, duB;
s32 dvL, dvT, dvB;
EDGE L,R;
yy[0]=rotated[face->pt[0].point_index].y>>SHIFT;
yy[1]=rotated[face->pt[1].point_index].y>>SHIFT;
yy[2]=rotated[face->pt[2].point_index].y>>SHIFT;
xx[0]=rotated[face->pt[0].point_index].x>>SHIFT;
xx[1]=rotated[face->pt[1].point_index].x>>SHIFT;
xx[2]=rotated[face->pt[2].point_index].x>>SHIFT;
i0 = 0;
i1 = 1;
i2 = 2;
if (yy[0]<=yy[1] && yy[0]<=yy[2])
{
//y0 is smallest
if (yy[1]>yy[2])
{
//y1 is largest
i1 = 2;
i2 = 1;
}
else
{
//y2 is largest
}
}
else if (yy[1]<=yy[0] && yy[1]<=yy[2])
{
i0 = 1;
//y1 is smallest
if (yy[0]<yy[2])
{
//y2 is largest
i1 = 0;
}
else
{
//y0 is largest
i1 = 2;
i2 = 0;
}
}
else
{
i0 = 2;
//y2 is smallest
if (yy[1]<yy[0])
{
//y0 is largest
i2 = 0;
}
else
{
//y1 is largest
i2 = 1;
i1 = 0;
}
}
dyL = yy[i2]-yy[i0];
if (dyL==0) return;
rdyL = FSCALE / dyL;
dxL = (xx[i2]-xx[i0]) * rdyL;
duL = (face->pt[i2].u-face->pt[i0].u) * rdyL;
dvL = (face->pt[i2].v-face->pt[i0].v) * rdyL;
dyT = yy[i1]-yy[i0];
L.x=xx[i0]<<FSHIFT;
Y=yy[i0];
L.u=face->pt[i0].u<<FSHIFT;
L.v=face->pt[i0].v<<FSHIFT;
if (dyT!=0)
{
rdyT = FSCALE / dyT;
dxT = (xx[i1]-xx[i0]) * rdyT;
duT = (face->pt[i1].u-face->pt[i0].u) * rdyT;
dvT = (face->pt[i1].v-face->pt[i0].v) * rdyT;
R=L;
while (Y < yy[i1])
{
scan(&L,&R,Y);
Y++;
L.x+=dxL;
R.x+=dxT;
L.u+=duL;
L.v+=dvL;
R.u+=duT;
R.v+=dvT;
}
}
//bottom
R.x=xx[i1]<<FSHIFT;
R.u=face->pt[i1].u<<FSHIFT;
R.v=face->pt[i1].v<<FSHIFT;
dyB = yy[i2]-yy[i1];
if (dyB!=0)
{
rdyB = FSCALE / dyB;
dxB = (xx[i2]-xx[i1]) * rdyB;
duB = (face->pt[i2].u-face->pt[i1].u) * rdyB;
dvB = (face->pt[i2].v-face->pt[i1].v) * rdyB;
while (Y < yy[i2])
{
scan(&L,&R,Y);
Y++;
L.x+=dxL;
R.x+=dxB;
L.u+=duL;
L.v+=dvL;
R.u+=duB;
R.v+=dvB;
}
}
}