// great game(boy) // (c) 2004 John Klima // implements the gba3ds API by torlus // free non-commercial use // for limited help with this code contact gameboy@cityarts.com // base includes #include "gba.h" #include "dispcnt.h" #include "keypad.h" #include "dma.h" #include "print.h" #include "timers.h" //for the text #include #define SEPCHAR " " // some useful functions #include "util.h" #include "gbautil.h" // engine-related declarations #include "engine.h" // model definitions (half-life SMD format) #include "afghan.h" #include "tomahawk.h" #include "b52.h" #include "f14.h" // animations definitions #include "anim_afghan.h" #include "anim_tomahawk.h" #include "anim_b52.h" #include "anim_f14.h" // textures definitions extern const u16 afghan_raw[]; u16 EWRAM *texture_afghan[] = { afghan_raw }; //the map extern const u16 un_texture[]; u16 EWRAM *texture_un[] = { un_texture}; //default blue extern const u16 b52_texture[]; u16 EWRAM *texture_b52[] = { b52_texture}; //specific b52 texture extern const u16 f14_texture[]; u16 EWRAM *texture_f14[] = { f14_texture}; //specific f14 texture // vertex definitions vertex EWRAM afghan_Vertex[472]; triangle *afghan_Triangle = (triangle *) afghan_triangle; //the terrain geometry vertex EWRAM tomahawk_Vertex[79]; triangle *tomahawk_Triangle = (triangle *) tomahawk_triangle; //cruise missle vertex EWRAM b52_Vertex[167]; triangle *b52_Triangle = (triangle *) b52_triangle; //b52 vertex EWRAM f14_Vertex[85]; triangle *f14_Triangle = (triangle *) f14_triangle; //f14 #define MULTIBOOT volatile const u8 __gba_multiboot; //MULTIBOOT //background images extern const u16 title_back[]; // angles and position of the character/object s32 A_afghan[3]; s32 T_afghan[3]; s32 A_tomahawk[3]; s32 T_tomahawk[3]; s32 A_b52[3]; s32 T_b52[3]; s32 A_f14[3]; s32 T_f14[3]; // camera position s32 camT[3]; s32 camA[3]; // camera matrix s32 cam[16]; // some vars for animation u32 afghan_frame=0; // fps counter u32 totframes = 0; u32 lastsec = 0; u32 fps=10; //non zero start u32 data_ptr_start = 0; //current "seek" offset into data u32 data_ptr_end = 0; u32 datetick = 0; u32 last_datetick = 100; //greater than biggest data date index to start u32 secondtick = 0; // data munition constants (not all geometry has been implemented in this release) #define M_b52 1; #define M_b2b 2; #define M_f_14 3; #define M_b1 4; #define M_tomahawk 5; #define M_tali_g 6; #define M_un_g 7; #define M_c130 8; #define M_hum 9; #define M_leaf 10; //total count of munition type for current date u8 ct_b52 = 0; u8 ct_b2b = 0; u8 ct_f_14 = 0; u8 ct_b1 = 0; u8 ct_tomahawk = 0; u8 ct_tali_g = 0; u8 ct_un_g = 0; u8 ct_c130 = 0; u8 ct_hum = 0; u8 ct_leaf = 0; //for multi-line text parsing typedef struct { char line[128]; }STRING; // the date text for given data extern const STRING datetext[]; // the munitions position data extern const s16 munition[]; //////////////////////////////////////////////////////////////////////////////////////////////////// //general functions void GetInput(void); void Init(void); void Render(void); //model functions void DoAfghan(s32 * animation, s8 framecount); void DoTomahawk(s32 * animation, s8 framecount); void DoB52(s32 * animation, s8 framecount); void Dof14(s32 * animation, s8 framecount); void getNextDataDate(void); //sound functions void InterruptProcess(void) __attribute__ ((section(".iwram"))); //the interrupt handle from crt0.s void DmaPlaySound (void); //DEBUG FUNCTIONS s16 debug_out[32]; void DrawDebug(void); void DrawText(s16 index, STRING *text); //////////////////////////////////////////////////////////////////////////////////////////////////// // AGB MAIN /////////////////////////////////////////////////////////////// void AgbMain(void) { // go into mode 3 SetMode(MODE_3 | BG2_ENABLE); // initialization stuff Init(); // start timer for FPS counter REG_TM2CNT = TIME_FREQUENCY_256 | TIME_ENABLE; REG_TM3CNT = TIME_OVERFLOW | TIME_ENABLE; while(1) { //framerate if (REG_TM3D != lastsec) { fps = totframes; totframes=0; lastsec=REG_TM3D; //every 15 seconds, click the day ahead secondtick++; if (secondtick>10) { secondtick=0; datetick++; if (datetick > 34) { datetick = 0; last_datetick = 100; data_ptr_start = 0; //current "seek" offset into data data_ptr_end = 0; } } } totframes++; //iterate next in list if (datetick != last_datetick) { getNextDataDate(); last_datetick = datetick; } GetInput(); // process keyboard input Render(); //render scene } } //HANDY DEBUG void DrawDebug() { int i = 0; for(i = 0; i < 8;i++) { printnum(5,8*i,debug_out[i]); } } //////////////////////////////////////////////////////////////////// //GAMEBOY INPUT /////////////////////////////////////////////////////////////////// void GetInput(void) { int WALK_STEP = 15; if(!(*KEYS & KEY_UP )) { camT[2] -= int2fp(WALK_STEP) ; } if(!(*KEYS & KEY_DOWN)) { camT[2] += int2fp(WALK_STEP) ; } if(!(*KEYS & KEY_LEFT)) { camT[0] += int2fp(WALK_STEP); } if(!(*KEYS & KEY_RIGHT)) { camT[0] -= int2fp(WALK_STEP); } if(!(*KEYS & KEY_A)) { camA[0] += 1 ; if (camA[0]>255) camA[0]=1; } if(!(*KEYS & KEY_B)) { camA[0] -= 1 ; if (camA[0]<=0) camA[0]=255; } if(!(*KEYS & KEY_R)) { //camA[2] -= 1; //if (camA[2]<=0) camA[2]=255; camT[1] -= int2fp(WALK_STEP) ; } if(!(*KEYS & KEY_L)) { //camA[2] += 1; //if (camA[2]>255) camA[2]=1; camT[1] += int2fp(WALK_STEP) ; } } void Init(void) { s32 i; // camera initialization camT[0]=int2fp(0); camT[1]=int2fp(250); camT[2]=int2fp(0); camA[0] = 32 ; // set up the camera matrix matrix_loadIdentity(cam); matrix_setTranslation(cam, camT); matrix_setRotation(cam, camA); // scene/character angles and position A_afghan[0] = 0; A_afghan[1] = 0; A_afghan[2] = 0; T_afghan[0] = 0; T_afghan[1] = 0; T_afghan[2] = 0; A_tomahawk[0] = 0; A_tomahawk[1] = 0; A_tomahawk[2] = 0; T_tomahawk[0] = 0; T_tomahawk[1] = 0; T_tomahawk[2] = int2fp(20); A_b52[0] = 0; A_b52[1] = 0; A_b52[2] = 0; T_b52[0] = int2fp(20); T_b52[1] = 0; T_b52[2] = int2fp(20); A_f14[0] = 0; A_f14[1] = 0; A_f14[2] = 0; T_f14[0] = int2fp(20); T_f14[1] = 0; T_f14[2] = int2fp(20); //initialize object vertices for(i=0; i< afghan_VERTEXCOUNT;i++) { afghan_Vertex[i].bone = afghan_vertex[ 6*i + 0 ]; afghan_Vertex[i].rel[0] = afghan_vertex[ 6*i + 1 ]; afghan_Vertex[i].rel[1] = afghan_vertex[ 6*i + 2 ]; afghan_Vertex[i].rel[2] = afghan_vertex[ 6*i + 3 ]; afghan_Vertex[i].u = afghan_vertex[ 6*i + 4 ]; afghan_Vertex[i].v = afghan_vertex[ 6*i + 5 ]; } for(i=0; i< tomahawk_VERTEXCOUNT;i++) { tomahawk_Vertex[i].bone = tomahawk_vertex[ 6*i + 0 ]; tomahawk_Vertex[i].rel[0] = tomahawk_vertex[ 6*i + 1 ]; tomahawk_Vertex[i].rel[1] = tomahawk_vertex[ 6*i + 2 ]; tomahawk_Vertex[i].rel[2] = tomahawk_vertex[ 6*i + 3 ]; tomahawk_Vertex[i].u = tomahawk_vertex[ 6*i + 4 ]; tomahawk_Vertex[i].v = tomahawk_vertex[ 6*i + 5 ]; } for(i=0; i< b52_VERTEXCOUNT;i++) { b52_Vertex[i].bone = b52_vertex[ 6*i + 0 ]; b52_Vertex[i].rel[0] = b52_vertex[ 6*i + 1 ]; b52_Vertex[i].rel[1] = b52_vertex[ 6*i + 2 ]; b52_Vertex[i].rel[2] = b52_vertex[ 6*i + 3 ]; b52_Vertex[i].u = b52_vertex[ 6*i + 4 ]; b52_Vertex[i].v = b52_vertex[ 6*i + 5 ]; } for(i=0; i< f14_VERTEXCOUNT;i++) { f14_Vertex[i].bone = f14_vertex[ 6*i + 0 ]; f14_Vertex[i].rel[0] = f14_vertex[ 6*i + 1 ]; f14_Vertex[i].rel[1] = f14_vertex[ 6*i + 2 ]; f14_Vertex[i].rel[2] = f14_vertex[ 6*i + 3 ]; f14_Vertex[i].u = f14_vertex[ 6*i + 4 ]; f14_Vertex[i].v = f14_vertex[ 6*i + 5 ]; } } //////////////////////////////////////////////////////////////////// //moving scene rendering functions //////////////////////////////////////////////////////////////////// void Render(void) { // loads the background image into our screen buffer DMACopy(title_back, ScreenBuffer, (WIDTH*HEIGHT)>>1, DMA_ENABLE | DMA_TIMEING_IMMEDIATE | DMA_32 ); // initialize the Z-Buffer (240*160*2) bytes Fill(ZBuffer,500,8); //position camera matrix_loadIdentity(cam); matrix_setRotation(cam, camA); matrix_setTranslation(cam, camT); DoAfghan(anim_afghan_animation, anim_afghan_FRAMECOUNT); Draw(afghan_Triangle, afghan_Vertex, texture_afghan, afghan_TRIANGLECOUNT ); //rip through data and draw what needs drawing u32 index =0; s16 date = 0; s16 type = 0; s16 x = 0; s16 y = 0; s16 z = 0; for (index = data_ptr_start; index>1, DMA_ENABLE | DMA_TIMEING_IMMEDIATE | DMA_32 ); } ////////////////////////////////////////////////////////////// //model drawing/animations ////////////////////////////////////////////////////////////// void DoAfghan(s32 * animation, s8 framecount) { s32 org[16]; s32 *afghan_first_joint ; // transform vertices according to current skeleton afghan_first_joint = animation + ((afghan_JOINTCOUNT * afghan_frame)<<4); afghan_frame++; debug_out[0] = afghan_frame; if (afghan_frame == framecount ) afghan_frame=0; // transform vertices according to current skeleton Animate( afghan_Vertex, afghan_VERTEXCOUNT, afghan_first_joint ); // moves the character in order to set its first joint (character hostspot) to (0,0,0) matrix_loadIdentity(org); matrix_setInverseTranslation(org, afghan_first_joint+12); TransformVertices( afghan_Vertex, afghan_VERTEXCOUNT, org ); //rotate-translate objects matrix_loadIdentity(org); matrix_setRotation(org, A_afghan); matrix_setTranslation(org, T_afghan); TransformVertices( afghan_Vertex, afghan_VERTEXCOUNT, org ); //apply camera position TransformVertices( afghan_Vertex, afghan_VERTEXCOUNT, cam ); Perspective( afghan_Vertex, afghan_VERTEXCOUNT ); } void DoTomahawk(s32 * animation, s8 framecount) { s32 org[16]; s32 *tomahawk_first_joint ; s32 frame = 0; // transform vertices according to current skeleton tomahawk_first_joint = animation + ((tomahawk_JOINTCOUNT * frame)<<4); // transform vertices according to current skeleton Animate( tomahawk_Vertex, tomahawk_VERTEXCOUNT, tomahawk_first_joint ); // moves the character in order to set its first joint (character hostspot) to (0,0,0) matrix_loadIdentity(org); matrix_setInverseTranslation(org, tomahawk_first_joint+12); TransformVertices( tomahawk_Vertex, tomahawk_VERTEXCOUNT, org ); //rotate-translate objects matrix_loadIdentity(org); matrix_setRotation(org, A_tomahawk); matrix_setTranslation(org, T_tomahawk); TransformVertices( tomahawk_Vertex, tomahawk_VERTEXCOUNT, org ); //apply camera position TransformVertices( tomahawk_Vertex, tomahawk_VERTEXCOUNT, cam ); Perspective( tomahawk_Vertex, tomahawk_VERTEXCOUNT ); } void Dof14(s32 * animation, s8 framecount) { s32 org[16]; s32 *f14_first_joint ; s32 frame = 0; // transform vertices according to current skeleton f14_first_joint = animation + ((f14_JOINTCOUNT * frame)<<4); // transform vertices according to current skeleton Animate( f14_Vertex, f14_VERTEXCOUNT, f14_first_joint ); // moves the character in order to set its first joint (character hostspot) to (0,0,0) matrix_loadIdentity(org); matrix_setInverseTranslation(org, f14_first_joint+12); TransformVertices( f14_Vertex, f14_VERTEXCOUNT, org ); //rotate-translate objects matrix_loadIdentity(org); matrix_setRotation(org, A_f14); matrix_setTranslation(org, T_f14); TransformVertices( f14_Vertex, f14_VERTEXCOUNT, org ); //apply camera position TransformVertices( f14_Vertex, f14_VERTEXCOUNT, cam ); Perspective( f14_Vertex, f14_VERTEXCOUNT ); } void DoB52(s32 * animation, s8 framecount) { s32 org[16]; s32 *b52_first_joint ; s32 frame = 0; // transform vertices according to current skeleton b52_first_joint = animation + ((b52_JOINTCOUNT * frame)<<4); // transform vertices according to current skeleton Animate( b52_Vertex, b52_VERTEXCOUNT, b52_first_joint ); // moves the character in order to set its first joint (character hostspot) to (0,0,0) matrix_loadIdentity(org); matrix_setInverseTranslation(org, b52_first_joint+12); TransformVertices( b52_Vertex, b52_VERTEXCOUNT, org ); //rotate-translate objects matrix_loadIdentity(org); matrix_setRotation(org, A_b52); matrix_setTranslation(org, T_b52); TransformVertices( b52_Vertex, b52_VERTEXCOUNT, org ); //apply camera position TransformVertices( b52_Vertex, b52_VERTEXCOUNT, cam ); Perspective( b52_Vertex, b52_VERTEXCOUNT ); } /////////////////////////////////////////////////////////////// //SOUND /////////////////////////////////////////////////////////////// void InterruptProcess(void) { //Sample finished! Stop DMA mode Direct sound REG_TM0CNT_H=0; //disable timer 0 REG_DMA1CNT_H=0; //stop DMA //clear the interrupt(s) REG_IF |= REG_IF; } void DmaPlaySound (void) { /* //Play a mono sound at 11khz in DMA mode Direct Sound //uses timer 0 as sampling rate source //uses timer 1 to count the samples played in order to stop the sound REG_SOUNDCNT_L=0; REG_SOUNDCNT_H=0x0b0F; //DS A&B + fifo reset + timer0 + max volume to L and R REG_SOUNDCNT_X=0x0080; //turn sound chip on REG_DMA1SAD=(unsigned long) _trackone; // _binary_lo1234_pcm_start; //dma1 source REG_DMA1DAD=0x040000a0; //write to FIFO A address REG_DMA1CNT_H=0xb600; //dma control: DMA enabled+ start on FIFO+32bit+repeat REG_TM1CNT_L= 0xA9DD; //0x7098; //0xffff-the number of samples to play REG_TM1CNT_H=0xC4; //enable timer1 + irq and cascade from timer 0 REG_IE=0x10; //enable irq for timer 1 overflow REG_IME=1; //enable interrupt //Formula for playback frequency is: 0xFFFF-round(cpuFreq/playbackFreq) //REG_TM0CNT_L=0xFBE8; //16khz playback freq REG_TM0CNT_L=0xFA10; //11.025 khz REG_TM0CNT_H=0x0080; //enable timer at CPU freq done = 0; */ } void DrawText(s16 index, STRING *text) { //pull index line from STRING array and print it out in 1-3 lines char line1[32]; char line2[32]; char line3[32]; char temp[128]; char *word=NULL; line1[0]='\0'; line2[0]='\0'; line3[0]='\0'; temp[0]='\0'; strcpy(&temp,&text[index]); word=strtok(&temp,SEPCHAR); while (word != NULL) { strcat(&line1," "); strcat(&line1,word); word=strtok(NULL,SEPCHAR); if (strlen(&line1)>20) goto line_2 ; } line_2: while (word != NULL) { strcat(&line2," "); strcat(&line2,word); word=strtok(NULL,SEPCHAR); if (strlen(&line2)>20) goto line_3 ; } line_3: while (word != NULL) { strcat(&line3," "); strcat(&line3,word); word=strtok(NULL,SEPCHAR); } prints(5,130, line1); prints(5,140, line2); prints(5,150, line3); } void getNextDataDate(void) { //uses global datetick, and data_ptr_start and data_ptr_end //to scan forward till next new date. s32 lookat_date = 100; while(lookat_date != datetick) { lookat_date = munition[data_ptr_start * 5]; data_ptr_start++; } data_ptr_start--; //back up one lookat_date = datetick; data_ptr_end = data_ptr_start; while(lookat_date == datetick) { lookat_date = munition[data_ptr_end * 5]; data_ptr_end++; } data_ptr_end--; //back up one }