#include "header.h" TX_NS_GP_TRI_FACE flamePrim[12]; VERTEX flameVert[7]; u_long flameTMD[40]; // Initialise racer void InitRacer(void) { TX_GP_TRI_FACE *pointer; OBJECT *obj; NORMAL *norm; int i, num, flag, temp; VECTOR vec; MATRIX mat; COLOUR flameCol; // Use tmd flag to see if this is the first run of the function flag = ((HEADER *)RACER_ADDRESS)->flag; racer.heightSegment[0] = racer.collisionSegment[0] = 1; racer.heightSegment[1] = racer.collisionSegment[1] = rawTrack->numSegments-1; racer.heightSegment[2] = racer.collisionSegment[2] = rawTrack->numSegments-1; racer.heightSegment[3] = 0; SetVector(&racer.pos, 0, 0, 8<<8); SetVector(&racer.vel, 0, 0, 0); SetVector(&racer.rot, 0, 0, 0); SetVector(&racer.heightPoint[3], 0, 0, 0); racer.tilt = 0; racer.speed = 0; racer.height[0] = racer.height[1] = racer.height[2] = racer.height[3] = 64<<8; racer.heightVel[0] = racer.heightVel[1] = racer.heightVel[2] = racer.heightVel[3] = 0; // Init both models to the same coordinate system LinkObject((u_long *)RACER_ADDRESS, &racer.coord, &racer.handler); LinkObject((u_long *)REFLECT_ADDRESS, &racer.coord, &racer.reflectHandler); racer.handler.attribute = (1<<6)+(1<<9); // No light, 2x2 subdivision racer.reflectHandler.attribute = (1<<6)+(1<<9)+(1<<30); // No light, 2x2 subdivision, transparent // Init Shadow LinkObject((u_long *)SHADOW_ADDRESS, &racer.shadowCoord, &racer.shadowHandler); racer.shadowHandler.attribute = (1<<6); // No light // Init raw TMD data (once) if (flag == 0) { printf("Editing TMD data\n"); // Ensure all polygon transparency types are correct obj = (OBJECT *)((HEADER *)REFLECT_ADDRESS+1); pointer = (TX_GP_TRI_FACE *)(obj->primitive_top); num = obj->n_primitive; for (i=0; ivert0; pointer->vert0 = pointer->vert2; pointer->vert2 = temp; temp = pointer->norm0; pointer->norm0 = pointer->norm2; pointer->norm2 = temp; // Set the ABR field to 100% fore + 100% back pointer->tsb = pointer->tsb & ~96; // Clear ABR field pointer->tsb |= (1<<5); // Set ABR field pointer++; } // Decrease the surface normals slightly to prevent integer rounding errors norm = (NORMAL *)(obj->normal_top); num = obj->n_normal; for (i=0; inx = (norm->nx*31)>>5; norm->ny = (norm->ny*31)>>5; norm->nz = (norm->nz*31)>>5; norm++; } } // Init speed trail info for (i=0; i<4; i++) { SetVector(&racer.trail[i], 0, 0, 0); } // Create flame tmd for (i=0; i<6; i++) { ResetMatrix(mat.m); RotMatrixZ(4096*(i+1)/6, &mat); // SetVector(&vec, 0, 6+((i&1)<<3), -((i&1)<<3)); SetVector(&vec, 0, 6, 0); ApplyMatrixLV(&mat, &vec, &vec); SetVertex(&flameVert[i], vec.vx, (vec.vy<<1)/3+8, vec.vz-12); } SetVertex(&flameVert[6], 0, 8, -20-12); // SetRGB(&flameCol[0], 0, 0, 0); // SetRGB(&flameCol[1], 128, 0, 0); // SetRGB(&flameCol[2], 128, 128, 0); SetRGB(&flameCol, 0, 0, 0); PrepareTMD(&flameVert[0], &flameCol, NULL); SetTmdHeader((HEADER *)flameTMD); obj = (OBJECT *)((HEADER *)flameTMD + 1); MakeFlame(&flamePrim[0]); obj->vert_top = (u_long *)&flameVert[0]; obj->n_vert = 7; obj->normal_top = (u_long *)NULL; obj->n_normal = 0; obj->primitive_top = (u_long *)&flamePrim[0]; obj->n_primitive = 12; obj->scale = 0; LinkObject((u_long *)flameTMD, &racer.coord, &racer.flameHandler); racer.flameHandler.attribute = (1<<30); } void DrawRacer(GsOT *ot, int shift) { MATRIX ls, mat; GsGLINE line; VECTOR vec; int i, col, size, dr=0, dg=0, db=0; line.r0 = line.g0 = line.b0 = LimitRange(racer.speed>>8, 0, 128); line.r1 = line.g1 = line.b1 = 0; line.attribute = (1<<30)+(1<<28); // Calculate reflections EnvMap(&racer.reflectHandler); // Draw shadow SetVector(&vec, racer.pos.vx>>8, (racer.pos.vy-racer.heightOffTrack)>>8, racer.pos.vz>>8); MoveObject(&vec, &racer.rot, &racer.shadowCoord); GsGetLs(&racer.shadowCoord, &ls); GsSetLsMatrix(&ls); GsSortObject4(&racer.shadowHandler, ot, shift, getScratchAddr(0)); // Draw racer GsGetLs(&racer.coord, &ls); GsSetLsMatrix(&ls); GsSortObject4(&racer.handler, ot, shift+1, getScratchAddr(0)); // Draw reflection map GsSetLsMatrix(&ls); GsSortObject4(&racer.reflectHandler, ot, shift+2, getScratchAddr(0)); // --------------------------------- // Draw flame // --------------------------------- col = LimitRange(racer.speed>>8, 0, 64); size = LimitRange(racer.speed>>8, 0, 128); // Set odd vertices (points) for (i=1; i<6; i+=2) { ResetMatrix(mat.m); RotMatrixZ(4096*(i+1)/6, &mat); SetVector(&vec, 0, ((18*col)>>7)+((rand()%col)>>3), -10); ApplyMatrixLV(&mat, &vec, &vec); SetVertex(&flameVert[i], vec.vx, (vec.vy<<2)/3+8, vec.vz-12); } SetVertex(&flameVert[6], 0, 8, -(size/6)-20+(rand()&7)); // Random flame flicker if (!(rand()&7)) { dr = ((rand()&63)*size)>>7; dg = ((rand()&63)*size)>>7; db = ((rand()&63)*size)>>7; } // Set colours for (i=0; i<3; i++) { // Flicker the flame colours flamePrim[i*4].r0 = flamePrim[i*4+1].r0 = flamePrim[i*4+2].r0 = flamePrim[i*4+3].r0 = dr; flamePrim[i*4].r2 = flamePrim[i*4+1].r2 = flamePrim[i*4+2].r1 = flamePrim[i*4+3].r1 = dr; flamePrim[i*4].b0 = flamePrim[i*4+1].b0 = flamePrim[i*4+2].b0 = flamePrim[i*4+3].b0 = db; flamePrim[i*4].b1 = flamePrim[i*4+1].b1 = flamePrim[i*4+2].b1 = flamePrim[i*4+3].b1 = db; flamePrim[i*4].b2 = flamePrim[i*4+1].b2 = flamePrim[i*4+2].b2 = flamePrim[i*4+3].b2 = db; // Inside colour flamePrim[i*4].g0 = flamePrim[i*4].g2 = col>>1; flamePrim[i*4+1].g0 = flamePrim[i*4+1].g2 = col>>1; flamePrim[i*4+2].g0 = flamePrim[i*4+2].g1 = col>>1; flamePrim[i*4+3].g0 = flamePrim[i*4+3].g1 = col>>1; // Spike colour flamePrim[i*4].r1 = flamePrim[i*4+1].r1 = col<<1; // Blast colour flamePrim[i*4+2].r2 = col; flamePrim[i*4+3].r2 = col; } // Sort TMD GsSetLsMatrix(&ls); GsSortObject4(&racer.flameHandler, ot, shift+2, getScratchAddr(0)); // --------------------------------- // Draw speed lines // --------------------------------- // Get rotation matrix ResetMatrix(ls.m); RotMatrixX(racer.rot.vx, &ls); RotMatrixZ(racer.rot.vz, &ls); RotMatrixY(racer.rot.vy, &ls); racer.trail[1] = racer.trail[0]; racer.trail[3] = racer.trail[2]; // Get wing corner positions in 3d SetVector(&racer.trail[0], 26, 0, -30); ApplyMatrixLV(&ls, &racer.trail[0], &racer.trail[0]); racer.trail[0].vx += racer.pos.vx>>8; racer.trail[0].vy += racer.pos.vy>>8; racer.trail[0].vz += racer.pos.vz>>8; SetVector(&racer.trail[2], -26, 0, -30); ApplyMatrixLV(&ls, &racer.trail[2], &racer.trail[2]); racer.trail[2].vx += racer.pos.vx>>8; racer.trail[2].vy += racer.pos.vy>>8; racer.trail[2].vz += racer.pos.vz>>8; // Convert to 2d ApplyMatrixLV(&GsWSMATRIX, &racer.trail[0], &vec); vec.vz += GsWSMATRIX.t[2]; if (vec.vz > 0) { line.x0 = (vec.vx+GsWSMATRIX.t[0])*projection/vec.vz; line.y0 = (vec.vy+GsWSMATRIX.t[1])*projection/vec.vz; // Shorten distance between last pos & this pos by 3/4 vec.vx = (3*racer.trail[0].vx+racer.trail[1].vx)>>2; vec.vy = (3*racer.trail[0].vy+racer.trail[1].vy)>>2; vec.vz = (3*racer.trail[0].vz+racer.trail[1].vz)>>2; ApplyMatrixLV(&GsWSMATRIX, &vec, &vec); vec.vz += GsWSMATRIX.t[2]; if (vec.vz > 0) { line.x1 = (vec.vx+GsWSMATRIX.t[0])*projection/vec.vz; line.y1 = (vec.vy+GsWSMATRIX.t[1])*projection/vec.vz; GsSortGLine(&line, ot, 0);//racer.trail[i].vz >> priority); } } ApplyMatrixLV(&GsWSMATRIX, &racer.trail[2], &vec); vec.vz += GsWSMATRIX.t[2]; if (vec.vz > 0) { line.x0 = (vec.vx+GsWSMATRIX.t[0])*projection/vec.vz; line.y0 = (vec.vy+GsWSMATRIX.t[1])*projection/vec.vz; // Shorten distance between last pos & this pos by 3/4 vec.vx = (3*racer.trail[2].vx+racer.trail[3].vx)>>2; vec.vy = (3*racer.trail[2].vy+racer.trail[3].vy)>>2; vec.vz = (3*racer.trail[2].vz+racer.trail[3].vz)>>2; ApplyMatrixLV(&GsWSMATRIX, &vec, &vec); vec.vz += GsWSMATRIX.t[2]; if (vec.vz > 0) { line.x1 = (vec.vx+GsWSMATRIX.t[0])*projection/vec.vz; line.y1 = (vec.vy+GsWSMATRIX.t[1])*projection/vec.vz; GsSortGLine(&line, ot, 0);//racer.trail[i].vz >> priority); } } }