/************************************************************ * * Net Yaroze RollerCoaster (version 1.1) * - removed background gradient & time consuming atan call, * now runs at 50 fps * ***********************************************************/ // remove the comment tags on the next line to display timing value //#define SHOWTIME 1 //#define CALCULATE_NORMALS 1 #include #include #include "pad.h" #include "tmdtype.h" #define Y_ADJUST -400 #define CONEMAN_ADDRESS 0x80090000 #define TEXTURE1_ADDRESS 0x800f0000 #define CAM_ADDRESS 0x800f9000 #define VERTEX_ADDRESS 0x800e0000 + 144 #define MAX_FIXUP_POLYS 500 #define NUM_STEPS 219 #define NUM_ACTIVE_STEPS 219 #define FACES_PER_STEP 3 #define VERTICES_PER_STEP 4 #define OT_LENGTH 9 #define PACKETMAX2 (4000*24) /* Max GPU packets */ static PACKET packetArea[2][PACKETMAX2]; /* GPU PACKETS AREA */ static GsOT Wot[2]; /* Handler of OT */ static GsOT_TAG wtags[2][1< BLINK_HIDDEN+BLINK_VISIBLE) blinkcount = 0; if (blinkcount < BLINK_VISIBLE) GsSortSprite(&cam, &Wot[side], 1); /* draw map walls */ UpdateObjectCoordinates(&levelwalls.rotate, &levelwalls.coord); GsGetLs(&(levelwalls.coord), &tmpls); GsSetLightMatrix(&tmpls); GsSetLsMatrix(&tmpls); GsSortObject4( &(levelwalls.handler), &Wot[side], 3, getScratchAddr(0)); UpdateObjectCoordinates(&levelfloor.rotate, &levelfloor.coord); GsGetLs(&(levelfloor.coord), &tmpls); GsSetLightMatrix(&tmpls); GsSetLsMatrix(&tmpls); GsSortObject4( &(levelfloor.handler), &groundot[side], 3, getScratchAddr(0)); /* update player position, set rotation & draw */ // DrawObject(&coneman,conemanpos.vx, conemanpos.vy, conemanpos.vz, side); /* wait for drawing to complete */ DrawSync(0); count = GetRCnt(1); #ifdef SHOWTIME font = FntOpen(-280,-120,320,10,0,55); FntPrint("Time : %d ",count); FntFlush(font); #endif VSync(0); GsSwapDispBuff(); ResetRCnt(1); StartRCnt(1); GsSortClear(0,0,60,&groundot[side]); GsDrawOt(&groundot[side]); GsDrawOt(&Wot[side]); GsDrawOt(&cot[side]); if (DealWithControllerPad() == 0) break; } //main render loop ResetGraph(1); } // main // ----- Init routine ------------------------- void InitialiseAll (void) { int i,df; RECT Bg; long videomode; short * pt; /* copy the Bézier control points into an SVECTOR arrray for easy manipulation */ pt = (short *)(VERTEX_ADDRESS-144); for (i=0; i<24; i++) { points[i].vx = ((short) *pt)*5; pt++; points[i].vy = ((short) *pt)*5; pt++; points[i].vz = ((short) *pt)*5; pt++; } /* load textures */ LoadTexture((u_long *)TEXTURE1_ADDRESS, &tex1); LoadTexture((u_long *)CAM_ADDRESS, &camimg); /* ghost cam sprite */ InitGsSprite(&cam); cam.u = cam.v = 0; cam.tpage = 11; cam.attribute |= 2 << 24; cam.x = (200); cam.y = -120; cam.w = camimg.pw; cam.h = camimg.ph; screenwidth = 640; //SetVideoMode(MODE_PAL); videomode = GetVideoMode(); if (videomode == MODE_NTSC) screenheight = 240; else screenheight = 256; GetPadBuf(&bb0, &bb1); // Get controller reception buffer PadInit(); // init controller pad FntLoad(960,256); /* Create rollercoaster track & floor TMD's */ CreateRoller(); CreateFloor(); /* initialise all models */ SetUpObject(&levelwalls,(u_long *) &mapobject,0); SetUpObject(&levelfloor,(u_long *) &mapfloor,0); SetUpObject(&coneman,(u_long *) CONEMAN_ADDRESS,1); /* Initialise graphics & all those OT's */ GsInitGraph(screenwidth,screenheight,GsNONINTER|GsOFSGPU,1,0); GsDefDispBuff(0,0,0,screenheight); GsInit3D(); Wot[0].length=OT_LENGTH; Wot[0].org=wtags[0]; Wot[1].length=OT_LENGTH; Wot[1].org=wtags[1]; GsClearOt(0,0,&Wot[0]); GsClearOt(0,0,&Wot[1]); groundot[0].length=OT_LENGTH; groundot[0].org=groundtags[0]; groundot[1].length=OT_LENGTH; groundot[1].org=groundtags[1]; GsClearOt(0,0,&cot[0]); GsClearOt(0,0,&cot[1]); cot[0].length=OT_LENGTH; cot[0].org=ctags[0]; cot[1].length=OT_LENGTH; cot[1].org=ctags[1]; GsClearOt(0,0,&cot[0]); GsClearOt(0,0,&cot[1]); ProjectionDistance = 350; // screen to viewpoint distance GsSetProjection(ProjectionDistance); view.rz = 0; view.super = WORLD; GsSetRefView2(&view); //GsSetAmbient(ONE/2,ONE/2,ONE/2); GsSetAmbient(ONE/4,ONE/4,ONE/4); TheLights[0].vx = ONE; TheLights[0].vy = 0; TheLights[0].vz = 0; TheLights[0].r = 128; TheLights[0].g = 128; TheLights[0].b = 128; GsSetFlatLight(0, &TheLights[0]); /* GsSetLightMode(1); fog.dqa = -9000 *4096/64/ProjectionDistance; fog.dqb = 1.25 * 4096 * 4096; fog.rfc = 0; fog.gfc = 0; fog.bfc = 60; GsSetFogParam(&fog); */ } void FindPosition(SVECTOR * temp, SVECTOR * tangent, int * dist, int * index) { SVECTOR p4; int pi1,pi2,pi3; pi1 = *index; pi2 = (*index)+1; pi3 = (*index)+2; if (pi3 == 24) pi3 = 0; // The track is created with automatic mirroring of tangent-points // around the control points. This ensures that there are no sudden // changes in direction & velocity (equal magnitude & direction of tangent-vectors) p4.vx = points[pi3].vx - points[pi3+1].vx + points[pi3].vx; p4.vy = points[pi3].vy - points[pi3+1].vy + points[pi3].vy; p4.vz = points[pi3].vz - points[pi3+1].vz + points[pi3].vz; FindBCPoint(*dist, tangent,temp,points[pi1],points[pi2],p4,points[pi3]); // if you want to alter the speed, this is the place to do it *dist += 15;//5; if (*dist >= 1000) { *dist -= 1000; (*index)+=2; if (*index == 24) *index = 0; } } // ----- Misc. helper / object routines ------------------------------ void InitGsSprite (GsSPRITE* sprite) { sprite->attribute = 0; sprite->x = 0; sprite->y = 0; sprite->w = 0; sprite->h = 0; sprite->tpage = 0; sprite->u = 0; sprite->v = 0; sprite->cx = 0; sprite->cy = 0; sprite->r = 128; sprite->g = 128; sprite->b = 128; sprite->mx = 0; sprite->my = 0; sprite->scalex = ONE; sprite->scaley = ONE; sprite->rotate = 0; } void DrawObject(ObjectHandler * object, short tx, short ty, short tz, int side) { MATRIX tmpls; //,tmplw; VECTOR velocity; velocity.vx = velocity.vy = velocity.vz = 0; object->coord.coord.t[0] = tx; object->coord.coord.t[1] = ty; object->coord.coord.t[2] = tz; object->coord.flg = 0; UpdateObjectCoordinates(&object->rotate, &object->coord); GsGetLs(&(object->coord), &tmpls); GsSetLightMatrix(&tmpls); GsSetLsMatrix(&tmpls); GsSortObject4( &(object->handler), &cot[side], 3, getScratchAddr(0)); } void LoadTexture(u_long * addr, GsIMAGE * image) { GsGetTimInfo(addr+1, image); LoadImage((RECT *)&image->px, image->pixel); if((image->pmode>>3)&0x01) { LoadImage((RECT *)&image->cx, image->clut); } DrawSync(0); } void SetUpObject (ObjectHandler * object, u_long * obj_addr, short link) { u_long *pointer; object->position.vx = 0; object->position.vy = 0; object->position.vz = 0; object->rotate.vx = 0; object->rotate.vy = 0; object->rotate.vz = 0; GsInitCoordinate2(WORLD, &object->coord); object->handler.coord2 = &(object->coord); pointer = obj_addr; pointer++; if (link == 1) GsMapModelingData(pointer); pointer += 2; GsLinkObject4( (u_long)pointer, &object->handler, 0); } void UpdateObjectCoordinates (SVECTOR* rotationVector, GsCOORDINATE2* coordSystem) { MATRIX tempMatrix; tempMatrix.t[0] = coordSystem->coord.t[0]; tempMatrix.t[1] = coordSystem->coord.t[1]; tempMatrix.t[2] = coordSystem->coord.t[2]; RotMatrix(rotationVector, &tempMatrix); // get rotation matrix from rotation vector coordSystem->coord = tempMatrix; // assign new matrix to coordinate system coordSystem->flg = 0; // tell GTE that coordinate system has been updated } #define STEP 50 // ----- Pad routines ------------------------------ int DealWithControllerPad (void) { long pad = PadRead(); if (pad & PADselect) return 0; /* if (pad & PADLdown) levelwalls.rotate.vz -= STEP; if (pad & PADLup) levelwalls.rotate.vz += STEP; if (pad & PADLleft) levelwalls.rotate.vy -= STEP; if (pad & PADLright) levelwalls.rotate.vy += STEP; if (pad & PADL1) levelwalls.rotate.vx -= STEP; if (pad & PADL2) levelwalls.rotate.vx += STEP; */ /* if (pad & PADLdown) view.vrz -= STEP; if (pad & PADLup) view.vrz += STEP; if (pad & PADLleft) view.vry -= STEP; if (pad & PADLright) view.vry += STEP; if (pad & PADL1) view.vrx -= STEP; if (pad & PADL2) view.vrx += STEP; if (pad & PADRdown) view.vpz -= STEP; if (pad & PADRup) view.vpz += STEP; if (pad & PADRleft) view.vpy -= STEP; if (pad & PADRright) view.vpy += STEP; if (pad & PADR1) view.vpx -= STEP; if (pad & PADR2) view.vpx += STEP; */ return 1; } void PadInit (void) { GetPadBuf(&bb0, &bb1); } u_long PadRead(void) { return(~(*(bb0+3) | *(bb0+2) << 8 | *(bb1+3) << 16 | *(bb1+2) << 24)); } // ----- TMD creation routines ------------------------------ void CreatePrimitive(TMDPRIM_FLT4 * prim, short type, short normal, short v0, short v1, short v2, short v3) { short ofs; short yofs; short texsize; texsize = 64; yofs = type / 4; ofs = (type%4)*64; prim->mode = 0x2c00; prim->ilen = 0x07; prim->olen = 0x09; prim->cba = ((240+type) << 6) + (640 >> 4); prim->tsb = 10; prim->u0 = ofs+0; prim->v0 = yofs+(texsize-1); prim->u1 = ofs+0; prim->v1 = 0+yofs; prim->u2 = ofs+(texsize-1); prim->v2 = (texsize-1)+yofs; prim->u3 = ofs+(texsize-1); prim->v3 = yofs+0; prim->vertex0 = v0; prim->vertex1 = v1; prim->vertex2 = v2; prim->vertex3 = v3; prim->normal0 = normal; } void CreateQuadPrim(TMDPRIM_FL4 * prim,short normal, short v0, short v1, short v2, short v3, char r, char g, char b) { prim->olen = 0x05; prim->olen = 0x04; prim->mode = 0x2800; prim->mode2 = 0x28; prim->r = r; prim->g = g; prim->b = b; prim->vertex0 = v0; prim->vertex1 = v1; prim->vertex2= v2; prim->vertex3= v3; prim->normal0 = normal; } void CreateFloor() { int x,y; // set tmd header mapfloor.header.id = 0x00000041; mapfloor.header.flag = 1; mapfloor.header.nobj = 1; mapfloor.objtable.vert_top = (u_long*) &mapfloor.vertex; mapfloor.objtable.n_vert = FLOOR_VERTICES*FLOOR_VERTICES; mapfloor.objtable.normal_top = (u_long*) &mapfloor.normal; mapfloor.objtable.n_normal = 1; mapfloor.objtable.primitive_top = (u_long*) &mapfloor.packets; mapfloor.objtable.n_primitive = (FLOOR_VERTICES-1)*(FLOOR_VERTICES-1); mapobject.objtable.scale = 0; // create vertexlist for (y=0; y= NUM_STEPS) step1 -= NUM_STEPS; if (step2 >= NUM_STEPS) step2 -= NUM_STEPS; step1 *= VERTICES_PER_STEP; step2 *= VERTICES_PER_STEP; mapobject.packets[i].v0 = step2+1; mapobject.packets[i].v1 = step2; mapobject.packets[i].v2 = step1+1; mapobject.packets[i].v3 = step1; mapobject.packetsw[i*2].vertex0 = step1; mapobject.packetsw[i*2].vertex1 = step2; mapobject.packetsw[i*2].vertex2 = step1+2; mapobject.packetsw[i*2].vertex3 = step2+2; mapobject.packetsw[(i*2)+1].vertex0 = step2+1; mapobject.packetsw[(i*2)+1].vertex1 = step1+1; mapobject.packetsw[(i*2)+1].vertex2 = step2+3; mapobject.packetsw[(i*2)+1].vertex3 = step1+3; } } void CreateRoller() { int stepIndex; short leftw,rightw; int tunnel; int i,fixfaces; short leftr,leftg,leftb,rightr,rightg,rightb; tunnel = 0; fixfaces = 0; memcpy((void*)&mapobject.vertex,(void*) VERTEX_ADDRESS,(NUM_STEPS*VERTICES_PER_STEP)*sizeof(SVECTOR)); // set tmd header mapobject.header.id = 0x00000041; mapobject.header.flag = 1; mapobject.header.nobj = 1; mapobject.objtable.vert_top = (u_long*) &mapobject.vertex; mapobject.objtable.n_vert = NUM_STEPS*VERTICES_PER_STEP; mapobject.objtable.normal_top = (u_long*) &mapobject.normal; mapobject.objtable.n_normal = NUM_STEPS*FACES_PER_STEP; mapobject.objtable.primitive_top = (u_long*) &mapobject.packets; mapobject.objtable.n_primitive = NUM_ACTIVE_STEPS*3; mapobject.objtable.scale = 0; for (stepIndex=0; stepIndexvx = (short) ((x*4096) / len); p4->vy = (short) ((y*4096) / len); p4->vz = (short) ((z*4096) / len); // printf("Normal: %d %d %d\n",p4->vx,p4->vy,p4->vz); } void CalculatePointOnLine(SVECTOR p1, SVECTOR p2, SVECTOR * dest, int point) { dest->vx = (((p2.vx - p1.vx) * point) / 1000) + p1.vx; dest->vy = (((p2.vy - p1.vy) * point) / 1000) + p1.vy; dest->vz = (((p2.vz - p1.vz) * point) / 1000) + p1.vz; } /* point is the position along the curve (100% = 1000) */ void FindBCPoint(int point, SVECTOR * tangent, SVECTOR * temp, SVECTOR p1, SVECTOR p2, SVECTOR p3, SVECTOR p4) { SVECTOR npoints[6]; CalculatePointOnLine(p1,p2,&npoints[0],point); CalculatePointOnLine(p2,p3,&npoints[1],point); CalculatePointOnLine(p3,p4,&npoints[2],point); CalculatePointOnLine(npoints[0],npoints[1],&npoints[3],point); CalculatePointOnLine(npoints[1],npoints[2],&npoints[4],point); tangent->vx = npoints[4].vx - npoints[3].vx; tangent->vy = npoints[4].vy - npoints[3].vy; tangent->vz = npoints[4].vz - npoints[3].vz; CalculatePointOnLine(npoints[3],npoints[4],&npoints[5],point); temp->vx = npoints[5].vx; temp->vy = npoints[5].vy; temp->vz = npoints[5].vz; }