commit db40e678944e204ebff57f93b7c7dcb795bd2ac3 Author: SlyVTT Date: Tue Nov 7 21:45:39 2023 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f069e7c --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Build files +/build-fx +/build-cg +/build-cg-push +/*.g1a +/*.g3a + +# Python bytecode +__pycache__/ + +# Common IDE files +*.sublime-project +*.sublime-workspace +.vscode \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..893a120 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,44 @@ +# 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(ScreenSaver VERSION 1.0 LANGUAGES CXX C ASM) + +include(GenerateG3A) +include(Fxconv) + +find_package(Gint 2.9 REQUIRED) +find_package(LibProf 2.4 REQUIRED) + + +set(SOURCES + src/main.cpp + + src/utilities/fast_trig.cpp + src/utilities/extrakeyboard.cpp + src/utilities/utilities.cpp + src/utilities/vector2D.cpp + + src/effects/plasma.cpp + src/effects/morph.cpp +) + +set(ASSETS_cg + assets-cg/fontmatrix.png + assets-cg/fontFantasy.png + + assets-cg/SlyVTT.png + assets-cg/Selection.png +) + +fxconv_declare_assets(${ASSETS_cg} WITH_METADATA) + +add_executable(ssaver ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}}) +target_compile_options(ssaver PRIVATE -Wall -Wextra -O3 -std=c++20) +target_link_options(ssaver PRIVATE -Wl,-Map=Build_Addin.map -Wl,--print-memory-usage -fno-use-cxa-atexit -fpermissive) +target_link_libraries(ssaver -lnum LibProf::LibProf Gint::Gint -lstdc++) + +if("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50) + generate_g3a(TARGET ssaver OUTPUT "SSaver.g3a" + NAME " " 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..e69de29 diff --git a/assets-cg/Selection.png b/assets-cg/Selection.png new file mode 100644 index 0000000..6a92dd0 Binary files /dev/null and b/assets-cg/Selection.png differ diff --git a/assets-cg/SlyVTT.png b/assets-cg/SlyVTT.png new file mode 100644 index 0000000..0a1990f Binary files /dev/null and b/assets-cg/SlyVTT.png differ diff --git a/assets-cg/bglens.png b/assets-cg/bglens.png new file mode 100644 index 0000000..f6ae4ce Binary files /dev/null and b/assets-cg/bglens.png differ diff --git a/assets-cg/bglens2.png b/assets-cg/bglens2.png new file mode 100644 index 0000000..ec73ffd Binary files /dev/null and b/assets-cg/bglens2.png differ diff --git a/assets-cg/bglens3.png b/assets-cg/bglens3.png new file mode 100644 index 0000000..03d9c5a Binary files /dev/null and b/assets-cg/bglens3.png differ diff --git a/assets-cg/bglens4.png b/assets-cg/bglens4.png new file mode 100644 index 0000000..d5e1ada Binary files /dev/null and b/assets-cg/bglens4.png differ diff --git a/assets-cg/createfont.py b/assets-cg/createfont.py new file mode 100644 index 0000000..dfe9189 --- /dev/null +++ b/assets-cg/createfont.py @@ -0,0 +1,3 @@ +from make_grid import * + +make_grid(5, 5) diff --git a/assets-cg/eye.png b/assets-cg/eye.png new file mode 100644 index 0000000..a6f778f Binary files /dev/null and b/assets-cg/eye.png differ diff --git a/assets-cg/fontFantasy.png b/assets-cg/fontFantasy.png new file mode 100644 index 0000000..0b93339 Binary files /dev/null and b/assets-cg/fontFantasy.png differ diff --git a/assets-cg/fontmatrix.png b/assets-cg/fontmatrix.png new file mode 100644 index 0000000..b410043 Binary files /dev/null and b/assets-cg/fontmatrix.png differ diff --git a/assets-cg/fxconv-metadata.txt b/assets-cg/fxconv-metadata.txt new file mode 100644 index 0000000..d69fd3f --- /dev/null +++ b/assets-cg/fxconv-metadata.txt @@ -0,0 +1,44 @@ +bglens3.png: + type: bopti-image + profile: p8 + name: bglens + +bglens4.png: + type: bopti-image + profile: p8 + name: bglens2 + +fontmatrix.png: + name: matrix + type: font + charset: print + grid.size: 9x14 + +bglens.png: + type: bopti-image + profile: p8 + name: bglens3 + +eye.png: + type: bopti-image + profile: p4 + name: eye + +SlyVTT.png: + type: bopti-image + profile: p8 + name: SlyVTT + +Selection.png: + type: bopti-image + profile: p8 + name: Selection + +fontFantasy.png: + type: font + charset: print + name: font_fantasy + grid.size: 8x8 + grid.padding: 1 + proportional: true + diff --git a/assets-cg/gff b/assets-cg/gff new file mode 100644 index 0000000..bce4402 --- /dev/null +++ b/assets-cg/gff @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +from math import ceil +from sys import argv +from PIL import Image, ImageDraw, ImageFont + +if (len(argv) < 4): + raise BaseException("At least three arguments expected: " + \ + " " + \ + "[initial char index] [char range]") + +font_path = argv[1] +font_size = int(argv[2]) +image_out = argv[3] +initial_char_index = int(argv[4]) if len(argv) > 4 else 0x20 +char_range = int(argv[5]) if len(argv) > 5 else 96 +line_count = ceil(char_range / 16) +scan_index = 0x20 if len(argv) > 4 else initial_char_index +scan_range = 0x30ff - 0x20 if len(argv) > 4 else char_range + +assert char_range > 1 + +mode = '1' # 1-bit depth +background_color = (1) # white +foreground_color = (0) # black + +# load font +font = ImageFont.truetype(font_path, font_size) + +# find max char size +char_width = 0 +char_height = 0 +for i in range(scan_range): + bbox = list(font.getbbox(chr(scan_index + i))) + # don't you dare overlap + if (bbox[0] < 0): + bbox[2] = -bbox[0] + if (bbox[1] < 0): + bbox[3] -= bbox[1] + if bbox[2] > char_width: + char_width = bbox[2] + if bbox[3] > char_height: + char_height = bbox[3] + +image_out_width = char_width * 16 +image_out_height = char_height * line_count + +# fxconv metadata +print(f"{image_out.split('/')[-1]}:") +print(" type: font") +print(" charset: print") +print(f" grid.size: {char_width}x{char_height}") + +# create image +im = Image.new(mode, (image_out_width, image_out_height)) + +# draw +draw = ImageDraw.Draw(im) +draw.rectangle((0, 0, image_out_width, image_out_height), fill=background_color) + +x = -char_width +y = 0 +for i in range(char_range): + x += char_width + char = chr(initial_char_index + i) + bbox = font.getbbox(char) + x_mod = 0 + y_mod = 0 + # don't you dare overlap + if (bbox[0] < 0): + x_mod = -bbox[0] + if (bbox[1] < 0): + y_mod = -bbox[1] + if i != 0 and i % 16 == 0: + x = 0 + y += char_height + draw.text((x + x_mod, y + y_mod), char, fill=foreground_color, font=font) + +# save +im.save(image_out) + diff --git a/assets-cg/icon-sel.png b/assets-cg/icon-sel.png new file mode 100644 index 0000000..9907442 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..de8dba4 Binary files /dev/null and b/assets-cg/icon-uns.png differ diff --git a/assets-cg/make_grid.py b/assets-cg/make_grid.py new file mode 100644 index 0000000..8e93d69 --- /dev/null +++ b/assets-cg/make_grid.py @@ -0,0 +1,28 @@ +from PIL import Image, ImageDraw + + +def make_grid(char_w, char_h): + """ + Arguments + char_w : character's width (int) + char_h : character's height (int) + + Description + Make a grid with 1 pxl of padding and boxes around each character in order to make easier the font creation. + + Usage + Just enter : + >>> make_grid(char_width, char_height) + An image will be create in the same folder that this programm in *.png format and the name starts by : 'grid_'. + """ + width, height = 16 * (char_w + 2), 6 * (char_h + 2) + grid = Image.new('RGB', (width, height), 'white') + draw = ImageDraw.Draw(grid) + + for x in range(0, width, char_w + 2): + for y in range(0, height, char_h + 2): + if (x // (char_w + 2) - y // (char_h + 2)) % 2: color = 'blue' + else: color = 'orange' + draw.rectangle((x, y, x + char_w + 1, y + char_h + 1), fill=None, outline=color) + + grid.save(f"grid_{char_w}—{char_h}.png") diff --git a/assets-cg/matrix.ttf b/assets-cg/matrix.ttf new file mode 100644 index 0000000..3d232ae Binary files /dev/null and b/assets-cg/matrix.ttf 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/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..0c58279 --- /dev/null +++ b/clean @@ -0,0 +1,2 @@ +rm -r build-cg/ +rm *.g3a diff --git a/rebuild b/rebuild new file mode 100755 index 0000000..1f9dd05 --- /dev/null +++ b/rebuild @@ -0,0 +1,3 @@ +rm -r build-cg +rm *.g3a +fxsdk build-cg VERBOSE=1 diff --git a/send b/send new file mode 100755 index 0000000..273aa57 --- /dev/null +++ b/send @@ -0,0 +1 @@ +fxlink -sw *.g3a diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..4613882 --- /dev/null +++ b/src/config.h @@ -0,0 +1,10 @@ +#ifndef CONFIG_H +#define CONFIG_H + + + #define MAXHEIGHT 224 + + + #define MORE_RAM 1 + +#endif diff --git a/src/effects/effects.h b/src/effects/effects.h new file mode 100644 index 0000000..e3239d9 --- /dev/null +++ b/src/effects/effects.h @@ -0,0 +1,26 @@ +#ifndef EFFECTS_H +#define EFFECTS_H + +#include "../config.h" + +#include +#include + + +/* EFFECT #1 : PLASMA EFFECT */ + +void plasma_init( bopti_image_t *screen ); +void plasma_update( bopti_image_t *screen, float dt ); +void plasma_render( bopti_image_t *screen ); +void plasma_deinit( bopti_image_t *screen ); + + +/* EFFECT #2 : MORPHING EFFECT : FROM SPHERE TO TORUS */ + +void morph_init( bopti_image_t *screen ); +void morph_update( bopti_image_t *screen, float dt ); +void morph_render( bopti_image_t *screen ); +void morph_deinit( bopti_image_t *screen ); + + +#endif diff --git a/src/effects/morph.cpp b/src/effects/morph.cpp new file mode 100644 index 0000000..2dd6cf3 --- /dev/null +++ b/src/effects/morph.cpp @@ -0,0 +1,165 @@ +#include "effects.h" + +#include +#include "../utilities/fast_trig.h" + +#include + +/********************************\ + * MOPRHING EFFECT - MODULE 2 * + * Specific data and structures * +\********************************/ + +typedef struct +{ + libnum::num32 x; + libnum::num32 y; + libnum::num32 z; + libnum::num32 rx; + libnum::num32 ry; + libnum::num32 rz; + int16_t sx; + int16_t sy; +} Vertex3D; + +#define NB_POINTS 2048 +#define SCALE 80 + +Vertex3D Sphere[NB_POINTS]; +Vertex3D Torus[NB_POINTS]; +Vertex3D Morph[NB_POINTS]; + +libnum::num32 scale; +libnum::num32 eye; +libnum::num32 eyescale; +int centerx, centery; + +static float anglef = 0.0; +static int angle = 0; + +static double frame_counter = 0; + +void ProjectVertex( Vertex3D *vertex ) +{ + libnum::num32 divisor = libnum::num32(1) / (scale * vertex->rz + eye); + + vertex->sx = centerx + (int) ((eyescale * vertex->rx) * divisor ); + vertex->sy = centery + (int) ((eyescale * vertex->ry) * divisor ); +} + + +void RotateVertex( Vertex3D *vertex, int ax, int ay, int az ) +{ + // Rotate around x axis + vertex->ry = vertex->y * FastCosInt(ax) - vertex->z * FastSinInt(ax); + vertex->rz = vertex->y * FastSinInt(ax) + vertex->z * FastCosInt(ax); + + // Rotate around y axis + vertex->rx = vertex->x * FastCosInt(ay) + vertex->rz * FastSinInt(ay); + vertex->rz = vertex->x * -FastSinInt(ay) + vertex->rz * FastCosInt(ay); + + // Rotate around z axis + libnum::num32 tmpx = vertex->rx * FastCosInt(az) - vertex->ry * FastSinInt(az); + vertex->ry = vertex->rx * FastSinInt(az) + vertex->ry * FastCosInt(az); + vertex->rx = tmpx; +} + + + +void morph_init( bopti_image_t *screen ) +{ + uint16_t palette[256]; + size_t palette_size = 512; + + for(int i=0; i<256; ++i) + palette[i] = C_RGB( 0, 0, 0 ); + + palette[255] = C_WHITE; + + memcpy(screen->palette, palette, palette_size); + + + eye = libnum::num32( 250 ); + scale = libnum::num32( SCALE ); + eyescale = eye*scale; + + centerx = (DWIDTH / 2); + centery = (MAXHEIGHT / 2); + + // Create Sphere + for (int i = 0; i < NB_POINTS; i++) + { + int theta = rand() % 360; + int phi = rand() % 360 ; + Sphere[i].x = FastCosInt(phi) * FastSinInt(theta); + Sphere[i].y = FastSinInt(phi) * FastSinInt(theta); + Sphere[i].z = FastCosInt(theta); + } + + // Create torus + for (int i = 0; i < NB_POINTS; i++) + { + int theta = rand() % 360; + int phi = rand() % 360 ; + Torus[i].x = (libnum::num32(0.8) + libnum::num32(0.4) * FastCosInt(theta)) * FastCosInt(phi); + Torus[i].y = (libnum::num32(0.8) + libnum::num32(0.4) * FastCosInt(theta)) * FastSinInt(phi); + Torus[i].z = libnum::num32(0.4) * FastSinInt(theta); + } + + //data = (int8_t*) malloc( DWIDTH*MAXHEIGHT ); +} + + +void morph_update( bopti_image_t *screen, [[Maybe_unused]] float dt ) +{ + anglef += dt / 10000.0; + angle = (int) anglef; + + frame_counter += dt / 10000.0; + int frame = (int)frame_counter % 1024; + + + // Transform the torus into a sphere + if (frame < 256) { + int key = frame; + for (int i = 0; i < NB_POINTS; i++) { + Morph[i].x = (libnum::num32(key) * Sphere[i].x + libnum::num32(256 - key) * Torus[i].x) / libnum::num32(256); + Morph[i].y = (libnum::num32(key) * Sphere[i].y + libnum::num32(256 - key) * Torus[i].y) / libnum::num32(256); + Morph[i].z = (libnum::num32(key) * Sphere[i].z + libnum::num32(256 - key) * Torus[i].z) / libnum::num32(256); + } + } + + // Transform the sphere into a torus + if (frame > 512 && frame <= 768) { + int key = frame - 512; + for (int i = 0; i < NB_POINTS; i++) { + Morph[i].x = (libnum::num32(key) * Torus[i].x + libnum::num32(256 - key) * Sphere[i].x) / libnum::num32(256); + Morph[i].y = (libnum::num32(key) * Torus[i].y + libnum::num32(256 - key) * Sphere[i].y) / libnum::num32(256); + Morph[i].z = (libnum::num32(key) * Torus[i].z + libnum::num32(256 - key) * Sphere[i].z) / libnum::num32(256); + } + } + + memset( screen->data, -128, DWIDTH*MAXHEIGHT ); + + int8_t *data = (int8_t *) screen->data; + + for (int i = 0; i < NB_POINTS; i++) + { + RotateVertex(&Morph[i], 0, angle, angle); + ProjectVertex(&Morph[i]); + data[ Morph[i].sx + Morph[i].sy * DWIDTH ] = 127; + } + + memcpy( screen->data, data, DWIDTH*MAXHEIGHT ); +} + + +void morph_render( bopti_image_t *screen ) +{ + dimage(0,0,screen); +} + +void morph_deinit( bopti_image_t *screen ) +{ + +} \ No newline at end of file diff --git a/src/effects/plasma.cpp b/src/effects/plasma.cpp new file mode 100644 index 0000000..34e4969 --- /dev/null +++ b/src/effects/plasma.cpp @@ -0,0 +1,86 @@ +#include "effects.h" + +#include +#include + +/********************************\ + * PLASMA EFFECT - MODULE 1 * + * Specific data and structures * +\********************************/ + +static int aSin[512]; +uint8_t index; +static uint16_t pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0, tpos1, tpos2, tpos3, tpos4; +uint16_t x; + + +void plasma_init( bopti_image_t *screen ) +{ + uint16_t palette[256]; + size_t palette_size = 512; + + for(int i=0; i<64; ++i) + { + palette[i] = C_RGB( i<<2, 255 - ((i << 2) + 1), 0 ); + palette[i+64] = C_RGB( 255, (i << 2) + 1, 0 ); + palette[i+128] = C_RGB( 255 - ((i << 2) + 1), 255 - ((i << 2) + 1), 0 ); + palette[i+192] = C_RGB( 0, (i << 2) + 1, 0 ); + } + + memcpy(screen->palette, palette, palette_size); + + for (int i = 0; i < 512; i++) + { + float rad = ((float)i * 0.703125) * 0.0174532; /* 360 / 512 * degree to rad, 360 degrees spread over 512 values to be able to use AND 512-1 instead of using modulo 360*/ + aSin[i] = sin(rad) * 1024; /*using fixed point math with 1024 as base*/ + } +} + +void plasma_update( bopti_image_t *screen, [[Maybe_unused]] float dt ) +{ + uint8_t *image = (uint8_t *) screen->data; + + tpos4 = pos4; + tpos3 = pos3; + + for (int i = 0; i < MAXHEIGHT; ++i) + { + tpos1 = pos1 + 5; + tpos2 = pos2 + 3; + + tpos3 &= 511; + tpos4 &= 511; + + for (int j = 0; j < DWIDTH; ++j) + { + tpos1 &= 511; + tpos2 &= 511; + + x = aSin[tpos1] + aSin[tpos2] + aSin[tpos3] + aSin[tpos4]; /*actual plasma calculation*/ + + index = 128 + (x >> 4); /*fixed point multiplication but optimized so basically it says (x * (64 * 1024) / (1024 * 1024)), x is already multiplied by 1024*/ + + *image++ = index; + + tpos1 += 5; + tpos2 += 3; + } + + tpos4 += 3; + tpos3 += 1; + } + + pos1 +=9; + pos3 +=8; +} + + +void plasma_render( bopti_image_t *screen ) +{ + dimage(0,0,screen); +} + +void plasma_deinit( bopti_image_t *screen ) +{ + +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..502db06 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,313 @@ +#include +#include +#include +#include +#include + +#include + +#include "config.h" + +#include +#include + +#include +#include +#include + +#include "utilities/fast_trig.h" +#include "utilities/extrakeyboard.h" +#include "utilities/utilities.h" + + +#include "effects/effects.h" + + + + +#define TOTAL_NB_EFFECT 2 +typedef void (*PtrToFunc)( bopti_image_t * ); +typedef void (*PtrToFuncDt)( bopti_image_t *, float ); + +PtrToFunc Effects_Init[] = { &plasma_init, &morph_init }; +PtrToFuncDt Effects_Update[] = { &plasma_update, &morph_update }; +PtrToFunc Effects_Render[] = { &plasma_render, &morph_render }; +PtrToFunc Effects_DeInit[] = { &plasma_deinit, &morph_deinit }; +int current_effect = 1; + + +#if(MORE_RAM) + static kmalloc_arena_t extended_ram = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0,0,0,0,0,0 }; + static kmalloc_arena_t *_uram; + kmalloc_gint_stats_t *_uram_stats; + kmalloc_gint_stats_t *extram_stats; +#else + static kmalloc_arena_t *_uram; + kmalloc_gint_stats_t *_uram_stats; +#endif + + + +bool exitToOS = false; +bool skip_intro = false; +bool screenshot = false; +bool record = false; + + +KeyboardExtra Keyboard; + + +float elapsedTime = 0.0f; +uint32_t time_update=0, time_render=0; +prof_t perf_update, perf_render; + + +extern font_t font_fantasy; +extern font_t matrix; + + + +bopti_image_t *screen; +uint16_t palette[256]; +size_t palette_size = 512; +uint8_t imagedata[DWIDTH*MAXHEIGHT]; + + + +int get_pixel(bopti_image_t const *img, int x, int y) +{ + return image_get_pixel(img, x, y); +} + +void set_pixel(bopti_image_t *img, int x, int y, int color) +{ + image_set_pixel(img, x, y, color); +} + + +/********************************\ + * INTRODUCING THE CCJ DEMOS * + * Specific data and structures * +\********************************/ + +extern bopti_image_t SlyVTT, Selection; +static char text[] = "CHILL CASIO JAM 2022"; +void run_intro( void ) +{ + dclear( C_BLACK ); + dimage(0, 12, &SlyVTT ); + dprint( 175, 25, C_WHITE, "%s", text); + dimage( 175, 50, &Selection ); + dprint( 175, 180, C_WHITE, "PRESS EXE TO SELECT" ); + dprint( 175, 200, C_WHITE, "OLDSCHOOL DEMO EFFECTS" ); +} + + + +bool AddMoreRAM( void ) +{ + #if(MORE_RAM && !CALCEMU) + + /* allow more RAM */ + char const *osv = (char*) 0x80020020; + + if((!strncmp(osv, "03.", 3) && osv[3] <= '6') && 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 false; + + } + 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; + } + #elif (MORE_RAM && CALCEMU) + + 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 + + return false; + + #endif + + return false; +} + +void FreeMoreRAM( void ) +{ + #if(MORE_RAM) + memset(extended_ram.start, 0, (char *)extended_ram.end - (char *)extended_ram.start); + #endif +} + + + +static void Initialise( void ) +{ + (*Effects_Init[ current_effect ])( screen ); +} + +static void Render( void ) +{ + (*Effects_Render[ current_effect ])( screen ); +} + +static void Update( [[maybe_unused]] float dt ) +{ + (*Effects_Update[ current_effect ])( screen, dt ); +} + +static void Close( void ) +{ + (*Effects_DeInit[ current_effect ])( screen ); +} + + + +static void GetInputs( [[maybe_unused]] float dt ) +{ + if (Keyboard.IsKeyPressed(MYKEY_EXIT)) {exitToOS = true; }; + + if (Keyboard.IsKeyPressed(MYKEY_F1) && current_effect>=1) + { + // close the current effect by calling its DeInitFunction + Close(); + // switch to new effect + current_effect--; + // initialise the current effect + Initialise(); + } + + if (Keyboard.IsKeyPressed(MYKEY_F6) && current_effect<=TOTAL_NB_EFFECT-2) + { + // close the current effect by calling its DeInitFunction + Close(); + // switch to new effect + current_effect++; + // initialise the current effect + Initialise(); + } +} + + + +int main(void) +{ + + _uram = kmalloc_get_arena("_uram"); + #if(MORE_RAM) + bool canWeAllocateMoreRam = AddMoreRAM(); + #endif + + + int EntryClockLevel; + EntryClockLevel = clock_get_speed(); + clock_set_speed( CLOCK_SPEED_F4 ); + + srand( rtc_ticks() ); + + screen = image_alloc( DWIDTH, MAXHEIGHT, IMAGE_P8_RGB565A ); + screen->width = DWIDTH; + screen->height = MAXHEIGHT; + + exitToOS = false; + + Initialise(); + + __printf_enable_fp(); + __printf_enable_fixed(); + + prof_init(); + + do + { + perf_update = prof_make(); + prof_enter(perf_update); + { + // all the stuff to be update should be put here + Keyboard.Update( elapsedTime ); + + // read inputs from the player + GetInputs( elapsedTime ); + + // update as per the time spend to do the loop + Update( elapsedTime ); + + // update the RAM consumption status + _uram_stats = kmalloc_get_gint_stats(_uram); + #if(MORE_RAM) + extram_stats = kmalloc_get_gint_stats(&extended_ram); + #endif + } + 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 + dclear( C_BLACK ); + + Render(); + + dupdate(); + } + prof_leave(perf_render); + time_render = prof_time(perf_render); + + elapsedTime = ((float) (time_update+time_render)); + } + while (exitToOS==false); + + + prof_quit(); + + clock_set_speed( EntryClockLevel ); + + image_free( screen ); + + #if(MORE_RAM) + if (canWeAllocateMoreRam) FreeMoreRAM( ); + #endif + + return 1; +} diff --git a/src/utilities/extrakeyboard.cpp b/src/utilities/extrakeyboard.cpp new file mode 100644 index 0000000..f7127ab --- /dev/null +++ b/src/utilities/extrakeyboard.cpp @@ -0,0 +1,162 @@ +#include "../config.h" + +#include "extrakeyboard.h" +#include +#include +#include + + +typedef struct +{ + bool pressed; + uint32_t since = 0; +} keyinfo; + + +keyinfo MyKeyMapper[MYKEY_LASTENUM+1]; + + +KeyboardExtra::KeyboardExtra() +{ + uint32_t timer = rtc_ticks(); + now = timer; + for(int i=0; i<=MYKEY_LASTENUM; i++) MyKeyMapper[i] = { .pressed = false, .since = timer }; +} + + +KeyboardExtra::~KeyboardExtra() +{ + +} + + +void KeyboardExtra::Update( [[maybe_unused]] 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 KeyboardExtra::IsKeyPressedEvent( int key ) +{ + return (MyKeyMapper[key].pressed && MyKeyMapper[key].since == now); +} + + +bool KeyboardExtra::IsKeyReleasedEvent( int key ) +{ + return (!MyKeyMapper[key].pressed && MyKeyMapper[key].since == now); +} + + +bool KeyboardExtra::IsKeyPressed( int key ) +{ + return MyKeyMapper[key].pressed; +} + + +bool KeyboardExtra::IsKeyReleased( int key ) +{ + return (!MyKeyMapper[key].pressed); +} + + +uint32_t KeyboardExtra::IsKeyHoldPressed( int key ) +{ + if (MyKeyMapper[key].pressed && MyKeyMapper[key].since < now) + return (uint32_t) (now-MyKeyMapper[key].since); + else return 0; +} + + +uint32_t KeyboardExtra::IsKeyHoldReleased( int key ) +{ + if (!MyKeyMapper[key].pressed && MyKeyMapper[key].since < now) + return (uint32_t) (now-MyKeyMapper[key].since); + else return 0; +} + +uint32_t KeyboardExtra::GetLastTickKeyEvent( int key ) +{ + return (uint32_t) MyKeyMapper[key].since; +} \ No newline at end of file diff --git a/src/utilities/extrakeyboard.h b/src/utilities/extrakeyboard.h new file mode 100644 index 0000000..151d1d1 --- /dev/null +++ b/src/utilities/extrakeyboard.h @@ -0,0 +1,94 @@ +#ifndef EXTRAKEYBOARD_H +#define EXTRAKEYBOARD_H + +#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, +}; + + + +class KeyboardExtra +{ + public: + KeyboardExtra(); + ~KeyboardExtra(); + + void Update( float dt ); + bool IsKeyPressedEvent( int key ); + bool IsKeyReleasedEvent( int key ); + bool IsKeyPressed( int key ); + bool IsKeyReleased( int key ); + uint32_t IsKeyHoldPressed( int key ); + uint32_t IsKeyHoldReleased( int key ); + uint32_t GetLastTickKeyEvent( int key ); + + private: + uint32_t now; +}; + + +#endif diff --git a/src/utilities/fast_trig.cpp b/src/utilities/fast_trig.cpp new file mode 100644 index 0000000..a744a6a --- /dev/null +++ b/src/utilities/fast_trig.cpp @@ -0,0 +1,183 @@ +#include "fast_trig.h" +#include "num/num.h" + +static libnum::num cosTable[360]; +static libnum::num sinTable[360]; +static bool is_fast_trig_initialised = false; + +void Fast_Trig_Init( void ) +{ + for(int u=0; u<360; u++) + { + cosTable[u] = libnum::num( cos( u * PI / 180 ) ); + sinTable[u] = libnum::num( sin( u * PI / 180 ) ); + } + is_fast_trig_initialised = true; +} + + +libnum::num FastCosInt( int16_t angle ) +{ + if (!is_fast_trig_initialised) Fast_Trig_Init(); + + if (angle>=0 and angle<360) return cosTable[ angle ]; + else + { + int16_t input = angle; + if (input<0) + { + while (input<0) input+=360; + return cosTable[ input ]; + } + else + { + while (input>=360) input-=360; + return cosTable[ input ]; + } + } +} + +libnum::num FastSinInt( int16_t angle ) +{ + if (!is_fast_trig_initialised) Fast_Trig_Init(); + + if (angle>=0 and angle<360) return sinTable[ angle ]; + else + { + int16_t input = angle; + if (input<0) + { + while (input<0) input+=360; + return sinTable[ input ]; + } + else + { + while (input>=360) input-=360; + return sinTable[ input ]; + } + } +} + +libnum::num FastTanInt( int16_t angle ) +{ + if (!is_fast_trig_initialised) Fast_Trig_Init(); + + int16_t input = angle; + + if (input<0) + { + while (input<0) input+=360; + } + else if (input>=360) + { + while (input>=360) input-=360; + } + + libnum::num value; + + if (input==90) + { + value.v = INT32_MAX; + return value; + } + else if (input==270) + { + value.v = INT32_MIN; + return value; + } + else + { + value = FastSinInt(input) / FastCosInt(input); + return value; + } +} + + + +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; +} + +/* TO DO : rework these functions for sine and cosine calculation */ + +libnum::num32 cos_num32(libnum::num32 angle) { + // Taylor serie for cos(x) = 1 - x²/2! + x⁴/4! + x⁶/6! + x⁸/8! + ... + + // Cosine function is even + if (angle < libnum::num32(0)) + return cos_num32(-angle); + + // Look for an angle in the range [0, 2*pi [ + libnum::num32 anglereduced = angle; + while (anglereduced >= libnum::num32(2 * PI)) + anglereduced -= libnum::num32(2 * PI); + + // Exploit the symetry for angle and angle+Pi to reduce the order of the + // limited developpement + if (anglereduced >= libnum::num(PI)) + return -cos_num32(anglereduced - libnum::num(PI)); + + libnum::num32 sum = libnum::num32(1); + libnum::num32 angle2 = anglereduced * anglereduced; + + // set first value of the Taylor serie : x⁰/0! = 1/1 + libnum::num32 numerator = libnum::num32(1); + libnum::num32 denominator = libnum::num32(1); + + for (int i = 2; i <= 8; i += 2) { + numerator *= (-angle2); + denominator *= libnum::num32(i - 1) * libnum::num32(i); + sum += (numerator / denominator); + } + + return sum; +} + +libnum::num32 sin_num32(libnum::num32 angle) { + // Taylor serie for cos(x) = x/1! - x³/3! + x⁵/5! - x⁷/7! + x⁹/9! + ... + + // Sine function is odd + if (angle < libnum::num32(0)) + return -sin_num32(-angle); + + // Look for an angle in the range [0, 2*pi [ + libnum::num32 anglereduced = angle; + while (anglereduced >= libnum::num32(2 * PI)) + anglereduced -= libnum::num32(2 * PI); + + // Exploit the symetry for angle and angle+Pi to reduce the order of the + // limited developpement + if (anglereduced >= libnum::num(PI)) + return -sin_num32(anglereduced - libnum::num(PI)); + + libnum::num32 sum = anglereduced; + libnum::num32 angle2 = anglereduced * anglereduced; + + // set first value of the Taylor serie : x¹/1! = x/1 + libnum::num32 numerator = anglereduced; + libnum::num32 denominator = libnum::num32(1); + + for (int i = 2; i <= 8; i += 2) { + numerator *= (-angle2); + denominator *= libnum::num32(i) * libnum::num32(i + 1); + sum += (numerator / denominator); + } + + return sum; +} diff --git a/src/utilities/fast_trig.h b/src/utilities/fast_trig.h new file mode 100644 index 0000000..30d0648 --- /dev/null +++ b/src/utilities/fast_trig.h @@ -0,0 +1,22 @@ +#ifndef FAST_TRIG_H +#define FAST_TRIG_H + + +#include +#include + +#define PI 3.14159265 + +void Fast_Trig_Init( void ); + +libnum::num FastCosInt( int16_t angle ); +libnum::num FastSinInt( int16_t angle ); +libnum::num FastTanInt( int16_t angle ); + +libnum::num32 sqrt_num32(libnum::num32 v); +libnum::num32 cos_num32(libnum::num32 angle); +libnum::num32 sin_num32(libnum::num32 angle); + + + +#endif diff --git a/src/utilities/utilities.cpp b/src/utilities/utilities.cpp new file mode 100644 index 0000000..8079f8b --- /dev/null +++ b/src/utilities/utilities.cpp @@ -0,0 +1,17 @@ +#include "../config.h" + +#include +#include + +#include "utilities.h" + +#include +#include +#include +#include +#include +#include "vector2D.h" +#include + +#include + diff --git a/src/utilities/utilities.h b/src/utilities/utilities.h new file mode 100644 index 0000000..90f2411 --- /dev/null +++ b/src/utilities/utilities.h @@ -0,0 +1,15 @@ +#ifndef UTILITIES_H +#define UTILITIES_H + + +#include +#include "vector2D.h" + + +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#define FLOOR(a) ((a) < 0 ? (int)((a)-1.0) : (int)(a)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + + +#endif \ No newline at end of file diff --git a/src/utilities/vector2D.cpp b/src/utilities/vector2D.cpp new file mode 100644 index 0000000..8b43540 --- /dev/null +++ b/src/utilities/vector2D.cpp @@ -0,0 +1,111 @@ +#include "vector2D.h" +#include "fast_trig.h" + +Vector2D::Vector2D() { + this->x = libnum::num32(0); + this->y = libnum::num32(0); + } + + Vector2D::Vector2D(float x, float y) { + this->x = libnum::num32(x); + this->y = libnum::num32(y); + } + + Vector2D::Vector2D(libnum::num32 x, libnum::num32 y) { + this->x = x; + this->y = y; + } + + Vector2D::Vector2D(const Vector2D &v) { + this->x = v.x; + this->y = v.y; + } + + Vector2D::~Vector2D() {} + + void Vector2D::Set(Vector2D v) { + this->x = v.x; + this->y = v.y; + } + + void Vector2D::Normalise(void) { + libnum::num32 len = this->Length(); + this->x /= len; + this->y /= len; + } + + Vector2D Vector2D::Clone(void) { + Vector2D NewVector(this->x, this->y); + return NewVector; + } + + Vector2D Vector2D::MakeVector(Vector2D A, Vector2D B) { + Vector2D NewVector(B.x - A.x, B.y - A.y); + return NewVector; + } + + void Vector2D::AddVectors(Vector2D a, Vector2D b) { + this->x = a.x + b.x; + this->y = a.y + b.y; + } + + void Vector2D::Add(Vector2D v, libnum::num32 scale) { + this->x += v.x * scale; + this->y += v.y * scale; + } + + void Vector2D::SubtractVectors(Vector2D a, Vector2D b) { + this->x = a.x - b.x; + this->y = a.y - b.y; + } + + void Vector2D::Subtract(Vector2D v, libnum::num32 scale) { + this->x -= v.x * scale; + this->y -= v.y * scale; + } + + libnum::num32 Vector2D::Length(void) { + return sqrt_num32(this->x * this->x + this->y * this->y); + } + + void Vector2D::Scale(libnum::num32 scale) { + this->x *= scale; + this->y *= scale; + } + + libnum::num32 Vector2D::Dot(Vector2D v) { return (this->x * v.x + this->y * v.y); } + + libnum::num32 Vector2D::Det(Vector2D v) { return (this->x * v.y - this->y * v.x); } + + Vector2D Vector2D::PerpCW(void) { + Vector2D temp(-this->y, this->x); + return temp; + } + + Vector2D Vector2D::PerpCCW(void) { + Vector2D temp(this->y, -this->x); + return temp; + } + + + +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; +} \ No newline at end of file diff --git a/src/utilities/vector2D.h b/src/utilities/vector2D.h new file mode 100644 index 0000000..a58d20d --- /dev/null +++ b/src/utilities/vector2D.h @@ -0,0 +1,112 @@ +#ifndef VECTOR2D_H +#define VECTOR2D_H + +#include +#include +#include "fast_trig.h" + + +class Vector2D { +public: + Vector2D(); + Vector2D(float x, float y); + Vector2D(libnum::num32 x, libnum::num32 y); + Vector2D(const Vector2D &v); + ~Vector2D(); + + void Set(Vector2D v); + + void Normalise(void); + + Vector2D Clone(void); + Vector2D MakeVector(Vector2D A, Vector2D B); + + void AddVectors(Vector2D a, Vector2D b); + void Add(Vector2D v, libnum::num32 scale); + void SubtractVectors(Vector2D a, Vector2D b); + void Subtract(Vector2D v, libnum::num32 scale); + + libnum::num32 Length(void); + void Scale(libnum::num32 scale); + + libnum::num32 Dot(Vector2D v); + libnum::num32 Det(Vector2D v); + + Vector2D PerpCW(void); + Vector2D PerpCCW(void); + + /* 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); + + +#endif \ No newline at end of file