#include "gint/display-cg.h" #include "gint/display.h" #include "parameters.h" #include #include #include "./Shaders/AzurShaders.h" #include #include #include #if (DEBUG_MODE) #if !(CALCEMU) #include #include #endif #endif #include #include #include #include #include #include #include #include "./Utilities/extrakeyboard.h" #include "./Pinball/pinball_entities.h" #include "./Pinball/simulations.h" #include "stdint-gcc.h" #include "./Pinball/tables.h" #include "./Utilities/utilities.h" #include "./Utilities/vector2D.h" #include #include "./Pinball/tables.h" #include bool screenshot = false; bool record = false; bool textoutput = false; bool exitToOS = false; uint8_t texttodraw = 1; uint8_t CurrentSequence = 0; float elapsedTime = 0.0f; float realDeltaTime = 0.0f; float cumulatedTime = 0.0f; uint32_t time_update = 0, time_render = 0; prof_t perf_update, perf_render; KeyboardExtra MyKeyboard; Scene MyPinball; /* TODO : this is for debugging purpose only to be removed when fixed */ bool targetline = false; /* create the pinball board */ void SetupScene(int which_table) { if (which_table == 0) Setup_Table_0(); else if (which_table == 1) Setup_Table_1(); else if (which_table == 2) Setup_Table_2(); else if (which_table == 3) Setup_Table_3(); else if (which_table == 4) Setup_Table_4(); else if (which_table == 5) Setup_Table_5(); else if (which_table == 6) Setup_Table_6(); cumulatedTime = 0.0f; } static void hook_prefrag(int id, void *fragment, int size) { if (!screenshot && !record) return; #if !(CALCEMU) /* Screenshot takes precedence */ char const *type = screenshot ? "image" : "video"; int pipe = usb_ff_bulk_output(); if (id == 0) { usb_fxlink_header_t h; usb_fxlink_image_t sh; int size = azrp_width * azrp_height * 2; usb_fxlink_fill_header(&h, "fxlink", type, size + sizeof sh); sh.width = htole32(azrp_width); sh.height = htole32(azrp_height); sh.pixel_format = htole32(USB_FXLINK_IMAGE_RGB565); usb_write_sync(pipe, &h, sizeof h, false); usb_write_sync(pipe, &sh, sizeof sh, false); } usb_write_sync(pipe, fragment, size, false); if (id == azrp_frag_count - 1) { usb_commit_sync(pipe); screenshot = false; } #endif } static void update(float dt) { MyPinball.dt = libnum::num32(dt); /* Close the ball locker after 1 second to avoid balls to return into the channel */ if (cumulatedTime>1.0f) MyPinball.locker_is_enabled = true; /* Update the rotation of the flippers as per user inputs */ for (int i = 0; i < MyPinball.flippers.size(); i++) MyPinball.flippers[i].Simulate(MyPinball.dt); for (int i = 0; i < MyPinball.balls.size(); i++) { /* Update the position of the balls */ MyPinball.balls[i].Simulate(MyPinball.dt, MyPinball.gravity); /* Update the balls and check for collisions between balls (if more than two * balls) */ if (MyPinball.balls.size() >= 2) { for (int j = 0; j < MyPinball.balls.size(); j++) if (i != j) HandleBallBallCollision(&MyPinball.balls[i], &MyPinball.balls[j]); } /* Check for collision with bumpers (improve the score) */ for (int j = 0; j < MyPinball.obstacles.size(); j++) HandleBallObstacleCollision(&MyPinball.balls[i], MyPinball.obstacles[j]); /* Check for collision with islands (geometric forms to deviate the balls)*/ for (int j = 0; j < MyPinball.islands.size(); j++) { HandleBallIslandCollision(&MyPinball.balls[i], MyPinball.islands[j], libnum::num(0.01)); } /* Check for collision with the pinball entry locker borders */ if (MyPinball.has_locker && MyPinball.locker_is_enabled) HandleBallIslandCollision(&MyPinball.balls[i], MyPinball.locker, libnum::num(0.01)); /* Check for collision with flippers */ for (int j = 0; j < MyPinball.flippers.size(); j++) HandleBallFlipperCollision(&MyPinball.balls[i], MyPinball.flippers[j]); /* Check for collision with the pinball borders */ HandleBallBorderCollision(&MyPinball.balls[i], MyPinball.borders); } } static void render(void) { /* Clear Screen */ azrp_clear(RGB565_BLACK); /* render the side image if available */ if (MyPinball.sideimage != nullptr) azrp_image_p8(azrp_width - MyPinball.sideimage->width - 25, 5, MyPinball.sideimage, DIMAGE_NONE); /* Render the border of the pinball table */ CollectionRender( MyPinball.borders, RGB565_WHITE ); if (MyPinball.has_locker) { /* draw the locker : red if inactive and white if active and considered as a border*/ CollectionRender( MyPinball.locker, MyPinball.locker_is_enabled ? RGB565_WHITE : RGB565_BLOODYRED); #if(0) /* TODO this is for debugging */ /* Something is buggy when azrp_filled_circle is used !!! */ /* wile it is working when lines are drawn - strange bug, need to be fixed */ if (targetline) { azrp_line(CX(MyPinball.Lock_pos)-5, CY(MyPinball.Lock_pos),CX(MyPinball.Lock_pos)+5, CY(MyPinball.Lock_pos), MyPinball.Lock_color); azrp_line(CX(MyPinball.Lock_pos), CY(MyPinball.Lock_pos)-5,CX(MyPinball.Lock_pos), CY(MyPinball.Lock_pos)+5, MyPinball.Lock_color); } else azrp_filledcircle(CX(MyPinball.Lock_pos), CY(MyPinball.Lock_pos), CR(MyPinball.Lock_radius), MyPinball.Lock_color); #endif } /* Render the circular bumpers that gives score points and push the ball away */ for (int i = 0; i < MyPinball.obstacles.size(); i++) MyPinball.obstacles[i].Render(); /* render the non circular obstacles that just block the path of the ball */ for (int i = 0; i < MyPinball.islands.size(); i++) CollectionRender( MyPinball.islands[i] , RGB565_WHITE); /* render the balls */ for (int i = 0; i < MyPinball.balls.size(); i++) MyPinball.balls[i].Render(); /* render de flippers */ for (int i = 0; i < MyPinball.flippers.size(); i++) MyPinball.flippers[i].Render(); #if (DEBUG_MODE) /* debug info (FPS and current game duration )*/ azrp_draw_text(150, 0, "FPS = %.0f - DeltaTime = %.3f ms" , (float)(1.0f / realDeltaTime), realDeltaTime * 1000.0f ); if (MyPinball.balls[MyPinball.CurrentBallToLaunch].IsInBucket( MyPinball.BucketMin , MyPinball.BucketMax )) azrp_rect( 10, 10, 10, 10, C_GREEN ); else azrp_rect( 10, 10, 10, 10, C_RED ); #endif /* score */ azrp_draw_pinball(250, 200, RGB565_DEEPPURPLE, "Score:%d", MyPinball.score); } static void get_inputs(float dt) { /* EXIT THE GAME */ if (MyKeyboard.IsKeyPressed(MYKEY_SHIFT) && MyKeyboard.IsKeyHoldPressed(MYKEY_EXIT)) { exitToOS = true; } /* LEFT FLIPPER */ if (MyKeyboard.IsKeyPressed(MYKEY_F1) || MyKeyboard.IsKeyPressed(MYKEY_LEFT) ) { for (int i = 0; i < MyPinball.flippers.size(); i++) if (MyPinball.flippers[i].side == LEFT) MyPinball.flippers[i].touchIdentifier = libnum::num32(0); } else { for (int i = 0; i < MyPinball.flippers.size(); i++) if (MyPinball.flippers[i].side == LEFT) MyPinball.flippers[i].touchIdentifier = libnum::num32(-1); } /* RIGHT FLIPPER */ if (MyKeyboard.IsKeyPressed(MYKEY_F6) || MyKeyboard.IsKeyPressed(MYKEY_RIGHT) ) { for (int i = 0; i < MyPinball.flippers.size(); i++) if (MyPinball.flippers[i].side == RIGHT) MyPinball.flippers[i].touchIdentifier = libnum::num32(0); } else { for (int i = 0; i < MyPinball.flippers.size(); i++) if (MyPinball.flippers[i].side == RIGHT) MyPinball.flippers[i].touchIdentifier = libnum::num32(-1); } #if(!DEMO) /* RESET THE GAME AND CHANGE THE CURRENT TABLE ( [OPTN] + [Fx] loads Table #x )*/ if (MyKeyboard.IsKeyPressed(MYKEY_SHIFT) && MyKeyboard.IsKeyHoldPressed(MYKEY_F1)) { SetupScene(0); } if (MyKeyboard.IsKeyPressed(MYKEY_SHIFT) && MyKeyboard.IsKeyHoldPressed(MYKEY_F2)) { SetupScene(1); } if (MyKeyboard.IsKeyPressed(MYKEY_SHIFT) && MyKeyboard.IsKeyHoldPressed(MYKEY_F3)) { SetupScene(2); } if (MyKeyboard.IsKeyPressed(MYKEY_SHIFT) && MyKeyboard.IsKeyHoldPressed(MYKEY_F4)) { SetupScene(3); } if (MyKeyboard.IsKeyPressed(MYKEY_SHIFT) && MyKeyboard.IsKeyHoldPressed(MYKEY_F5)) { SetupScene(4); } if (MyKeyboard.IsKeyPressed(MYKEY_SHIFT) && MyKeyboard.IsKeyHoldPressed(MYKEY_F6)) { SetupScene(5); } if (MyKeyboard.IsKeyPressed(MYKEY_ALPHA) && MyKeyboard.IsKeyHoldPressed(MYKEY_F1)) { SetupScene(6); } #endif if (MyKeyboard.IsKeyPressed(MYKEY_EXE)) { if (MyPinball.balls[MyPinball.CurrentBallToLaunch].IsStopped() || MyPinball.balls[MyPinball.CurrentBallToLaunch].IsInBucket( MyPinball.BucketMin , MyPinball.BucketMax )) { cumulatedTime=0.0f; MyPinball.locker_is_enabled = false; MyPinball.balls[MyPinball.CurrentBallToLaunch].SetPosition( MyPinball.InitialPosition ); MyPinball.balls[MyPinball.CurrentBallToLaunch].SetSpeed( Vector2D( libnum::num32(0.0), libnum::num32(3.5)) ); } } // TODO : to be changed to remove cumulatedTime if (MyKeyboard.IsKeyReleasedEvent(MYKEY_VARS) && MyPinball.has_locker && cumulatedTime<1.0f) { MyPinball.locker_is_enabled = !MyPinball.locker_is_enabled; } #if (DEBUG_MODE) #if !(CALCEMU) if (MyKeyboard.IsKeyPressed(MYKEY_OPTN) && MyKeyboard.IsKeyPressedEvent(MYKEY_7) && usb_is_open()) { screenshot = true; }; if (MyKeyboard.IsKeyPressed(MYKEY_OPTN) && MyKeyboard.IsKeyPressedEvent(MYKEY_8) && usb_is_open()) { record = true; }; if (MyKeyboard.IsKeyPressed(MYKEY_OPTN) && MyKeyboard.IsKeyPressedEvent(MYKEY_9) && usb_is_open()) { record = false; }; #endif #endif } int main(void) { exitToOS = false; __printf_enable_fp(); __printf_enable_fixed(); azrp_config_scale(SCALE_PIXEL); azrp_hook_set_prefrag(hook_prefrag); #if (DEBUG_MODE) #if !(CALCEMU) usb_interface_t const *interfaces[] = {&usb_ff_bulk, NULL}; usb_open(interfaces, GINT_CALL_NULL); #endif #endif // TODO : Currently Loads Table #4 that is the most complete one // To be adjusted by a menu and based on user input in final version SetupScene(6); prof_init(); do { perf_update = prof_make(); prof_enter(perf_update); { // all the stuff to be update should be put here MyKeyboard.Update(); get_inputs(elapsedTime); update(elapsedTime); } prof_leave(perf_update); time_update = prof_time(perf_update); perf_render = prof_make(); prof_enter(perf_render); { // all the stuff to be rendered should be put here render(); azrp_update(); } prof_leave(perf_render); time_render = prof_time(perf_render); /* elapsedTime expressed in microseconds when coming from the libprof high * accuracy time measurement */ realDeltaTime = ((float)(time_update + time_render)) / 1000000.0f; /* this is actual real time */ elapsedTime = ((float)1.0f / 60.0f); /* TODO : when shaders will be optimized and quick enough, elapsedTime will be set to actual realDeltaTime */ cumulatedTime += elapsedTime; /* TODO : this is a ugly trick to mitigate the problem with the locker - for now it closes after a certain time*/ } while (exitToOS == false); prof_quit(); #if (DEBUG_MODE) #if !(CALCEMU) usb_close(); #endif #endif return 1; }