commit 4a94bceb8ffb438230975f84da7e4ab66e6523a5 Author: SlyVTT Date: Sat May 27 21:48:20 2023 +0200 Very first commit diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..87361b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Build files +/build-fx +/build-cg +/build-cg-push +/*.g1a +/*.g3a +/compile_flags.txt + +# Python bytecode +__pycache__/ + +# Common IDE files +*.sublime-project +*.sublime-workspace +.vscode diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..09d00d7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,39 @@ +# Configure with [fxsdk build-fx] or [fxsdk build-cg], which provide the +# toolchain file and module path of the fxSDK + +cmake_minimum_required(VERSION 3.15) +project(Pinball VERSION 1.0 LANGUAGES CXX C ASM) + +include(GenerateG3A) +include(Fxconv) + +find_package(Azur 0.1 REQUIRED) +find_package(Gint 2.9 REQUIRED) +find_package(LibProf 2.4 REQUIRED) + + +set(SOURCES + src/main.cpp + # ... +) +# Shared assets, fx-9860G-only assets and fx-CG-50-only assets +set(ASSETS + # ... +) + +set(ASSETS_cg + assets-cg/font.png + # ... +) + +fxconv_declare_assets(${ASSETS} ${ASSETS_cg} WITH_METADATA) + +add_executable(myaddin ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}}) +target_compile_options(myaddin PRIVATE -Wall -Wextra -O3 -std=c++20) +target_link_options(myaddin PRIVATE -Wl,-Map=Build_Addin.map -Wl,--print-memory-usage) +target_link_libraries(myaddin Azur::Azur -lnum LibProf::LibProf Gint::Gint -lstdc++) + +if("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50) + generate_g3a(TARGET myaddin OUTPUT "Pinball.g3a" + NAME "Pinball" ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png) +endif() diff --git a/README.md b/README.md new file mode 100644 index 0000000..e58f32b --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# This is my contribution for the Casio Programming Contest #30 (CPC#30) + +Program made using fxSDK/gint/Azur from Lephenixnoir. + +The theme of the contest is "The depths". + +7 days to prepare a game around that general theme. + +Started Saturday May 27th 2023 6pm and to be done by Saturday June 3rd 2023 6pm. + diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..95cdae9 --- /dev/null +++ b/TODO.txt @@ -0,0 +1,8 @@ +Add non circular obstacles + +Add several boards + +Add background pictures + +Add targets and enable bonus + diff --git a/assets-cg/example.png b/assets-cg/example.png new file mode 100644 index 0000000..8826800 Binary files /dev/null and b/assets-cg/example.png differ diff --git a/assets-cg/font.png b/assets-cg/font.png new file mode 100644 index 0000000..3cf3776 Binary files /dev/null and b/assets-cg/font.png differ diff --git a/assets-cg/fxconv-metadata.txt b/assets-cg/fxconv-metadata.txt new file mode 100644 index 0000000..5e3f5a8 --- /dev/null +++ b/assets-cg/fxconv-metadata.txt @@ -0,0 +1,4 @@ +*.png: + type: bopti-image + name_regex: (.*)\.png img_\1 + profile: p8_rgb565a diff --git a/assets-cg/icon-cg.xcf b/assets-cg/icon-cg.xcf new file mode 100644 index 0000000..5b854f0 Binary files /dev/null and b/assets-cg/icon-cg.xcf differ diff --git a/assets-cg/icon-sel.png b/assets-cg/icon-sel.png new file mode 100644 index 0000000..0ce3029 Binary files /dev/null and b/assets-cg/icon-sel.png differ diff --git a/assets-cg/icon-uns.png b/assets-cg/icon-uns.png new file mode 100644 index 0000000..039c096 Binary files /dev/null and b/assets-cg/icon-uns.png differ diff --git a/build b/build new file mode 100755 index 0000000..d3b1d35 --- /dev/null +++ b/build @@ -0,0 +1 @@ +fxsdk build-cg VERBOSE=1 diff --git a/buildpush b/buildpush new file mode 100755 index 0000000..9be693f --- /dev/null +++ b/buildpush @@ -0,0 +1,3 @@ +rm -r build-cg +rm *.g3a +fxsdk build-cg-push -s VERBOSE=1 diff --git a/capture b/capture new file mode 100755 index 0000000..0332a60 --- /dev/null +++ b/capture @@ -0,0 +1 @@ +fxlink -iw diff --git a/clean b/clean new file mode 100755 index 0000000..7d6a591 --- /dev/null +++ b/clean @@ -0,0 +1,4 @@ +rm -r build-cg/ +rm -r build-cg-push/ +rm assets-cg/levels/*.json +rm *.g3a diff --git a/send b/send new file mode 100755 index 0000000..b01e9b6 --- /dev/null +++ b/send @@ -0,0 +1 @@ +fxlink -sw *.g3a -u diff --git a/src/extrakeyboard.h b/src/extrakeyboard.h new file mode 100644 index 0000000..81b0f16 --- /dev/null +++ b/src/extrakeyboard.h @@ -0,0 +1,258 @@ +#ifndef EXTRAKEYBOARD_H +#define EXTRAKEYBOARD_H + +#include "extrakeyboard.h" +#include +#include +#include + +enum { + MYKEY_F1 = 0, + MYKEY_F2, + MYKEY_F3, + MYKEY_F4, + MYKEY_F5, + MYKEY_F6, + + MYKEY_SHIFT, + MYKEY_OPTN, + MYKEY_VARS, + MYKEY_MENU, + MYKEY_LEFT, + MYKEY_UP, + + MYKEY_ALPHA, + MYKEY_SQUARE, + MYKEY_POWER, + MYKEY_EXIT, + MYKEY_DOWN, + MYKEY_RIGHT, + + MYKEY_XOT, + MYKEY_LOG, + MYKEY_LN, + MYKEY_SIN, + MYKEY_COS, + MYKEY_TAN, + + MYKEY_FRAC, + MYKEY_FD, + MYKEY_LEFTP, + MYKEY_RIGHTP, + MYKEY_COMMA, + MYKEY_ARROW, + + MYKEY_7, + MYKEY_8, + MYKEY_9, + MYKEY_DEL, + + MYKEY_4, + MYKEY_5, + MYKEY_6, + MYKEY_MUL, + MYKEY_DIV, + + MYKEY_1, + MYKEY_2, + MYKEY_3, + MYKEY_ADD, + MYKEY_SUB, + + MYKEY_0, + MYKEY_DOT, + MYKEY_EXP, + MYKEY_NEG, + MYKEY_EXE, + + MYKEY_ACON, + + MYKEY_LASTENUM, +}; + +typedef struct { + bool pressed; + uint32_t since = 0; +} keyinfo; + +keyinfo MyKeyMapper[MYKEY_LASTENUM + 1]; + +class KeyboardExtra { +public: + KeyboardExtra() { + uint32_t timer = rtc_ticks(); + now = timer; + for (int i = 0; i <= MYKEY_LASTENUM; i++) + MyKeyMapper[i] = {.pressed = false, .since = timer}; + } + + ~KeyboardExtra() {} + + void Update(float dt) { + uint32_t timer = rtc_ticks(); + + now = timer; + + key_event_t ev; + + int keycode = -1; + + while ((ev = pollevent()).type != KEYEV_NONE) { + if (ev.key == KEY_F1) + keycode = MYKEY_F1; + else if (ev.key == KEY_F2) + keycode = MYKEY_F2; + else if (ev.key == KEY_F3) + keycode = MYKEY_F3; + else if (ev.key == KEY_F4) + keycode = MYKEY_F4; + else if (ev.key == KEY_F5) + keycode = MYKEY_F5; + else if (ev.key == KEY_F6) + keycode = MYKEY_F6; + + else if (ev.key == KEY_SHIFT) + keycode = MYKEY_SHIFT; + else if (ev.key == KEY_OPTN) + keycode = MYKEY_OPTN; + else if (ev.key == KEY_VARS) + keycode = MYKEY_VARS; + else if (ev.key == KEY_MENU) + keycode = MYKEY_MENU; + else if (ev.key == KEY_LEFT) + keycode = MYKEY_LEFT; + else if (ev.key == KEY_UP) + keycode = MYKEY_UP; + + else if (ev.key == KEY_ALPHA) + keycode = MYKEY_ALPHA; + else if (ev.key == KEY_SQUARE) + keycode = MYKEY_SQUARE; + else if (ev.key == KEY_POWER) + keycode = MYKEY_POWER; + else if (ev.key == KEY_EXIT) + keycode = MYKEY_EXIT; + else if (ev.key == KEY_DOWN) + keycode = MYKEY_DOWN; + else if (ev.key == KEY_RIGHT) + keycode = MYKEY_RIGHT; + + else if (ev.key == KEY_XOT) + keycode = MYKEY_XOT; + else if (ev.key == KEY_LOG) + keycode = MYKEY_LOG; + else if (ev.key == KEY_LN) + keycode = MYKEY_LN; + else if (ev.key == KEY_SIN) + keycode = MYKEY_SIN; + else if (ev.key == KEY_COS) + keycode = MYKEY_COS; + else if (ev.key == KEY_TAN) + keycode = MYKEY_TAN; + + else if (ev.key == KEY_FRAC) + keycode = MYKEY_FRAC; + else if (ev.key == KEY_FD) + keycode = MYKEY_FD; + else if (ev.key == KEY_LEFTP) + keycode = MYKEY_LEFTP; + else if (ev.key == KEY_RIGHTP) + keycode = MYKEY_RIGHTP; + else if (ev.key == KEY_COMMA) + keycode = MYKEY_COMMA; + else if (ev.key == KEY_ARROW) + keycode = MYKEY_ARROW; + + else if (ev.key == KEY_7) + keycode = MYKEY_7; + else if (ev.key == KEY_8) + keycode = MYKEY_8; + else if (ev.key == KEY_9) + keycode = MYKEY_9; + else if (ev.key == KEY_DEL) + keycode = MYKEY_DEL; + + else if (ev.key == KEY_4) + keycode = MYKEY_4; + else if (ev.key == KEY_5) + keycode = MYKEY_5; + else if (ev.key == KEY_6) + keycode = MYKEY_6; + else if (ev.key == KEY_MUL) + keycode = MYKEY_MUL; + else if (ev.key == KEY_DIV) + keycode = MYKEY_DIV; + + else if (ev.key == KEY_1) + keycode = MYKEY_1; + else if (ev.key == KEY_2) + keycode = MYKEY_2; + else if (ev.key == KEY_3) + keycode = MYKEY_3; + else if (ev.key == KEY_ADD) + keycode = MYKEY_ADD; + else if (ev.key == KEY_SUB) + keycode = MYKEY_SUB; + + else if (ev.key == KEY_0) + keycode = MYKEY_0; + else if (ev.key == KEY_DOT) + keycode = MYKEY_DOT; + else if (ev.key == KEY_EXP) + keycode = MYKEY_EXP; + else if (ev.key == KEY_NEG) + keycode = MYKEY_NEG; + else if (ev.key == KEY_EXE) + keycode = MYKEY_EXE; + + else if (ev.key == KEY_ACON) + keycode = MYKEY_ACON; + + if (keycode != -1) { + if (ev.type == KEYEV_DOWN) + MyKeyMapper[keycode] = {.pressed = true, .since = timer}; + else if (ev.type == KEYEV_UP) + MyKeyMapper[keycode] = {.pressed = false, .since = timer}; + else if (ev.type == KEYEV_HOLD) { + } + } else { + // do nothing, just unstack the event from the events queue + }; + } + } + + bool IsKeyPressedEvent(int key) { + return (MyKeyMapper[key].pressed && MyKeyMapper[key].since == now); + } + + bool IsKeyReleasedEvent(int key) { + return (!MyKeyMapper[key].pressed && MyKeyMapper[key].since == now); + } + + bool IsKeyPressed(int key) { return MyKeyMapper[key].pressed; } + + bool IsKeyReleased(int key) { return (!MyKeyMapper[key].pressed); } + + uint32_t IsKeyHoldPressed(int key) { + if (MyKeyMapper[key].pressed && MyKeyMapper[key].since < now) + return (uint32_t)(now - MyKeyMapper[key].since); + else + return 0; + } + + uint32_t IsKeyHoldReleased(int key) { + if (!MyKeyMapper[key].pressed && MyKeyMapper[key].since < now) + return (uint32_t)(now - MyKeyMapper[key].since); + else + return 0; + } + + uint32_t GetLastTickKeyEvent(int key) { + return (uint32_t)MyKeyMapper[key].since; + } + +private: + uint32_t now; +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..4602b32 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,387 @@ +#include "parameters.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "extrakeyboard.h" +#include "pinball_entities.h" +#include "stdint-gcc.h" +#include "utilities.h" +#include "vector2D.h" + +#include + +#include + +bool screenshot = false; +bool record = false; +bool textoutput = false; +bool exitToOS = false; + +uint8_t texttodraw = 1; + +#define SCALE_PIXEL 1 +#define X_RESOL (DWIDTH / SCALE_PIXEL) +#define Y_RESOL (DHEIGHT / SCALE_PIXEL) + +float elapsedTime = 0.0f; +uint32_t time_update = 0, time_render = 0; +prof_t perf_update, perf_render; + +static kmalloc_arena_t extended_ram = {0}; +static kmalloc_arena_t *_uram; +kmalloc_gint_stats_t *_uram_stats; +kmalloc_gint_stats_t *extram_stats; + +KeyboardExtra MyKeyboard; + +Scene MyPinball; + +libnum::num32 flipperHeight; +libnum::num32 cScale; +libnum::num32 simWidth; +libnum::num32 simHeight; + +/* return the scaled x component of a vector */ +uint16_t CX(Vector2D pos) { return (int) (pos.x * cScale); } + +/* return the scaled y component of a vector */ +uint16_t CY(Vector2D pos) { return (int) (libnum::num32(azrp_height) - pos.y * cScale); } + +/* create the pinball board */ +void SetupScene(void) { + libnum::num32 offset = libnum::num32(0.02); + + flipperHeight = libnum::num32(1.7); + cScale = libnum::num32(azrp_height) / flipperHeight; + simWidth = libnum::num32(azrp_width) / cScale; + simHeight = libnum::num32(azrp_height) / cScale; + + MyPinball.score = 0; + + MyPinball.borders.clear(); + MyPinball.borders.push_back( Vector2D( libnum::num32(0.74) , libnum::num32(0.25))); + MyPinball.borders.push_back( Vector2D( libnum::num32(1.0)-offset, libnum::num32(0.4))); + MyPinball.borders.push_back( Vector2D( libnum::num32(1.0)-offset, flipperHeight - offset)); + MyPinball.borders.push_back( Vector2D( offset , flipperHeight - offset)); + MyPinball.borders.push_back( Vector2D( offset , libnum::num32(0.4))); + MyPinball.borders.push_back( Vector2D( libnum::num32(0.26) , libnum::num32(0.25))); + MyPinball.borders.push_back( Vector2D( libnum::num32(0.26) , libnum::num32(offset))); + MyPinball.borders.push_back( Vector2D( libnum::num32(0.74) , libnum::num32(offset))); + + + MyPinball.balls.clear(); + libnum::num32 ball_radius = libnum::num32(0.03); + libnum::num32 ball_mass = libnum::num32( PI ) * ball_radius * ball_radius; + Vector2D ball_pos1( libnum::num32(0.92), libnum::num32(0.5) ); + Vector2D ball_vel1( libnum::num32(0.2) , libnum::num32(3.5) ); + + MyPinball.balls.push_back( Ball( ball_radius, ball_mass, ball_pos1, ball_vel1, 0.2 ) ); + Vector2D ball_pos2( libnum::num32(0.08), libnum::num32(0.5) ); + Vector2D ball_vel2( libnum::num32(0.2) , libnum::num32(3.5) ); + MyPinball.balls.push_back( Ball( ball_radius, ball_mass, ball_pos2, ball_vel2, 0.2 ) ); + + + MyPinball.obstacles.clear(); + MyPinball.obstacles.push_back( Obstacle( 0.1 , Vector2D( libnum::num32(0.25), libnum::num32(0.6) ), 2.0 ) ); + MyPinball.obstacles.push_back( Obstacle( 0.1 , Vector2D( libnum::num32(0.75), libnum::num32(0.5) ), 2.0 ) ); + MyPinball.obstacles.push_back( Obstacle( 0.12, Vector2D( libnum::num32(0.7 ), libnum::num32(1.0) ), 2.0 ) ); + MyPinball.obstacles.push_back( Obstacle( 0.1 , Vector2D( libnum::num32(0.2 ), libnum::num32(1.2) ), 2.0 ) ); + + + libnum::num32 flip_radius = libnum::num32( 0.03); + libnum::num32 flip_length = libnum::num32( 0.2); + libnum::num32 flip_maxRotation = libnum::num32(1.0); + libnum::num32 flip_restAngle = libnum::num32(0.5); + libnum::num32 flip_angularVelocity = libnum::num32(10.0); + libnum::num32 flip_restitution = libnum::num32(0.0); + Vector2D flip_pos1( libnum::num32(0.26), libnum::num32(0.22) ); + Vector2D flip_pos2( libnum::num32(0.74), libnum::num32(0.22) ); + MyPinball.flippers.push_back( Flipper( flip_radius, flip_pos1, flip_length, -flip_restAngle, flip_maxRotation, flip_angularVelocity, flip_restitution) ); + MyPinball.flippers.push_back( Flipper( flip_radius, flip_pos2, flip_length, libnum::num32(PI) + flip_restAngle, -flip_maxRotation, flip_angularVelocity, flip_restitution) ); +} + +void HandleBallBallCollision( Ball ball1, Ball ball2 ) +{ + libnum::num32 restitution = MIN( ball1.restitution, ball2.restitution ); + Vector2D dir = ball2.pos - ball1.pos; + libnum::num32 d = dir.Length(); + if ( d==libnum::num32(0) || d > (ball1.radius + ball2.radius) ) return; + + dir.Normalise(); + + libnum::num32 corr = (ball1.radius + ball2.radius-d) / libnum::num32(2); + ball1.pos.Add(dir, -corr); + ball2.pos.Add(dir, corr); + + libnum::num32 v1 = ball1.vel.Dot(dir); + libnum::num32 v2 = ball2.vel.Dot(dir); + + libnum::num32 m1 = ball1.mass; + libnum::num32 m2 = ball2.mass; + + libnum::num32 newV1 = (m1*v1 + m2*v2 - m2*(v1-v2)*restitution / (m1+m2) ); + libnum::num32 newV2 = (m1*v1 + m2*v2 - m1*(v2-v1)*restitution / (m1+m2) ); + + ball1.vel.Add(dir, newV1-v1 ); + ball2.vel.Add(dir, newV2-v2 ); +} + +void HandleBallOsbtacleCollision( Ball ball, Obstacle obstacle ) +{ + Vector2D dir = ball.pos - obstacle.pos; + libnum::num32 d = dir.Length(); + if ( d==libnum::num32(0) || d > (ball.radius + obstacle.radius) ) return; + + dir.Normalise(); + + libnum::num32 corr = ball.radius + obstacle.radius-d; + ball.pos.Add(dir, corr); + + libnum::num32 v = ball.vel.Dot(dir); + ball.vel.Add(dir, obstacle.pushVel-v ); + + MyPinball.score++; +} + + +static void hook_prefrag(int id, void *fragment, int size) { + if (!screenshot && !record) + return; + + /* 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; + } +} + +static void update(float dt) {} + +static void render(void) { + + azrp_clear(C_BLACK); + + int mod = MyPinball.borders.size(); + for( int i=0; ifree_memory + extram_stats->free_memory); +} + +static void get_inputs(float dt) { + if (MyKeyboard.IsKeyPressed(MYKEY_SHIFT) && + MyKeyboard.IsKeyHoldPressed(MYKEY_EXIT)) { + exitToOS = true; + }; + +#if (DEBUG_MODE) + 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; + }; + + if (MyKeyboard.IsKeyPressedEvent(MYKEY_F1)) { + } + if (MyKeyboard.IsKeyPressedEvent(MYKEY_F2)) { + } + if (MyKeyboard.IsKeyPressedEvent(MYKEY_F3)) { + } + if (MyKeyboard.IsKeyPressedEvent(MYKEY_F4)) { + } + if (MyKeyboard.IsKeyPressedEvent(MYKEY_F5)) { + } + if (MyKeyboard.IsKeyPressedEvent(MYKEY_F6)) { + } +#endif + + /* we can have either LEFT or RIGHT or NONE OF THEM pressed for the direction + */ +} + +bool AddMoreRAM(void) { + /* allow more RAM */ + char const *osv = (char *)0x80020020; + + if ((!strncmp(osv, "03.", 3) && osv[3] <= '8') && + gint[HWCALC] == HWCALC_FXCG50) // CG-50 + { + extended_ram.name = "extram"; + extended_ram.is_default = true; + extended_ram.start = (void *)0x8c200000; + extended_ram.end = (void *)0x8c4e0000; + + kmalloc_init_arena(&extended_ram, true); + kmalloc_add_arena(&extended_ram); + return true; + } else if (gint[HWCALC] == HWCALC_PRIZM) // CG-10/20 + { + + extended_ram.name = "extram"; + extended_ram.is_default = true; + + uint16_t *vram1, *vram2; + dgetvram(&vram1, &vram2); + dsetvram(vram1, vram1); + + extended_ram.start = vram2; + extended_ram.end = (char *)vram2 + 396 * 224 * 2; + + kmalloc_init_arena(&extended_ram, true); + kmalloc_add_arena(&extended_ram); + return true; + + } else if (gint[HWCALC] == HWCALC_FXCG_MANAGER) // CG-50 EMULATOR + { + + extended_ram.name = "extram"; + extended_ram.is_default = true; + extended_ram.start = (void *)0x88200000; + extended_ram.end = (void *)0x884e0000; + + kmalloc_init_arena(&extended_ram, true); + kmalloc_add_arena(&extended_ram); + return true; + } else { + return false; + } +} + +void FreeMoreRAM(void) { + memset(extended_ram.start, 0, + (char *)extended_ram.end - (char *)extended_ram.start); +} + +int main(void) { + exitToOS = false; + + _uram = kmalloc_get_arena("_uram"); + + bool canWeAllocate3Mb = AddMoreRAM(); + + __printf_enable_fp(); + __printf_enable_fixed(); + + azrp_config_scale(SCALE_PIXEL); + + azrp_shader_clear_configure(); + azrp_shader_image_rgb16_configure(); + azrp_shader_image_p8_configure(); + azrp_shader_image_p4_configure(); + azrp_shader_line_configure(); + azrp_shader_circle_configure(); + + azrp_hook_set_prefrag(hook_prefrag); + + usb_interface_t const *interfaces[] = {&usb_ff_bulk, NULL}; + usb_open(interfaces, GINT_CALL_NULL); + + SetupScene(); + + prof_init(); + + do { + perf_update = prof_make(); + prof_enter(perf_update); + + { + // all the stuff to be update should be put here + MyKeyboard.Update(elapsedTime); + get_inputs(elapsedTime); + + update(elapsedTime); + + // update the RAM consumption status + _uram_stats = kmalloc_get_gint_stats(_uram); + extram_stats = kmalloc_get_gint_stats(&extended_ram); + } + + 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 = ((float)(time_update + time_render)) / 1000.0f; + + } while (exitToOS == false); + + prof_quit(); + usb_close(); + + if (canWeAllocate3Mb) + FreeMoreRAM(); + + return 1; +} diff --git a/src/parameters.h b/src/parameters.h new file mode 100644 index 0000000..d7588c2 --- /dev/null +++ b/src/parameters.h @@ -0,0 +1,9 @@ +#ifndef PARAMETERS_H +#define PARAMETERS_H + + +#define DEBUG_MODE 1 +#define BIAS 1 +#define NOBIAS (1-BIAS) + +#endif \ No newline at end of file diff --git a/src/pinball_entities.h b/src/pinball_entities.h new file mode 100644 index 0000000..1e0446a --- /dev/null +++ b/src/pinball_entities.h @@ -0,0 +1,120 @@ +#ifndef PINBALL_ENTITIES_H +#define PINBALL_ENTITIES_H + +#include "stdint-gcc.h" +#include "utilities.h" +#include "vector2D.h" +#include + +#include + +class Ball { +public: + Ball(libnum::num32 radius, libnum::num32 mass, Vector2D pos, Vector2D vel, + libnum::num32 restitution) { + this->radius = radius; + this->mass = mass; + this->pos = pos.Clone(); + this->vel = vel.Clone(); + this->restitution = restitution; + } + + ~Ball() {} + + void Simulate(libnum::num32 dt, Vector2D gravity) { + this->vel.Add(gravity, dt); + this->pos.Add(this->vel, dt); + } + + libnum::num32 radius, mass, restitution; + Vector2D pos, vel; +}; + + +class Obstacle { +public: + Obstacle(libnum::num32 radius, Vector2D pos, libnum::num32 pushVel) { + this->radius = radius; + this->pos = pos.Clone(); + this->pushVel = pushVel; + } + + Obstacle() {} + + libnum::num32 radius, pushVel; + Vector2D pos; +}; + + +class Flipper { +public: + Flipper(libnum::num32 radius, Vector2D pos, libnum::num32 length, + libnum::num32 restAngle, libnum::num32 maxRotation, + libnum::num32 angularVelocity, libnum::num32 restitution) { + this->radius = radius; + this->pos = pos.Clone(); + this->length = length; + this->restAngle = restAngle; + this->maxRotation = ABS(maxRotation); + this->sign = SIGN(maxRotation); + this->angularVelocity = angularVelocity; + this->rotation = libnum::num32(0); + this->currentAngularVelocity = libnum::num32(0); + this->touchIdentifier = libnum::num32(-1); + } + + void Simulate(libnum::num32 dt) { + libnum::num32 prevRotation = this->rotation; + bool pressed = this->touchIdentifier >= 0; + if (pressed) + this->rotation = MIN(this->rotation + dt * this->angularVelocity, this->maxRotation); + else + this->rotation = MAX(this->rotation - dt * this->angularVelocity, 0.0); + this->currentAngularVelocity = this->sign * (this->rotation - prevRotation) / dt; + } + + bool Select(Vector2D pos) + { + Vector2D D;; + D.SubtractVectors(this->pos, pos); + bool test = (D.Length() < this->length); + return test; + } + + Vector2D getTip() + { + libnum::num32 angle = this->restAngle + this->sign * this->rotation; + Vector2D D( COS(angle) , SIN(angle) ); + + Vector2D tip = this->pos.Clone(); + tip.Add(D, this->length); + return tip; + } + + libnum::num32 radius; + Vector2D pos; + libnum::num32 length; + libnum::num32 restAngle; + libnum::num32 maxRotation; + libnum::num32 sign; + libnum::num32 angularVelocity; + libnum::num32 rotation; + libnum::num32 currentAngularVelocity; + libnum::num32 touchIdentifier; +}; + + +struct Scene +{ + Vector2D gravity; + libnum::num32 dt; + uint32_t score; + bool pause; + std::vector borders; + std::vector balls; + std::vector obstacles; + std::vector flippers; +}; + + +#endif \ No newline at end of file diff --git a/src/utilities.h b/src/utilities.h new file mode 100644 index 0000000..a1439ee --- /dev/null +++ b/src/utilities.h @@ -0,0 +1,48 @@ +#ifndef UTILITIES_H +#define UTILITIES_H + +#include +#include +#include + +void azrp_draw_text(int x, int y, char const *fmt, ...) +{ + char str[128]; + va_list args; + va_start(args, fmt); + vsnprintf(str, 128, fmt, args); + va_end(args); + + extern bopti_image_t img_font; + + for(int i = 0; str[i]; i++) { + if(str[i] < 32 || str[i] >= 0x7f) continue; + + int row = (str[i] - 32) >> 4; + int col = (str[i] - 32) & 15; + azrp_subimage(x + 5 * i, y, &img_font, 7 * col + 1, 9 * row + 1, 6, 8, DIMAGE_NONE); + } +} + +libnum::num32 COS( libnum::num32 angle ) +{ + float a = (float) angle; + float c = cos( a ); + return libnum::num32(c); +} + +libnum::num32 SIN( libnum::num32 angle ) +{ + float a = (float) angle; + float s = sin( a ); + return libnum::num32(s); +} + +#define MIN(a,b) ( ((a)>=(b)) ? (b) : (a) ) +#define MAX(a,b) ( ((a)<=(b)) ? (b) : (a) ) +#define ABS(a) ( ((a)>=0) ? (a) : -(a) ) +#define SIGN(a) ( (a)<0 ? -1 : (a>0) ? +1 : 0 ) + +#define PI 3.14159265 + +#endif \ No newline at end of file diff --git a/src/vector2D.h b/src/vector2D.h new file mode 100644 index 0000000..3d048f4 --- /dev/null +++ b/src/vector2D.h @@ -0,0 +1,210 @@ +#ifndef VECTOR2D_H +#define VECTOR2D_H + +#include +#include + +libnum::num32 sqrt_num32(libnum::num32 v) { + uint32_t t, q, b, r; + r = v.v; + b = 0x40000000; + q = 0; + while (b > 0x40) { + t = q + b; + if (r >= t) { + r -= t; + q = t + b; + } + r <<= 1; + b >>= 1; + } + q >>= 8; + libnum::num32 ret; + ret.v = q; + return ret; +} + + +class Vector2D { + +public: + Vector2D() { + this->x = libnum::num32(0); + this->y = libnum::num32(0); + } + + Vector2D(float x, float y) { + this->x = libnum::num32(x); + this->y = libnum::num32(y); + } + + Vector2D(libnum::num32 x, libnum::num32 y) { + this->x = x; + this->y = y; + } + + Vector2D(const Vector2D &v) { + this->x = v.x; + this->y = v.y; + } + + ~Vector2D() {} + + void Set( Vector2D v ) + { + this->x = v.x; + this->y = v.y; + } + + void Normalise( void ) + { + libnum::num32 len = this->Length(); + this->x /= len; + this->y /= len; + } + + Vector2D Clone(void) { + Vector2D NewVector(this->x, this->y); + return NewVector; + } + + Vector2D MakeVector(Vector2D A, Vector2D B) { + Vector2D NewVector(B.x - A.x, B.y - A.y); + return NewVector; + } + + void AddVectors(Vector2D a, Vector2D b) { + this->x = a.x + b.x; + this->y = a.y + b.y; + } + + void Add(Vector2D v, libnum::num32 scale) { + this->x += v.x * scale; + this->y += v.y * scale; + } + + void SubtractVectors(Vector2D a, Vector2D b) { + this->x = a.x - b.x; + this->y = a.y - b.y; + } + + void Subtract(Vector2D v, libnum::num32 scale) { + this->x -= v.x * scale; + this->y -= v.y * scale; + } + + libnum::num32 Length(void) { + return sqrt_num32(this->x * this->x + this->y * this->y); + } + + void Scale(libnum::num32 scale) { + this->x *= scale; + this->y *= scale; + } + + libnum::num32 Dot(Vector2D v) { return (this->x * v.x + this->y * v.y); } + + libnum::num32 Det(Vector2D v) { return (this->x * v.y - this->y * v.x); } + + Vector2D PerpCW(void) { + Vector2D temp(-this->y, this->x); + return temp; + } + + Vector2D PerpCCW(void) { + Vector2D temp(this->y, -this->x); + return temp; + } + + /* overloading of most interesting operators */ + libnum::num32 operator[](uint8_t pos) { return pos == 0 ? x : y; } + + Vector2D &operator=(const Vector2D &v) { + this->x = v.x; + this->y = v.y; + return *this; + } + + Vector2D operator+(const Vector2D &v) const { + return Vector2D(x + v.x, y + v.y); + } + + Vector2D operator-(const Vector2D &v) const { + return Vector2D(x - v.x, y - v.y); + } + + Vector2D &operator+=(Vector2D const &other) { + this->x += other.x; + this->y += other.y; + return *this; + } + + Vector2D operator-() const { return (Vector2D(-x, -y)); } + + Vector2D operator+() const { return *this; } + + Vector2D &operator-=(Vector2D const &other) { + this->x -= other.x; + this->y -= other.y; + return *this; + } + + Vector2D &operator*=(libnum::num32 scale) { + this->x *= scale; + this->y *= scale; + return *this; + } + + Vector2D &operator/=(libnum::num32 scale) { + this->x /= scale; + this->y /= scale; + return *this; + } + + friend Vector2D operator*(libnum::num32 scale, Vector2D const &v) { + Vector2D r; + r.x = v.x * scale; + r.y = v.y * scale; + return r; + } + + friend Vector2D operator*(Vector2D const &v, libnum::num32 scale) { + Vector2D r; + r.x = v.x * scale; + r.y = v.y * scale; + return r; + } + + friend Vector2D operator/(Vector2D const &v, libnum::num32 scale) { + Vector2D r; + r.x = v.x / scale; + r.y = v.y / scale; + return r; + } + + libnum::num32 x; + libnum::num32 y; +}; + + + +Vector2D ClosestPointOnSegment(Vector2D P, Vector2D A, Vector2D B ) { + Vector2D AB = B - A; + + libnum::num32 t = AB.Dot(AB); + + if (t == 0) return A; + + libnum::num32 t2 = (P.Dot(AB) - A.Dot(AB)) / t; + + if (t2 < libnum::num32(0)) t2 = libnum::num32(0); + if (t2 > libnum::num32(1)) t2 = libnum::num32(1); + + Vector2D C = A.Clone(); + C.Add(AB, t2); + + return C; +} + + +#endif \ No newline at end of file