initial commit

This commit is contained in:
Sylvain PILLOT 2023-11-07 21:45:39 +01:00
commit db40e67894
37 changed files with 1537 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@ -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

44
CMakeLists.txt Normal file
View File

@ -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()

0
README.md Normal file
View File

BIN
assets-cg/Selection.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
assets-cg/SlyVTT.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
assets-cg/bglens.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

BIN
assets-cg/bglens2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
assets-cg/bglens3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

BIN
assets-cg/bglens4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

3
assets-cg/createfont.py Normal file
View File

@ -0,0 +1,3 @@
from make_grid import *
make_grid(5, 5)

BIN
assets-cg/eye.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
assets-cg/fontFantasy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
assets-cg/fontmatrix.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -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

80
assets-cg/gff Normal file
View File

@ -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: " + \
"<font path> <font size> <output image> " + \
"[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)

BIN
assets-cg/icon-sel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
assets-cg/icon-uns.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

28
assets-cg/make_grid.py Normal file
View File

@ -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")

BIN
assets-cg/matrix.ttf Normal file

Binary file not shown.

1
build Executable file
View File

@ -0,0 +1 @@
fxsdk build-cg VERBOSE=1

1
capture Executable file
View File

@ -0,0 +1 @@
fxlink -iw

2
clean Executable file
View File

@ -0,0 +1,2 @@
rm -r build-cg/
rm *.g3a

3
rebuild Executable file
View File

@ -0,0 +1,3 @@
rm -r build-cg
rm *.g3a
fxsdk build-cg VERBOSE=1

1
send Executable file
View File

@ -0,0 +1 @@
fxlink -sw *.g3a

10
src/config.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef CONFIG_H
#define CONFIG_H
#define MAXHEIGHT 224
#define MORE_RAM 1
#endif

26
src/effects/effects.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef EFFECTS_H
#define EFFECTS_H
#include "../config.h"
#include <gint/display.h>
#include <gint/image.h>
/* 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

165
src/effects/morph.cpp Normal file
View File

@ -0,0 +1,165 @@
#include "effects.h"
#include <num/num.h>
#include "../utilities/fast_trig.h"
#include <cstring>
/********************************\
* 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 )
{
}

86
src/effects/plasma.cpp Normal file
View File

@ -0,0 +1,86 @@
#include "effects.h"
#include <cstring>
#include <cmath>
/********************************\
* 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 )
{
}

313
src/main.cpp Normal file
View File

@ -0,0 +1,313 @@
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/dma.h>
#include <gint/rtc.h>
#include <gint/clock.h>
#include <fxlibc/printf.h>
#include "config.h"
#include <libprof.h>
#include <gint/kmalloc.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#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;
}

View File

@ -0,0 +1,162 @@
#include "../config.h"
#include "extrakeyboard.h"
#include <gint/keyboard.h>
#include <gint/rtc.h>
#include <cstdint>
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;
}

View File

@ -0,0 +1,94 @@
#ifndef EXTRAKEYBOARD_H
#define EXTRAKEYBOARD_H
#include <cstdint>
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

183
src/utilities/fast_trig.cpp Normal file
View File

@ -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;
}

22
src/utilities/fast_trig.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef FAST_TRIG_H
#define FAST_TRIG_H
#include <cmath>
#include <num/num.h>
#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

View File

@ -0,0 +1,17 @@
#include "../config.h"
#include <azur/azur.h>
#include <azur/gint/render.h>
#include "utilities.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fxlibc/printf.h>
#include <sys/types.h>
#include "vector2D.h"
#include <num/num.h>
#include <algorithm>

15
src/utilities/utilities.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef UTILITIES_H
#define UTILITIES_H
#include <cstdint>
#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

111
src/utilities/vector2D.cpp Normal file
View File

@ -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;
}

112
src/utilities/vector2D.h Normal file
View File

@ -0,0 +1,112 @@
#ifndef VECTOR2D_H
#define VECTOR2D_H
#include <num/num.h>
#include <stdint.h>
#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