diff --git a/README.md b/README.md deleted file mode 100644 index 33bb998..0000000 --- a/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# ODE Physics Engine Integration - -## ✅ ODE Integration Complete - -Full Open Dynamics Engine (ODE) support has been integrated into suicmez for 3D physics simulation, perfect for voxel games! - -## Available ODE Functions - -### Initialization and Cleanup -- `ode_init()` - Initialize the ODE library -- `ode_close()` - Clean up ODE resources - -### World Management -- `ode_world_create()` - Create a new physics world -- `ode_world_destroy(world)` - Destroy a physics world -- `ode_world_set_gravity(world, x, y, z)` - Set world gravity -- `ode_world_step(world, stepsize)` - Advance physics simulation - -### Rigid Bodies -- `ode_body_create(world)` - Create a new rigid body -- `ode_body_destroy(body)` - Destroy a rigid body -- `ode_body_set_position(body, x, y, z)` - Set body position -- `ode_body_set_linear_vel(body, x, y, z)` - Set linear velocity - -### Mass and Geometry -- `ode_body_set_box_mass(body, density, lx, ly, lz)` - Set box-shaped mass -- `ode_create_box_geom(space, lx, ly, lz)` - Create box collision geometry -- `ode_geom_set_body(geom, body)` - Attach geometry to body -- `ode_geom_destroy(geom)` - Destroy geometry - -### Collision Spaces -- `ode_simple_space_create(parent)` - Create collision space -- `ode_space_destroy(space)` - Destroy collision space - -## Example Usage - -```sui -# Initialize physics -ode_init() - -# Create world with gravity -let world = ode_world_create() -let space = ode_simple_space_create(0 as *()) # null parent -ode_world_set_gravity(world, 0.0, -9.81, 0.0) - -# Create a falling voxel/box -let body = ode_body_create(world) -ode_body_set_box_mass(body, 1.0, 1.0, 1.0, 1.0) # 1x1x1 meter box -ode_body_set_position(body, 0.0, 5.0, 0.0) # Start 5 units up - -let geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) -ode_geom_set_body(geom, body) - -# Simulate physics -let mut i = 0 -while i < 100 do - ode_world_step(world, 0.016) # 60 FPS - i = i + 1 -end - -# Cleanup -ode_geom_destroy(geom) -ode_body_destroy(body) -ode_space_destroy(space) -ode_world_destroy(world) -ode_close() -``` - -## Compilation - -Use the updated compile scripts which now include ODE: - -```bash -./compile.sh tests/your_ode_program.sui -./compile_and_run.sh tests/your_ode_program.sui -``` - -## ODE Version - -Currently using: **ODE 0.16.6** - -- Real-time rigid body dynamics -- Collision detection -- Joint constraints -- Stable simulation for games - -All ODE features are now available through suicmez for building physics-based voxel games! -ODE_INTEGRATION.md \ No newline at end of file diff --git a/compile.sh b/compile.sh index 17832da..692994e 100755 --- a/compile.sh +++ b/compile.sh @@ -1,17 +1,27 @@ #!/bin/bash # Simple helper script to compile Sui code and link with libsuicmez +DEBUG_FLAG="" +if [ "$1" = "--debug" ]; then + DEBUG_FLAG="--debug" + shift +fi + if [ $# -eq 0 ]; then - echo "Usage: ./compile.sh [output_name]" + echo "Usage: ./compile.sh [--debug] [output_name]" echo "" - echo "Example:" + echo "Options:" + echo " --debug Generate debug printf statements in the C output" + echo "" + echo "Examples:" echo " ./compile.sh tests/structs.sui" + echo " ./compile.sh --debug tests/structs.sui" echo " ./compile.sh tests/structs.sui my_program" exit 1 fi INPUT_SUI="$1" -OUTPUT_NAME="${2:-${INPUT_NAME%.sui}}" +OUTPUT_NAME="${2:-${INPUT_SUI%.sui}}" if [ ! -f "$INPUT_SUI" ]; then echo "Error: File not found: $INPUT_SUI" @@ -20,7 +30,11 @@ fi # Compile Sui to C echo "Compiling $INPUT_SUI to C..." -cargo run "$INPUT_SUI" || exit 1 +if [ -n "$DEBUG_FLAG" ]; then + cargo run -- "$DEBUG_FLAG" "$INPUT_SUI" || exit 1 +else + cargo run -- "$INPUT_SUI" || exit 1 +fi # Get the C file name (should be next to the .sui file) C_FILE="${INPUT_SUI%.sui}.c" @@ -45,7 +59,7 @@ ODE_LIBS=$(pkg-config --libs ode 2>/dev/null || echo "-lode -lm") # Compile C to executable with raylib and ODE support echo "Compiling C code and linking with libsuicmez, raylib, and ODE..." -gcc "$C_FILE" libsuicmez/libsuicmez.c $RAYLIB_CFLAGS $RAYLIB_LIBS $ODE_CFLAGS $ODE_LIBS -o "$OUTPUT_BINARY" || exit 1 +gcc "$C_FILE" libsuicmez/libsuicmez.c libsuicmez/suicmez_gc.c $RAYLIB_CFLAGS $RAYLIB_LIBS $ODE_CFLAGS $ODE_LIBS -lm -o "$OUTPUT_BINARY" || exit 1 echo "✓ Successfully created: $OUTPUT_BINARY" echo " Run with: ./$OUTPUT_BINARY" diff --git a/compile_and_run.sh b/compile_and_run.sh index 008b47d..478cdc0 100755 --- a/compile_and_run.sh +++ b/compile_and_run.sh @@ -1,11 +1,21 @@ #!/bin/bash # Compile Sui source to C, then compile and run the executable +DEBUG_FLAG="" +if [ "$1" = "--debug" ]; then + DEBUG_FLAG="--debug" + shift +fi + if [ $# -eq 0 ]; then - echo "Usage: ./compile_and_run.sh [program_args...]" + echo "Usage: ./compile_and_run.sh [--debug] [program_args...]" + echo "" + echo "Options:" + echo " --debug Generate debug printf statements in the C output" echo "" echo "Examples:" echo " ./compile_and_run.sh tests/structs.sui" + echo " ./compile_and_run.sh --debug tests/structs.sui" echo " ./compile_and_run.sh tests/myprogram.sui arg1 arg2" exit 1 fi @@ -28,7 +38,13 @@ echo "━━━━━━━━━━━━━━━━━━━━━━━━ echo "Step 1: Compiling Sui to C..." echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -if ! cargo run "$INPUT_SUI" > /dev/null 2>&1; then +if [ -n "$DEBUG_FLAG" ]; then + CARGO_CMD="cargo run -- \"$DEBUG_FLAG\" \"$INPUT_SUI\"" +else + CARGO_CMD="cargo run -- \"$INPUT_SUI\"" +fi + +if ! eval "$CARGO_CMD" > /dev/null 2>&1; then echo "" echo "✗ Sui compilation failed" exit 1 @@ -54,7 +70,7 @@ RAYLIB_LIBS=$(pkg-config --libs raylib 2>/dev/null || echo "-lraylib -lm") ODE_CFLAGS=$(pkg-config --cflags ode 2>/dev/null || echo "-I/usr/include") ODE_LIBS=$(pkg-config --libs ode 2>/dev/null || echo "-lode -lm") -if ! gcc "$C_FILE" libsuicmez/libsuicmez.c $RAYLIB_CFLAGS $RAYLIB_LIBS $ODE_CFLAGS $ODE_LIBS -o "$OUTPUT_BINARY" 2>&1; then +if ! gcc "$C_FILE" libsuicmez/libsuicmez.c libsuicmez/suicmez_gc.c $RAYLIB_CFLAGS $RAYLIB_LIBS $ODE_CFLAGS $ODE_LIBS -lm -o "$OUTPUT_BINARY" 2>&1; then echo "" echo "✗ C compilation failed" exit 1 diff --git a/fishsoup/main b/fishsoup/main new file mode 100755 index 0000000..2a5d721 Binary files /dev/null and b/fishsoup/main differ diff --git a/fishsoup/main.c b/fishsoup/main.c new file mode 100644 index 0000000..1554fe1 --- /dev/null +++ b/fishsoup/main.c @@ -0,0 +1,141 @@ +#include "../libsuicmez/libsuicmez.h" +#include +#include +#include +#include + +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); + +// Helper for allocating arrays +static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) { + void* ptr = gc_alloc(type, elem_size * len); + if (init_data) memcpy(ptr, init_data, elem_size * len); + return ptr; +} + +// Helper for allocating structs +static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) { + void* ptr = gc_alloc(type, size); + if (init_data) memcpy(ptr, init_data, size); + return ptr; +} + + +struct Vec2 { + float x; + float y; +}; + +static const uint8_t sui_bitmap_Vec2[] = { 0, 0 }; +static const TypeInfo sui_typeinfo_Vec2 = { + .field_count = 2, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Vec2 +}; + +int suic_main(void); + + +int suic_main(void) { + suic_init_window(800, 600, suic_alloc_array(NULL, sizeof(char), 31, "Fishsoup - Basic 3D Platformer")); + suic_set_target_fps(60); + suic_ode_init(); + void* world = suic_ode_world_create(); + void* null_space = (struct unit**) 0; + void* space = suic_ode_simple_space_create(null_space); + suic_ode_world_set_gravity(world, 0.000000, -9.810000, 0.000000); + void* contactgroup = suic_ode_joint_group_create(0); + void* player_body = suic_ode_body_create(world); + suic_ode_body_set_box_mass(player_body, 1.000000, 1.000000, 1.000000, 1.000000); + suic_ode_body_set_position(player_body, 0.000000, 1.000000, 0.000000); + void* player_geom = suic_ode_create_box_geom(space, 1.000000, 1.000000, 1.000000); + suic_ode_geom_set_body(player_geom, player_body); + void* ground_geom = suic_ode_create_plane_geom(space, 0.000000, 1.000000, 0.000000, 0.500000); + suic_ode_body_set_linear_vel(player_body, 0.000000, 0.000000, 0.000000); + float player_x = 0.000000; + float player_y = 0.000000; + float player_z = 0.000000; + float player_angle = 0.000000; + float camera_distance = 5.000000; + float camera_height = 2.000000; + float mouse_x = 0.000000; + float mouse_y = 0.000000; + float last_mouse_x = 0.000000; + float last_mouse_y = 0.000000; + float vel_x = 0.000000; + float vel_y = 0.000000; + float vel_z = 0.000000; + while ((suic_window_should_close() == false)) { + mouse_x = suic_get_mouse_x(); + mouse_y = suic_get_mouse_y(); + float mouse_delta_x = (mouse_x - last_mouse_x); + float mouse_delta_y = (mouse_y - last_mouse_y); + last_mouse_x = mouse_x; + last_mouse_y = mouse_y; + float mouse_sensitivity = 0.005000; + player_angle = (player_angle - (mouse_delta_x * mouse_sensitivity)); + suic_ode_space_collide(world, space, contactgroup); + suic_ode_world_step(world, (1.000000 / 60.000000)); + suic_ode_joint_group_empty(contactgroup); + suic_ode_body_get_linear_vel(player_body, &vel_x, &vel_y, &vel_z); + float move_speed = 5.000000; + bool w_pressed = suic_is_key_down(87); + bool s_pressed = suic_is_key_down(83); + bool a_pressed = suic_is_key_down(65); + bool d_pressed = suic_is_key_down(68); + if (w_pressed) { + vel_x = (sin(player_angle) * move_speed); + vel_z = (cos(player_angle) * move_speed); + suic_ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z); + } + if (s_pressed) { + vel_x = (-sin(player_angle) * move_speed); + vel_z = (-cos(player_angle) * move_speed); + suic_ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z); + } + if (a_pressed) { + vel_x = (sin((player_angle + (3.141590 / 2.000000))) * move_speed); + vel_z = (cos((player_angle + (3.141590 / 2.000000))) * move_speed); + suic_ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z); + } + if (d_pressed) { + vel_x = (sin((player_angle - (3.141590 / 2.000000))) * move_speed); + vel_z = (cos((player_angle - (3.141590 / 2.000000))) * move_speed); + suic_ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z); + } + suic_ode_body_get_position(player_body, &player_x, &player_y, &player_z); + float camera_x = (player_x - (sin(player_angle) * camera_distance)); + float camera_y = (player_y + camera_height); + float camera_z = (player_z - (cos(player_angle) * camera_distance)); + suic_begin_drawing(); + suic_clear_background(135, 206, 235, 255); + suic_begin_mode3d(camera_x, camera_y, camera_z, player_x, player_y, player_z, 0.000000, 1.000000, 0.000000, 45.000000, 0); + suic_draw_cube(0.000000, -0.500000, 0.000000, 20.000000, 1.000000, 20.000000, 34, 139, 34, 255); + suic_draw_cube(player_x, player_y, player_z, 1.000000, 1.000000, 1.000000, 0, 255, 0, 255); + suic_end_mode3d(); + suic_end_drawing(); + } + suic_ode_geom_destroy(ground_geom); + suic_ode_geom_destroy(player_geom); + suic_ode_body_destroy(player_body); + suic_ode_joint_group_destroy(contactgroup); + suic_ode_space_destroy(space); + suic_ode_world_destroy(world); + suic_ode_close(); + suic_close_window(); + return 0; +} + +int main(int argc, char* argv[]) { + // Initialize GC + gc_init(); + // init globals + // init event loop + int result = suic_main(); + // Shutdown GC + gc_shutdown(); + return result; +} + diff --git a/fishsoup/main.o b/fishsoup/main.o new file mode 100755 index 0000000..1e14c56 Binary files /dev/null and b/fishsoup/main.o differ diff --git a/fishsoup/main.sui b/fishsoup/main.sui new file mode 100644 index 0000000..b31b2c6 --- /dev/null +++ b/fishsoup/main.sui @@ -0,0 +1,158 @@ +# Basic 3D Platformer - Fishsoup +# Mouse for rotation, WASD for movement + +struct Vec2 + x: float, + y: float, +end + +fn main() -> int do + # Initialize raylib + init_window(800, 600, "Fishsoup - Basic 3D Platformer") + defer close_window() + set_target_fps(60) + + # Initialize ODE + ode_init() + defer ode_close() + + # Create physics world + let world = ode_world_create() + defer ode_world_destroy(world) + let null_space = 0 as *() + let space = ode_simple_space_create(null_space) + defer ode_space_destroy(space) + + # Set gravity + ode_world_set_gravity(world, 0.0, -9.81, 0.0) + + # Create contact joint group + let contactgroup = ode_joint_group_create(0) + defer ode_joint_group_destroy(contactgroup) + + # Create player body + let player_body = ode_body_create(world) + defer ode_body_destroy(player_body) + + # Set player mass (cube 1x1x1) + ode_body_set_box_mass(player_body, 1.0, 1.0, 1.0, 1.0) + + # Set initial position + ode_body_set_position(player_body, 0.0, 1.0, 0.0) + + # Create geometry for player + let player_geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) + defer ode_geom_destroy(player_geom) + ode_geom_set_body(player_geom, player_body) + + # Create ground plane (at y = -0.5) + # Plane equation: ax + by + cz + d = 0 + # For y = -0.5: 0*x + 1*y + 0*z + 0.5 = 0 => y = -0.5 + let ground_geom = ode_create_plane_geom(space, 0.0, 1.0, 0.0, 0.5) + defer ode_geom_destroy(ground_geom) + + # Initialize player velocity to allow gravity to work + ode_body_set_linear_vel(player_body, 0.0, 0.0, 0.0) + + # Player variables + let mut player_x = 0.0 + let mut player_y = 0.0 + let mut player_z = 0.0 + let mut player_angle = 0.0 # Yaw + let mut camera_distance = 5.0 + let mut camera_height = 2.0 + let mut mouse_x = 0.0 + let mut mouse_y = 0.0 + let mut last_mouse_x = 0.0 + let mut last_mouse_y = 0.0 + let mut vel_x = 0.0 + let mut vel_y = 0.0 + let mut vel_z = 0.0 + + # Main game loop + while window_should_close() == false do + # Get mouse position for rotation + mouse_x = get_mouse_x() + mouse_y = get_mouse_y() + + # Calculate mouse delta + let mouse_delta_x = mouse_x - last_mouse_x + let mouse_delta_y = mouse_y - last_mouse_y + last_mouse_x = mouse_x + last_mouse_y = mouse_y + + # Update rotation based on mouse movement + let mouse_sensitivity = 0.005 + player_angle = player_angle - mouse_delta_x * mouse_sensitivity + + # Collision detection BEFORE step + ode_space_collide(world, space, contactgroup) + + # Step physics - this applies gravity + ode_world_step(world, 1.0 / 60.0) + ode_joint_group_empty(contactgroup) + + # NOW get the velocity after gravity has been applied + ode_body_get_linear_vel(player_body, &vel_x, &vel_y, &vel_z) + + # Handle input for movement + let move_speed = 5.0 + + # Check if any movement keys are pressed + let w_pressed = is_key_down(87) + let s_pressed = is_key_down(83) + let a_pressed = is_key_down(65) + let d_pressed = is_key_down(68) + + # Only update HORIZONTAL velocity if a key is pressed + # Keep vertical velocity (from gravity) + if w_pressed do + vel_x = sin(player_angle) * move_speed + vel_z = cos(player_angle) * move_speed + ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z) + end + + if s_pressed do + vel_x = -sin(player_angle) * move_speed + vel_z = -cos(player_angle) * move_speed + ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z) + end + + if a_pressed do + vel_x = sin(player_angle + 3.14159 / 2.0) * move_speed + vel_z = cos(player_angle + 3.14159 / 2.0) * move_speed + ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z) + end + + if d_pressed do + vel_x = sin(player_angle - 3.14159 / 2.0) * move_speed + vel_z = cos(player_angle - 3.14159 / 2.0) * move_speed + ode_body_set_linear_vel(player_body, vel_x, vel_y, vel_z) + end + + # Get player position + ode_body_get_position(player_body, &player_x, &player_y, &player_z) + + # Camera position (behind player) + let camera_x = player_x - sin(player_angle) * camera_distance + let camera_y = player_y + camera_height + let camera_z = player_z - cos(player_angle) * camera_distance + + # Drawing + begin_drawing() + clear_background(135, 206, 235, 255) # Sky blue + + begin_mode3d(camera_x, camera_y, camera_z, player_x, player_y, player_z, 0.0, 1.0, 0.0, 45.0, 0) + + # Draw ground + draw_cube(0.0, -0.5, 0.0, 20.0, 1.0, 20.0, 34, 139, 34, 255) # Green ground + + # Draw player + draw_cube(player_x, player_y, player_z, 1.0, 1.0, 1.0, 0, 255, 0, 255) # Green player + + end_mode3d() + end_drawing() + end + + 0 +end \ No newline at end of file diff --git a/fps_game b/fps_game new file mode 100755 index 0000000..59080a9 Binary files /dev/null and b/fps_game differ diff --git a/libsuicmez/libsuicmez.c b/libsuicmez/libsuicmez.c index 46fd414..532b1b0 100644 --- a/libsuicmez/libsuicmez.c +++ b/libsuicmez/libsuicmez.c @@ -1,385 +1,417 @@ -#include "raylib.h" #include "libsuicmez.h" -#include +#include "raylib.h" +#include "rlgl.h" +#include "suicmez_gc.h" #include +#include #include -// Simple garbage collection allocator -// This is a basic implementation that tracks allocations -// For production, consider using a more robust GC library - #define MAX_TRACKED_ALLOCATIONS 10000 typedef struct { - void* ptr; - size_t size; - int in_use; + void *ptr; + size_t size; + int in_use; } AllocationInfo; static AllocationInfo tracked_allocations[MAX_TRACKED_ALLOCATIONS]; static int allocation_count = 0; -static const char* last_error = NULL; +static const char *last_error = NULL; // Simple linear search to find allocation -static int find_allocation(void* ptr) { - for (int i = 0; i < allocation_count; i++) { - if (tracked_allocations[i].ptr == ptr && tracked_allocations[i].in_use) { - return i; - } +static int find_allocation(void *ptr) { + for (int i = 0; i < allocation_count; i++) { + if (tracked_allocations[i].ptr == ptr && tracked_allocations[i].in_use) { + return i; } - return -1; + } + return -1; } // GC-aware allocator -void* gc_suic_alloc(size_t size) { - if (size == 0) { - return NULL; - } - - void* ptr = malloc(size); - if (!ptr) { - last_error = "Memory allocation failed"; - return NULL; - } - - // Track this allocation - if (allocation_count < MAX_TRACKED_ALLOCATIONS) { - tracked_allocations[allocation_count].ptr = ptr; - tracked_allocations[allocation_count].size = size; - tracked_allocations[allocation_count].in_use = 1; - allocation_count++; - } else { - last_error = "Too many tracked allocations"; - free(ptr); - return NULL; - } - - return ptr; +void *gc_suic_alloc(size_t size) { + if (size == 0) { + return NULL; + } + + // Use the real GC allocator (for now without type info) + void *ptr = gc_alloc(NULL, size); + if (!ptr) { + last_error = "GC allocation failed"; + return NULL; + } + + return ptr; } // Free memory (called by gc_suic_free) -void suic_gc_free(void* ptr) { - if (!ptr) return; - - int idx = find_allocation(ptr); - if (idx >= 0) { - tracked_allocations[idx].in_use = 0; - free(ptr); - } +// With GC, we don't actually free - just mark as no longer needed +void suic_gc_free(void *ptr) { + // GC will handle freeing when appropriate + // For now, do nothing + (void)ptr; } // Error handling const char *suic_last_error(void) { - return last_error ? last_error : "No error"; + return last_error ? last_error : "No error"; } -void suic_clear_error(void) { - last_error = NULL; -} +void suic_clear_error(void) { last_error = NULL; } // Logging static suic_log_level current_log_level = SUIC_LOG_ALL; -void suic_set_log_level(suic_log_level level) { - current_log_level = level; -} +void suic_set_log_level(suic_log_level level) { current_log_level = level; } // Window management bool suic_init_window(int width, int height, const char *title) { - InitWindow(width, height, title); - return !WindowShouldClose(); + InitWindow(width, height, title); + return !WindowShouldClose(); } -void suic_close_window(void) { - CloseWindow(); -} +void suic_close_window(void) { CloseWindow(); } -bool suic_window_should_close(void) { - return WindowShouldClose(); -} +bool suic_window_should_close(void) { return WindowShouldClose(); } -void suic_set_target_fps(int fps) { - SetTargetFPS(fps); -} +void suic_set_target_fps(int fps) { SetTargetFPS(fps); } + +void suic_enable_msaa_4x(void) { SetConfigFlags(FLAG_MSAA_4X_HINT); } // Drawing -void suic_begin_drawing(void) { - BeginDrawing(); -} +void suic_begin_drawing(void) { BeginDrawing(); } -void suic_end_drawing(void) { - EndDrawing(); -} +void suic_end_drawing(void) { EndDrawing(); } -void suic_clear_background(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - ClearBackground((Color){r, g, b, a}); +void suic_clear_background(unsigned char r, unsigned char g, unsigned char b, + unsigned char a) { + ClearBackground((Color){r, g, b, a}); } // 3D mode Camera3D suic_to_rl_camera3d(suic_camera3d cam) { - return (Camera3D){ - .position = suic_to_rl_vec3(cam.position), - .target = suic_to_rl_vec3(cam.target), - .up = suic_to_rl_vec3(cam.up), - .fovy = cam.fovy, - .projection = cam.projection - }; + return (Camera3D){.position = suic_to_rl_vec3(cam.position), + .target = suic_to_rl_vec3(cam.target), + .up = suic_to_rl_vec3(cam.up), + .fovy = cam.fovy, + .projection = cam.projection}; } -void suic_begin_mode3d(float pos_x, float pos_y, float pos_z, float target_x, float target_y, float target_z, float up_x, float up_y, float up_z, float fovy, int projection) { - Camera3D camera = { - .position = (Vector3){pos_x, pos_y, pos_z}, - .target = (Vector3){target_x, target_y, target_z}, - .up = (Vector3){up_x, up_y, up_z}, - .fovy = fovy, - .projection = projection - }; - BeginMode3D(camera); +void suic_begin_mode3d(float pos_x, float pos_y, float pos_z, float target_x, + float target_y, float target_z, float up_x, float up_y, + float up_z, float fovy, int projection) { + Camera3D camera = {.position = (Vector3){pos_x, pos_y, pos_z}, + .target = (Vector3){target_x, target_y, target_z}, + .up = (Vector3){up_x, up_y, up_z}, + .fovy = fovy, + .projection = projection}; + BeginMode3D(camera); } -void suic_end_mode3d(void) { - EndMode3D(); -} +void suic_end_mode3d(void) { EndMode3D(); } // 3D Drawing -void suic_draw_cube(float x, float y, float z, float width, float height, float length, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - DrawCube((Vector3){x, y, z}, width, height, length, (Color){r, g, b, a}); +void suic_draw_cube(float x, float y, float z, float width, float height, + float length, unsigned char r, unsigned char g, + unsigned char b, unsigned char a) { + DrawCube((Vector3){x, y, z}, width, height, length, (Color){r, g, b, a}); } -void suic_draw_cube_wires(float x, float y, float z, float width, float height, float length, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - DrawCubeWires((Vector3){x, y, z}, width, height, length, (Color){r, g, b, a}); +void suic_draw_cube_wires(float x, float y, float z, float width, float height, + float length, unsigned char r, unsigned char g, + unsigned char b, unsigned char a) { + DrawCubeWires((Vector3){x, y, z}, width, height, length, (Color){r, g, b, a}); } -// Input -bool suic_is_key_down(int key) { - return IsKeyDown(key); -} +// Input - Keyboard +bool suic_is_key_down(int key) { return IsKeyDown(key); } -bool suic_is_mouse_button_down(int b) { - return IsMouseButtonDown(b); -} +bool suic_is_key_pressed(int key) { return IsKeyPressed(key); } + +bool suic_is_key_released(int key) { return IsKeyReleased(key); } + +// Input - Mouse +bool suic_is_mouse_button_down(int b) { return IsMouseButtonDown(b); } + +bool suic_is_mouse_button_pressed(int b) { return IsMouseButtonPressed(b); } + +bool suic_is_mouse_button_released(int b) { return IsMouseButtonReleased(b); } suic_vec2 suic_get_mouse_position(void) { - Vector2 pos = GetMousePosition(); - return (suic_vec2){pos.x, pos.y}; + Vector2 pos = GetMousePosition(); + return (suic_vec2){pos.x, pos.y}; +} + +suic_vec2 suic_get_mouse_delta(void) { + Vector2 delta = GetMouseDelta(); + return (suic_vec2){delta.x, delta.y}; +} + +float suic_get_mouse_x(void) { return GetMousePosition().x; } + +float suic_get_mouse_y(void) { return GetMousePosition().y; } + +float suic_get_mouse_delta_x(void) { return GetMouseDelta().x; } + +float suic_get_mouse_delta_y(void) { return GetMouseDelta().y; } + +// Input - Helper functions for gamedev +int suic_is_movement_input(void) { + // Returns bitmask: 1=W (forward), 2=A (left), 4=S (backward), 8=D (right) + int result = 0; + if (IsKeyDown(KEY_W)) + result |= 1; + if (IsKeyDown(KEY_A)) + result |= 2; + if (IsKeyDown(KEY_S)) + result |= 4; + if (IsKeyDown(KEY_D)) + result |= 8; + return result; +} + +int suic_is_sprint_held(void) { return IsKeyDown(KEY_LEFT_SHIFT) ? 1 : 0; } + +int suic_is_jump_pressed(void) { return IsKeyPressed(KEY_SPACE) ? 1 : 0; } + +// ============================================================================ +// CURSOR MANAGEMENT +// ============================================================================ + +void suic_disable_cursor(void) { DisableCursor(); } + +void suic_enable_cursor(void) { EnableCursor(); } + +bool suic_is_cursor_hidden(void) { return IsCursorHidden(); } + +// ============================================================================ +// MATRIX OPERATIONS FOR 3D TRANSFORMATIONS +// ============================================================================ + +void suic_rl_push_matrix(void) { rlPushMatrix(); } + +void suic_rl_pop_matrix(void) { rlPopMatrix(); } + +void suic_rl_translate_f(float x, float y, float z) { rlTranslatef(x, y, z); } + +void suic_rl_rotate_f(float angle, float x, float y, float z) { + rlRotatef(angle, x, y, z); } // Image and Texture suic_image_handle suic_image_load(const char *path) { - Image img = LoadImage(path); - return (suic_image_handle){img, (img.data != NULL) ? true : false}; + Image img = LoadImage(path); + return (suic_image_handle){img, (img.data != NULL) ? true : false}; } void suic_image_free(suic_image_handle *img) { - if (img && img->valid) { - UnloadImage(img->value); - img->valid = false; - } + if (img && img->valid) { + UnloadImage(img->value); + img->valid = false; + } } suic_texture_handle suic_texture_load(const char *path) { - Texture2D tex = LoadTexture(path); - return (suic_texture_handle){tex, (tex.id != 0) ? true : false}; + Texture2D tex = LoadTexture(path); + return (suic_texture_handle){tex, (tex.id != 0) ? true : false}; } suic_texture_handle suic_texture_from_image(suic_image_handle img) { - if (!img.valid) { - return (suic_texture_handle){0, false}; - } - Texture2D tex = LoadTextureFromImage(img.value); - return (suic_texture_handle){tex, (tex.id != 0) ? true : false}; + if (!img.valid) { + return (suic_texture_handle){0, false}; + } + Texture2D tex = LoadTextureFromImage(img.value); + return (suic_texture_handle){tex, (tex.id != 0) ? true : false}; } void suic_texture_free(suic_texture_handle *tex) { - if (tex && tex->valid) { - UnloadTexture(tex->value); - tex->valid = false; - } + if (tex && tex->valid) { + UnloadTexture(tex->value); + tex->valid = false; + } } void suic_draw_texture(suic_texture_handle tex, int x, int y, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - if (tex.valid) { - DrawTexture(tex.value, x, y, (Color){r, g, b, a}); - } + if (tex.valid) { + DrawTexture(tex.value, x, y, (Color){r, g, b, a}); + } } // Audio bool suic_audio_init(void) { - InitAudioDevice(); - return IsAudioDeviceReady(); + InitAudioDevice(); + return IsAudioDeviceReady(); } -void suic_audio_close(void) { - CloseAudioDevice(); -} +void suic_audio_close(void) { CloseAudioDevice(); } suic_sound_handle suic_sound_load(const char *path) { - Sound snd = LoadSound(path); - return (suic_sound_handle){snd, (snd.frameCount > 0) ? true : false}; + Sound snd = LoadSound(path); + return (suic_sound_handle){snd, (snd.frameCount > 0) ? true : false}; } void suic_sound_play(suic_sound_handle snd) { - if (snd.valid) { - PlaySound(snd.value); - } + if (snd.valid) { + PlaySound(snd.value); + } } void suic_sound_set_volume(suic_sound_handle snd, float volume) { - if (snd.valid) { - SetSoundVolume(snd.value, volume); - } + if (snd.valid) { + SetSoundVolume(snd.value, volume); + } } void suic_sound_free(suic_sound_handle *snd) { - if (snd && snd->valid) { - UnloadSound(snd->value); - snd->valid = false; - } + if (snd && snd->valid) { + UnloadSound(snd->value); + snd->valid = false; + } } // Raycasting suic_ray suic_get_mouse_ray(suic_vec2 mouse, suic_camera3d cam) { - Ray r = GetMouseRay( - (Vector2){mouse.x, mouse.y}, - suic_to_rl_camera3d(cam) - ); - return (suic_ray){ - .origin = (suic_vec3){r.position.x, r.position.y, r.position.z}, - .direction = (suic_vec3){r.direction.x, r.direction.y, r.direction.z} - }; + Ray r = GetMouseRay((Vector2){mouse.x, mouse.y}, suic_to_rl_camera3d(cam)); + return (suic_ray){ + .origin = (suic_vec3){r.position.x, r.position.y, r.position.z}, + .direction = (suic_vec3){r.direction.x, r.direction.y, r.direction.z}}; } suic_rayhit suic_raycast_aabb(suic_ray ray, suic_aabb box) { - Ray r = (Ray){ - .position = (Vector3){ray.origin.x, ray.origin.y, ray.origin.z}, - .direction = (Vector3){ray.direction.x, ray.direction.y, ray.direction.z} - }; - - BoundingBox bbox = (BoundingBox){ - .min = (Vector3){box.min.x, box.min.y, box.min.z}, - .max = (Vector3){box.max.x, box.max.y, box.max.z} - }; - - RayCollision collision = GetRayCollisionBox(r, bbox); - - return (suic_rayhit){ - .hit = collision.hit, - .distance = collision.distance, - .point = (suic_vec3){collision.point.x, collision.point.y, collision.point.z}, - .normal = (suic_vec3){collision.normal.x, collision.normal.y, collision.normal.z} - }; + Ray r = (Ray){.position = (Vector3){ray.origin.x, ray.origin.y, ray.origin.z}, + .direction = (Vector3){ray.direction.x, ray.direction.y, + ray.direction.z}}; + + BoundingBox bbox = + (BoundingBox){.min = (Vector3){box.min.x, box.min.y, box.min.z}, + .max = (Vector3){box.max.x, box.max.y, box.max.z}}; + + RayCollision collision = GetRayCollisionBox(r, bbox); + + return (suic_rayhit){ + .hit = collision.hit, + .distance = collision.distance, + .point = + (suic_vec3){collision.point.x, collision.point.y, collision.point.z}, + .normal = (suic_vec3){collision.normal.x, collision.normal.y, + collision.normal.z}}; } // ODE Physics Engine Implementation static int ode_initialized = 0; void suic_ode_init(void) { - if (!ode_initialized) { - dInitODE(); - ode_initialized = 1; - } + if (!ode_initialized) { + dInitODE(); + ode_initialized = 1; + } } void suic_ode_close(void) { - if (ode_initialized) { - dCloseODE(); - ode_initialized = 0; - } + if (ode_initialized) { + dCloseODE(); + ode_initialized = 0; + } } -suic_ode_world_id suic_ode_world_create(void) { - return dWorldCreate(); -} +suic_ode_world_id suic_ode_world_create(void) { return dWorldCreate(); } void suic_ode_world_destroy(suic_ode_world_id world) { - if (world) { - dWorldDestroy(world); - } + if (world) { + dWorldDestroy(world); + } } -void suic_ode_world_set_gravity(suic_ode_world_id world, dReal x, dReal y, dReal z) { - if (world) { - dWorldSetGravity(world, x, y, z); - } +void suic_ode_world_set_gravity(suic_ode_world_id world, dReal x, dReal y, + dReal z) { + if (world) { + dWorldSetGravity(world, x, y, z); + } } void suic_ode_world_step(suic_ode_world_id world, dReal stepsize) { - if (world) { - dWorldStep(world, stepsize); - } + if (world) { + dWorldStep(world, stepsize); + } } // Body management suic_ode_body_id suic_ode_body_create(suic_ode_world_id world) { - return dBodyCreate(world); + return dBodyCreate(world); } void suic_ode_body_destroy(suic_ode_body_id body) { - if (body) { - dBodyDestroy(body); - } + if (body) { + dBodyDestroy(body); + } } -void suic_ode_body_set_position(suic_ode_body_id body, dReal x, dReal y, dReal z) { - if (body) { - dBodySetPosition(body, x, y, z); - } +void suic_ode_body_set_position(suic_ode_body_id body, dReal x, dReal y, + dReal z) { + if (body) { + dBodySetPosition(body, x, y, z); + } } -void suic_ode_body_set_linear_vel(suic_ode_body_id body, dReal x, dReal y, dReal z) { - if (body) { - dBodySetLinearVel(body, x, y, z); - } +void suic_ode_body_set_linear_vel(suic_ode_body_id body, dReal x, dReal y, + dReal z) { + if (body) { + dBodySetLinearVel(body, x, y, z); + } } -void suic_ode_body_get_position(suic_ode_body_id body, float *x, float *y, float *z) { - if (body) { - const dReal *pos = dBodyGetPosition(body); - *x = (float)pos[0]; - *y = (float)pos[1]; - *z = (float)pos[2]; - } +void suic_ode_body_get_position(suic_ode_body_id body, float *x, float *y, + float *z) { + if (body) { + const dReal *pos = dBodyGetPosition(body); + *x = (float)pos[0]; + *y = (float)pos[1]; + *z = (float)pos[2]; + } } // Mass and geometry -void suic_ode_body_set_box_mass(suic_ode_body_id body, dReal density, dReal lx, dReal ly, dReal lz) { - if (body) { - dMass mass; - dMassSetBox(&mass, density, lx, ly, lz); - dBodySetMass(body, &mass); - } +void suic_ode_body_set_box_mass(suic_ode_body_id body, dReal density, dReal lx, + dReal ly, dReal lz) { + if (body) { + dMass mass; + dMassSetBox(&mass, density, lx, ly, lz); + dBodySetMass(body, &mass); + } } -suic_ode_geom_id suic_ode_create_box_geom(suic_ode_space_id space, dReal lx, dReal ly, dReal lz) { - return dCreateBox(space, lx, ly, lz); +suic_ode_geom_id suic_ode_create_box_geom(suic_ode_space_id space, dReal lx, + dReal ly, dReal lz) { + return dCreateBox(space, lx, ly, lz); } -suic_ode_geom_id suic_ode_create_plane_geom(suic_ode_space_id space, dReal a, dReal b, dReal c, dReal d) { - return dCreatePlane(space, a, b, c, d); +suic_ode_geom_id suic_ode_create_plane_geom(suic_ode_space_id space, dReal a, + dReal b, dReal c, dReal d) { + return dCreatePlane(space, a, b, c, d); } void suic_ode_geom_set_body(suic_ode_geom_id geom, suic_ode_body_id body) { - if (geom) { - dGeomSetBody(geom, body); - } + if (geom) { + dGeomSetBody(geom, body); + } } void suic_ode_geom_destroy(suic_ode_geom_id geom) { - if (geom) { - dGeomDestroy(geom); - } + if (geom) { + dGeomDestroy(geom); + } } // Collision space suic_ode_space_id suic_ode_simple_space_create(suic_ode_space_id parent) { - return dSimpleSpaceCreate(parent); + return dSimpleSpaceCreate(parent); } void suic_ode_space_destroy(suic_ode_space_id space) { - if (space) { - dSpaceDestroy(space); - } + if (space) { + dSpaceDestroy(space); + } } // ============================================================================ @@ -388,230 +420,335 @@ void suic_ode_space_destroy(suic_ode_space_id space) { // Global contact configuration static dReal contact_max_force = 10000.0; -static dReal contact_erp = 0.8; // Error reduction parameter +static dReal contact_erp = 0.8; // Error reduction parameter static dReal contact_cfm = 0.00001; // Constraint force mixing // Store world and contactgroup for collision callback typedef struct { - dWorldID world; - dJointGroupID contactgroup; + dWorldID world; + dJointGroupID contactgroup; } CollisionContext; // Collision callback for detecting contacts between geometries static void near_callback(void *data, dGeomID o1, dGeomID o2) { - CollisionContext *ctx = (CollisionContext*)data; - dBodyID b1 = dGeomGetBody(o1); - dBodyID b2 = dGeomGetBody(o2); - - // Don't process if both bodies are static or same body - if ((b1 && b2 && b1 == b2) || (!b1 && !b2)) { - return; - } - - const int N = 4; // Max contacts per collision - dContact contact[N]; - - // Check for collisions - int n = dCollide(o1, o2, N, &contact[0].geom, sizeof(dContact)); - if (n > 0) { - for (int i = 0; i < n; i++) { - // Set contact properties - contact[i].surface.mu = 0.5; // Friction coefficient - contact[i].surface.mu2 = 0.5; - contact[i].surface.bounce = 0.1; // Bounciness - contact[i].surface.bounce_vel = 0.1; - contact[i].surface.mode = dContactBounce | dContactSoftERP | dContactSoftCFM; - contact[i].surface.soft_erp = contact_erp; - contact[i].surface.soft_cfm = contact_cfm; - - // Create contact joint - dJointID c = dJointCreateContact(ctx->world, ctx->contactgroup, &contact[i]); - dJointAttach(c, b1, b2); - } + CollisionContext *ctx = (CollisionContext *)data; + dBodyID b1 = dGeomGetBody(o1); + dBodyID b2 = dGeomGetBody(o2); + + // Don't process if both bodies are static or same body + if ((b1 && b2 && b1 == b2) || (!b1 && !b2)) { + return; + } + + const int N = 4; // Max contacts per collision + dContact contact[N]; + + // Check for collisions + int n = dCollide(o1, o2, N, &contact[0].geom, sizeof(dContact)); + if (n > 0) { + for (int i = 0; i < n; i++) { + // Set contact properties + contact[i].surface.mu = 0.5; // Friction coefficient + contact[i].surface.mu2 = 0.5; + contact[i].surface.bounce = 0.1; // Bounciness + contact[i].surface.bounce_vel = 0.1; + contact[i].surface.mode = + dContactBounce | dContactSoftERP | dContactSoftCFM; + contact[i].surface.soft_erp = contact_erp; + contact[i].surface.soft_cfm = contact_cfm; + + // Create contact joint + dJointID c = + dJointCreateContact(ctx->world, ctx->contactgroup, &contact[i]); + dJointAttach(c, b1, b2); } + } } -void suic_ode_space_collide(suic_ode_world_id world, suic_ode_space_id space, suic_ode_joint_group_id contactgroup) { - if (space && contactgroup && world) { - CollisionContext ctx = {.world = world, .contactgroup = contactgroup}; - dSpaceCollide(space, (void*)&ctx, &near_callback); - } +void suic_ode_space_collide(suic_ode_world_id world, suic_ode_space_id space, + suic_ode_joint_group_id contactgroup) { + if (space && contactgroup && world) { + CollisionContext ctx = {.world = world, .contactgroup = contactgroup}; + dSpaceCollide(space, (void *)&ctx, &near_callback); + } } suic_ode_joint_group_id suic_ode_joint_group_create(int max_size) { - return dJointGroupCreate(max_size); + return dJointGroupCreate(max_size); } void suic_ode_joint_group_destroy(suic_ode_joint_group_id group) { - if (group) { - dJointGroupDestroy(group); - } + if (group) { + dJointGroupDestroy(group); + } } void suic_ode_joint_group_empty(suic_ode_joint_group_id group) { - if (group) { - dJointGroupEmpty(group); - } + if (group) { + dJointGroupEmpty(group); + } } -void suic_ode_set_contact_max_force(dReal force) { - contact_max_force = force; -} +void suic_ode_set_contact_max_force(dReal force) { contact_max_force = force; } -void suic_ode_set_contact_erp(dReal erp) { - contact_erp = erp; -} +void suic_ode_set_contact_erp(dReal erp) { contact_erp = erp; } -void suic_ode_set_contact_cfm(dReal cfm) { - contact_cfm = cfm; -} +void suic_ode_set_contact_cfm(dReal cfm) { contact_cfm = cfm; } // ============================================================================ // ADDITIONAL BODY FUNCTIONS // ============================================================================ -void suic_ode_body_get_linear_vel(suic_ode_body_id body, float *x, float *y, float *z) { - if (body) { - const dReal *vel = dBodyGetLinearVel(body); - *x = (float)vel[0]; - *y = (float)vel[1]; - *z = (float)vel[2]; - } +void suic_ode_body_get_linear_vel(suic_ode_body_id body, float *x, float *y, + float *z) { + if (body) { + const dReal *vel = dBodyGetLinearVel(body); + *x = (float)vel[0]; + *y = (float)vel[1]; + *z = (float)vel[2]; + } } -void suic_ode_body_get_rotation(suic_ode_body_id body, float *q_w, float *q_x, float *q_y, float *q_z) { - if (body) { - const dReal *q = dBodyGetQuaternion(body); - *q_w = (float)q[0]; - *q_x = (float)q[1]; - *q_y = (float)q[2]; - *q_z = (float)q[3]; - } +void suic_ode_body_get_rotation(suic_ode_body_id body, float *q_w, float *q_x, + float *q_y, float *q_z) { + if (body) { + const dReal *q = dBodyGetQuaternion(body); + *q_w = (float)q[0]; + *q_x = (float)q[1]; + *q_y = (float)q[2]; + *q_z = (float)q[3]; + } } -void suic_ode_body_set_rotation(suic_ode_body_id body, dReal q_w, dReal q_x, dReal q_y, dReal q_z) { - if (body) { - dQuaternion q; - q[0] = q_w; - q[1] = q_x; - q[2] = q_y; - q[3] = q_z; - dBodySetQuaternion(body, q); - } +void suic_ode_body_set_rotation(suic_ode_body_id body, dReal q_w, dReal q_x, + dReal q_y, dReal q_z) { + if (body) { + dQuaternion q; + q[0] = q_w; + q[1] = q_x; + q[2] = q_y; + q[3] = q_z; + dBodySetQuaternion(body, q); + } } // ============================================================================ // GAME OBJECT SYSTEM - Unified Physics & Rendering // ============================================================================ -suic_game_object* suic_game_object_create_box( - suic_ode_world_id world, - suic_ode_space_id space, - float x, float y, float z, - float width, float height, float length, - float density, - unsigned char r, unsigned char g, unsigned char b, unsigned char a -) { - suic_game_object* obj = (suic_game_object*)gc_suic_alloc(sizeof(suic_game_object)); - if (!obj) return NULL; - - // Create physics body - obj->body = dBodyCreate(world); - if (!obj->body) { - suic_gc_free(obj); - return NULL; +suic_game_object *suic_game_object_create_box( + suic_ode_world_id world, suic_ode_space_id space, float x, float y, float z, + float width, float height, float length, float density, unsigned char r, + unsigned char g, unsigned char b, unsigned char a) { + suic_game_object *obj = + (suic_game_object *)gc_suic_alloc(sizeof(suic_game_object)); + if (!obj) + return NULL; + + // Create physics body + obj->body = dBodyCreate(world); + if (!obj->body) { + suic_gc_free(obj); + return NULL; + } + + // Set position + dBodySetPosition(obj->body, x, y, z); + + // Create and attach geometry + obj->geom = dCreateBox(space, width, height, length); + if (!obj->geom) { + dBodyDestroy(obj->body); + suic_gc_free(obj); + return NULL; + } + + dGeomSetBody(obj->geom, obj->body); + + // Set mass + dMass mass; + dMassSetBox(&mass, density, width, height, length); + dBodySetMass(obj->body, &mass); + + // Store rendering data + obj->width = width; + obj->height = height; + obj->length = length; + obj->r = r; + obj->g = g; + obj->b = b; + obj->a = a; + obj->shape_type = 0; // 0 = box + + return obj; +} + +void suic_game_object_destroy(suic_game_object *obj) { + if (obj) { + if (obj->geom) { + dGeomDestroy(obj->geom); } - - // Set position + if (obj->body) { + dBodyDestroy(obj->body); + } + suic_gc_free(obj); + } +} + +void suic_game_object_set_position(suic_game_object *obj, float x, float y, + float z) { + if (obj && obj->body) { dBodySetPosition(obj->body, x, y, z); - - // Create and attach geometry - obj->geom = dCreateBox(space, width, height, length); - if (!obj->geom) { - dBodyDestroy(obj->body); - suic_gc_free(obj); - return NULL; - } - - dGeomSetBody(obj->geom, obj->body); - - // Set mass - dMass mass; - dMassSetBox(&mass, density, width, height, length); - dBodySetMass(obj->body, &mass); - - // Store rendering data - obj->width = width; - obj->height = height; - obj->length = length; - obj->r = r; - obj->g = g; - obj->b = b; - obj->a = a; - obj->shape_type = 0; // 0 = box - - return obj; + } } -void suic_game_object_destroy(suic_game_object* obj) { - if (obj) { - if (obj->geom) { - dGeomDestroy(obj->geom); - } - if (obj->body) { - dBodyDestroy(obj->body); - } - suic_gc_free(obj); - } +void suic_game_object_get_position(suic_game_object *obj, float *x, float *y, + float *z) { + if (obj && obj->body) { + const dReal *pos = dBodyGetPosition(obj->body); + *x = (float)pos[0]; + *y = (float)pos[1]; + *z = (float)pos[2]; + } } -void suic_game_object_set_position(suic_game_object* obj, float x, float y, float z) { - if (obj && obj->body) { - dBodySetPosition(obj->body, x, y, z); - } +void suic_game_object_set_velocity(suic_game_object *obj, float x, float y, + float z) { + if (obj && obj->body) { + dBodySetLinearVel(obj->body, x, y, z); + } } -void suic_game_object_get_position(suic_game_object* obj, float *x, float *y, float *z) { - if (obj && obj->body) { - const dReal *pos = dBodyGetPosition(obj->body); - *x = (float)pos[0]; - *y = (float)pos[1]; - *z = (float)pos[2]; - } +void suic_game_object_get_velocity(suic_game_object *obj, float *x, float *y, + float *z) { + if (obj && obj->body) { + const dReal *vel = dBodyGetLinearVel(obj->body); + *x = (float)vel[0]; + *y = (float)vel[1]; + *z = (float)vel[2]; + } } -void suic_game_object_set_velocity(suic_game_object* obj, float x, float y, float z) { - if (obj && obj->body) { - dBodySetLinearVel(obj->body, x, y, z); +void suic_game_object_draw(suic_game_object *obj) { + if (obj && obj->body) { + float x, y, z; + suic_game_object_get_position(obj, &x, &y, &z); + + if (obj->shape_type == 0) { // Box + DrawCube((Vector3){x, y, z}, obj->width, obj->height, obj->length, + (Color){obj->r, obj->g, obj->b, obj->a}); + // Draw wireframe for visual clarity + DrawCubeWires((Vector3){x, y, z}, obj->width, obj->height, obj->length, + (Color){0, 0, 0, 200}); } + } } -void suic_game_object_get_velocity(suic_game_object* obj, float *x, float *y, float *z) { - if (obj && obj->body) { - const dReal *vel = dBodyGetLinearVel(obj->body); - *x = (float)vel[0]; - *y = (float)vel[1]; - *z = (float)vel[2]; - } +// ============================================================================ +// PLAYER CONTROLLER - FPS STYLE MOVEMENT +// ============================================================================ + +suic_player_controller *suic_player_controller_create(float x, float y, + float z) { + suic_player_controller *player = + (suic_player_controller *)gc_suic_alloc(sizeof(suic_player_controller)); + if (!player) + return NULL; + + player->position = (suic_vec3){x, y, z}; + player->velocity = (suic_vec3){0.0, 0.0, 0.0}; + player->forward = (suic_vec3){0.0, 0.0, -1.0}; // Looking down -Z + player->right = (suic_vec3){1.0, 0.0, 0.0}; // Right is +X + player->move_speed = 5.0; // units per second + player->sprint_speed = 10.0; // units per second + player->jump_force = 10.0; // units per second + player->gravity = -9.81; + player->is_grounded = 1; + + return player; } -void suic_game_object_draw(suic_game_object* obj) { - if (obj && obj->body) { - float x, y, z; - suic_game_object_get_position(obj, &x, &y, &z); - - if (obj->shape_type == 0) { // Box - DrawCube( - (Vector3){x, y, z}, - obj->width, obj->height, obj->length, - (Color){obj->r, obj->g, obj->b, obj->a} - ); - // Draw wireframe for visual clarity - DrawCubeWires( - (Vector3){x, y, z}, - obj->width, obj->height, obj->length, - (Color){0, 0, 0, 200} - ); - } - } +void suic_player_controller_destroy(suic_player_controller *player) { + if (player) { + suic_gc_free(player); + } } + +void suic_player_controller_update(suic_player_controller *player, + float delta_time) { + if (!player) + return; + + // Apply gravity + player->velocity.y += player->gravity * delta_time; + + // Update position + player->position.x += player->velocity.x * delta_time; + player->position.y += player->velocity.y * delta_time; + player->position.z += player->velocity.z * delta_time; +} + +void suic_player_controller_set_direction(suic_player_controller *player, + float forward_x, float forward_y, + float forward_z, float right_x, + float right_y, float right_z) { + if (!player) + return; + player->forward = (suic_vec3){forward_x, forward_y, forward_z}; + player->right = (suic_vec3){right_x, right_y, right_z}; +} + +void suic_player_controller_move_forward(suic_player_controller *player, + float amount) { + if (!player) + return; + + float speed = player->move_speed; + if (suic_is_sprint_held()) { + speed = player->sprint_speed; + } + + player->velocity.x += player->forward.x * speed * amount; + player->velocity.z += player->forward.z * speed * amount; +} + +void suic_player_controller_move_right(suic_player_controller *player, + float amount) { + if (!player) + return; + + float speed = player->move_speed; + if (suic_is_sprint_held()) { + speed = player->sprint_speed; + } + + player->velocity.x += player->right.x * speed * amount; + player->velocity.z += player->right.z * speed * amount; +} + +void suic_player_controller_jump(suic_player_controller *player) { + if (!player || !player->is_grounded) + return; + + player->velocity.y = player->jump_force; + player->is_grounded = 0; +} + +void suic_player_controller_get_position(suic_player_controller *player, + float *x, float *y, float *z) { + if (player) { + *x = player->position.x; + *y = player->position.y; + *z = player->position.z; + } +} + +void suic_player_controller_set_position(suic_player_controller *player, + float x, float y, float z) { + if (player) { + player->position.x = x; + player->position.y = y; + player->position.z = z; + } +} + diff --git a/libsuicmez/libsuicmez.h b/libsuicmez/libsuicmez.h index baafec8..dba015f 100644 --- a/libsuicmez/libsuicmez.h +++ b/libsuicmez/libsuicmez.h @@ -5,6 +5,10 @@ #include #include #include +#include + +// Include GC header for TypeInfo +#include "suicmez_gc.h" // Raylib support #include "raylib.h" @@ -52,11 +56,43 @@ static inline suic_vec3 suic_from_rl_vec3(Vector3 v) { return (suic_vec3){v.x, v.y, v.z}; } +// Keyboard key constants (from raylib) +#define KEY_W 87 +#define KEY_A 65 +#define KEY_S 83 +#define KEY_D 68 +#define KEY_SPACE 32 +#define KEY_LEFT_SHIFT 341 +#define KEY_LEFT_CTRL 341 // Platform dependent +#define KEY_LEFT_ALT 342 +#define KEY_UP 265 +#define KEY_DOWN 264 +#define KEY_LEFT 263 +#define KEY_RIGHT 262 +#define KEY_ESCAPE 256 +#define KEY_ENTER 257 +#define KEY_TAB 258 +#define KEY_BACKSPACE 259 +#define KEY_DELETE 261 +#define KEY_HOME 268 +#define KEY_END 269 +#define KEY_EQUAL 61 +#define KEY_MINUS 45 +#define KEY_KP_ADD 334 +#define KEY_KP_SUBTRACT 333 +#define KEY_F1 290 + +// Mouse button constants +#define MOUSE_LEFT 0 +#define MOUSE_RIGHT 1 +#define MOUSE_MIDDLE 2 + // Window management bool suic_init_window(int width, int height, const char *title); void suic_close_window(void); bool suic_window_should_close(void); void suic_set_target_fps(int fps); +void suic_enable_msaa_4x(void); // Drawing (2D) void suic_begin_drawing(void); @@ -80,10 +116,37 @@ void suic_end_mode3d(void); void suic_draw_cube(float x, float y, float z, float width, float height, float length, unsigned char r, unsigned char g, unsigned char b, unsigned char a); void suic_draw_cube_wires(float x, float y, float z, float width, float height, float length, unsigned char r, unsigned char g, unsigned char b, unsigned char a); -// Input +// Input - Keyboard bool suic_is_key_down(int key); +bool suic_is_key_pressed(int key); +bool suic_is_key_released(int key); + +// Input - Mouse bool suic_is_mouse_button_down(int b); +bool suic_is_mouse_button_pressed(int b); +bool suic_is_mouse_button_released(int b); suic_vec2 suic_get_mouse_position(void); +suic_vec2 suic_get_mouse_delta(void); +float suic_get_mouse_x(void); +float suic_get_mouse_y(void); +float suic_get_mouse_delta_x(void); +float suic_get_mouse_delta_y(void); + +// Input - Helper functions for gamedev +int suic_is_movement_input(void); // Returns bitmask: 1=W, 2=A, 4=S, 8=D +int suic_is_sprint_held(void); +int suic_is_jump_pressed(void); + +// Cursor management +void suic_disable_cursor(void); +void suic_enable_cursor(void); +bool suic_is_cursor_hidden(void); + +// Matrix operations for 3D transformations +void suic_rl_push_matrix(void); +void suic_rl_pop_matrix(void); +void suic_rl_translate_f(float x, float y, float z); +void suic_rl_rotate_f(float angle, float x, float y, float z); // Images and Textures typedef struct suic_image_handle { @@ -119,10 +182,23 @@ void suic_sound_play(suic_sound_handle snd); void suic_sound_set_volume(suic_sound_handle snd, float volume); void suic_sound_free(suic_sound_handle *snd); +// Player controller for FPS-style movement +typedef struct suic_player_controller { + suic_vec3 position; + suic_vec3 velocity; + suic_vec3 forward; // Camera forward direction + suic_vec3 right; // Camera right direction + float move_speed; + float sprint_speed; + float jump_force; + float gravity; + int is_grounded; +} suic_player_controller; + // Raycasting typedef struct suic_ray { - suic_vec3 origin; - suic_vec3 direction; + suic_vec3 origin; + suic_vec3 direction; } suic_ray; typedef struct suic_rayhit { @@ -230,4 +306,15 @@ void suic_game_object_set_velocity(suic_game_object* obj, float x, float y, floa void suic_game_object_get_velocity(suic_game_object* obj, float *x, float *y, float *z); void suic_game_object_draw(suic_game_object* obj); +// Player controller functions for FPS-style games +suic_player_controller* suic_player_controller_create(float x, float y, float z); +void suic_player_controller_destroy(suic_player_controller* player); +void suic_player_controller_update(suic_player_controller* player, float delta_time); +void suic_player_controller_set_direction(suic_player_controller* player, float forward_x, float forward_y, float forward_z, float right_x, float right_y, float right_z); +void suic_player_controller_move_forward(suic_player_controller* player, float amount); +void suic_player_controller_move_right(suic_player_controller* player, float amount); +void suic_player_controller_jump(suic_player_controller* player); +void suic_player_controller_get_position(suic_player_controller* player, float *x, float *y, float *z); +void suic_player_controller_set_position(suic_player_controller* player, float x, float y, float z); + #endif // LIBSUICMEZ_H diff --git a/libsuicmez/suicmez_gc.c b/libsuicmez/suicmez_gc.c index f51aa70..42bfce9 100644 --- a/libsuicmez/suicmez_gc.c +++ b/libsuicmez/suicmez_gc.c @@ -112,6 +112,16 @@ static Obj *forward(Obj *obj) { return new_obj; } +static inline void scan_object_fields(Obj *obj) { + const TypeInfo *t = obj->header.type; + + for (uint16_t i = 0; i < t->field_count; i++) { + if (t->pointer_bitmap[i]) { + obj->fields[i] = forward((Obj*)obj->fields[i]); + } + } +} + static void gc_minor_collect(void) { gc.to_ptr = gc.to_space; @@ -189,16 +199,6 @@ void *gc_alloc(const TypeInfo *type, size_t payload_size) { return obj; } -static inline void scan_object_fields(Obj *obj) { - const TypeInfo *t = obj->header.type; - - for (uint16_t i = 0; i < t->field_count; i++) { - if (t->pointer_bitmap[i]) { - obj->fields[i] = forward((Obj*)obj->fields[i]); - } - } -} - void gc_init(void) { gc.young_size = YOUNG_SIZE; gc.old_size = OLD_SIZE; diff --git a/libsuicmez/suicmez_gc.h b/libsuicmez/suicmez_gc.h index 274c9da..43a233d 100644 --- a/libsuicmez/suicmez_gc.h +++ b/libsuicmez/suicmez_gc.h @@ -15,6 +15,7 @@ /* Forward declare Obj so ObjHeader can reference it */ typedef struct Obj Obj; +/* Forward declare TypeInfo */ typedef struct TypeInfo TypeInfo; /* Header must come first */ diff --git a/src/c_ir.rs b/src/c_ir.rs index aca4d2a..ec173e8 100644 --- a/src/c_ir.rs +++ b/src/c_ir.rs @@ -1,4 +1,4 @@ -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum CType { Void, Int, @@ -56,20 +56,20 @@ impl CType { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct CVarDecl { pub name: String, pub ty: CType, pub initializer: Option, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct CStructDecl { pub name: String, pub fields: Vec, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct CFuncDecl { pub name: String, pub return_type: CType, @@ -77,7 +77,7 @@ pub struct CFuncDecl { pub body: Option>, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum CExpr { IntLit(i64), FloatLit(f64), @@ -99,7 +99,7 @@ pub enum CExpr { Ternary(Box, Box, Box), // cond ? then : else } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum CBinaryOp { Add, Sub, @@ -136,7 +136,7 @@ impl CBinaryOp { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum CUnaryOp { Neg, Not, @@ -157,7 +157,7 @@ impl CUnaryOp { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum CStmt { VarDecl(CVarDecl), Expr(CExpr), @@ -171,7 +171,7 @@ pub enum CStmt { Block(Vec), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum CToplevel { StructDecl(CStructDecl), FuncDecl(CFuncDecl), diff --git a/src/c_lowerer/declaration_transpiler.rs b/src/c_lowerer/declaration_transpiler.rs index dedfcfa..5cb7dae 100644 --- a/src/c_lowerer/declaration_transpiler.rs +++ b/src/c_lowerer/declaration_transpiler.rs @@ -179,6 +179,7 @@ pub fn convert_to_c_type(name: &String) -> Result { "float" => Ok(CType::Float), "bool" => Ok(CType::Bool), "string" => Ok(CType::Ptr(Box::new(CType::Char))), + "()" => Ok(CType::Void), // Unit type _ => Ok(CType::Ptr(Box::new(CType::Struct(name.clone())))), // Assume heap-allocated struct } } diff --git a/src/c_lowerer/statements_transpiler.rs b/src/c_lowerer/statements_transpiler.rs index 2038f25..2c6f76c 100644 --- a/src/c_lowerer/statements_transpiler.rs +++ b/src/c_lowerer/statements_transpiler.rs @@ -339,6 +339,15 @@ impl StatementsTranspiler { TypedExprKind::Break => Ok(CStmt::Break), TypedExprKind::Continue => Ok(CStmt::Continue), TypedExprKind::Defer(_) => Err("Defer should be handled in Do blocks".to_string()), + TypedExprKind::If(cond, then_expr, else_expr) => { + let c_cond = self.transpile_expr(cond)?; + let then_stmts = self.expr_to_loop_stmts(then_expr)?; + let else_stmts = match else_expr { + Some(else_expr) => self.expr_to_loop_stmts(else_expr)?, + None => vec![], + }; + Ok(CStmt::If(c_cond, then_stmts, if else_stmts.is_empty() { None } else { Some(else_stmts) })) + } _ => { // For other expressions, treat as expression statements let c_expr = self.transpile_expr(expr)?; @@ -385,6 +394,11 @@ impl StatementsTranspiler { } Ok(c_stmts) } + TypedExprKind::If(_, _, _) => { + // For If expressions at the statement level, treat as statement + let stmt = self.transpile_stmt(expr)?; + Ok(vec![stmt]) + } _ => Ok(vec![CStmt::Return(Some(self.transpile_expr(expr)?))]), } } diff --git a/src/codegen/transpiler.rs b/src/codegen/transpiler.rs index dae1960..87aa005 100644 --- a/src/codegen/transpiler.rs +++ b/src/codegen/transpiler.rs @@ -41,10 +41,12 @@ pub struct Transpiler { stmt_transpiler: StatementsTranspiler, array_types: std::collections::HashSet, // Track array types we need to generate has_main: bool, // Track if we found a main function + typeinfo_map: std::collections::HashMap>, // Map struct name to pointer bitmap + debug: bool, // Whether to generate debug printf statements } impl Transpiler { - pub fn new() -> Self { + pub fn new(debug: bool) -> Self { Transpiler { structs: Vec::new(), functions: Vec::new(), @@ -53,6 +55,8 @@ impl Transpiler { stmt_transpiler: StatementsTranspiler::new(), array_types: std::collections::HashSet::new(), has_main: false, + typeinfo_map: std::collections::HashMap::new(), + debug, } } @@ -68,6 +72,19 @@ impl Transpiler { } } + /// Check if a CType is a pointer type (needs to be tracked in GC bitmap) + fn is_pointer_type(ty: &CType) -> bool { + matches!(ty, CType::Ptr(_) | CType::Array(_) | CType::Struct(_)) + } + + /// Generate pointer bitmap for a struct's fields + fn generate_pointer_bitmap(fields: &[CVarDecl]) -> Vec { + fields + .iter() + .map(|field| if Self::is_pointer_type(&field.ty) { 1u8 } else { 0u8 }) + .collect() + } + pub fn transpile_program(&mut self, nodes: &[TypedASTNode]) -> Result { for node in nodes { self.lower_declarations_to_c_ir(node)?; @@ -93,16 +110,17 @@ impl Transpiler { output.push_str("\n"); // GC functions - output.push_str("void* gc_suic_alloc(size_t size);\n"); - output.push_str("void suic_gc_free(void* ptr);\n"); + output.push_str("void* gc_alloc(const TypeInfo* type, size_t size);\n"); + output.push_str("void gc_init(void);\n"); + output.push_str("void gc_shutdown(void);\n"); output.push_str("\n"); // Helper functions for heap allocation output.push_str("// Helper for allocating arrays\n"); output.push_str( - "static void* suic_alloc_array(size_t elem_size, size_t len, void* init_data) {\n", + "static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) {\n", ); - output.push_str(" void* ptr = gc_suic_alloc(elem_size * len);\n"); + output.push_str(" void* ptr = gc_alloc(type, elem_size * len);\n"); output.push_str(" if (init_data) memcpy(ptr, init_data, elem_size * len);\n"); output.push_str(" return ptr;\n"); output.push_str("}\n"); @@ -110,8 +128,8 @@ impl Transpiler { // Helper for allocating structs output.push_str("// Helper for allocating structs\n"); - output.push_str("static void* suic_alloc_struct(size_t size, void* init_data) {\n"); - output.push_str(" void* ptr = gc_suic_alloc(size);\n"); + output.push_str("static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) {\n"); + output.push_str(" void* ptr = gc_alloc(type, size);\n"); output.push_str(" if (init_data) memcpy(ptr, init_data, size);\n"); output.push_str(" return ptr;\n"); output.push_str("}\n"); @@ -129,6 +147,14 @@ impl Transpiler { output.push_str(&self.generate_struct_decl(struct_decl)); output.push_str(";\n"); } + output.push_str("\n"); + + // Generate TypeInfo definitions for GC + for struct_decl in &self.structs { + output.push_str(&self.generate_typeinfo_decl(struct_decl)); + output.push_str("\n"); + } + output.push_str("\n"); // Generate function declarations (prototypes) for func in &self.functions { @@ -167,6 +193,9 @@ impl Transpiler { for field in &struct_decl.fields { self.collect_array_types_from_ctype(&field.ty); } + // Generate TypeInfo bitmap for this struct + let bitmap = Self::generate_pointer_bitmap(&struct_decl.fields); + self.typeinfo_map.insert(struct_decl.name.clone(), bitmap); self.structs.push(struct_decl); } TypedASTNodeKind::Enum(e) => { @@ -175,6 +204,9 @@ impl Transpiler { for field in &struct_decl.fields { self.collect_array_types_from_ctype(&field.ty); } + // Generate TypeInfo bitmap for this enum struct + let bitmap = Self::generate_pointer_bitmap(&struct_decl.fields); + self.typeinfo_map.insert(struct_decl.name.clone(), bitmap); self.structs.push(struct_decl); } } @@ -265,6 +297,46 @@ impl Transpiler { output } + fn generate_typeinfo_decl(&self, struct_decl: &CStructDecl) -> String { + if let Some(bitmap) = self.typeinfo_map.get(&struct_decl.name) { + // Generate pointer bitmap as a C array + let bitmap_str = bitmap + .iter() + .map(|b| b.to_string()) + .collect::>() + .join(", "); + + let field_count = struct_decl.fields.len(); + let pointer_count = bitmap.iter().filter(|&&b| b == 1).count(); + + format!( + "static const uint8_t sui_bitmap_{}[] = {{ {} }};\n\ + static const TypeInfo sui_typeinfo_{} = {{\n \ + .field_count = {},\n \ + .pointer_count = {},\n \ + .pointer_bitmap = sui_bitmap_{}\n\ + }};", + struct_decl.name, + bitmap_str, + struct_decl.name, + field_count, + pointer_count, + struct_decl.name + ) + } else { + // Empty bitmap for struct with no fields + format!( + "static const uint8_t sui_bitmap_{}[] = {{}};\n\ + static const TypeInfo sui_typeinfo_{} = {{\n \ + .field_count = 0,\n \ + .pointer_count = 0,\n \ + .pointer_bitmap = sui_bitmap_{}\n\ + }};", + struct_decl.name, struct_decl.name, struct_decl.name + ) + } + } + fn generate_func_proto(&self, func: &CFuncDecl) -> String { let params_str = if func.params.is_empty() { "void".to_string() @@ -300,11 +372,13 @@ impl Transpiler { fn generate_wrapper_main(&self) -> String { let mut output = String::new(); output.push_str("int main(int argc, char* argv[]) {\n"); - output.push_str(" // init gc and stuff\n"); + output.push_str(" // Initialize GC\n"); + output.push_str(" gc_init();\n"); output.push_str(" // init globals\n"); output.push_str(" // init event loop\n"); output.push_str(" int result = suic_main();\n"); - output.push_str(" // free the stuff\n"); + output.push_str(" // Shutdown GC\n"); + output.push_str(" gc_shutdown();\n"); output.push_str(" return result;\n"); output.push_str("}\n"); output @@ -321,13 +395,13 @@ impl Transpiler { fn generate_heap_alloc(&self, ty: &CType) -> String { match ty { CType::Struct(name) => { - format!("(struct {}*)suic_gc_alloc(sizeof(struct {}))", name, name) + format!("(struct {}*)gc_alloc(&sui_typeinfo_{}, sizeof(struct {}))", name, name, name) } CType::Array(elem_type) => { + let array_name = Self::get_array_struct_name(elem_type); format!( - "(struct {}*)suic_gc_alloc(sizeof(struct {}))", - Self::get_array_struct_name(elem_type), - Self::get_array_struct_name(elem_type) + "(struct {}*)gc_alloc(&sui_typeinfo_{}, sizeof(struct {}))", + array_name, array_name, array_name ) } _ => "NULL".to_string(), @@ -335,7 +409,10 @@ impl Transpiler { } fn add_debug_print(&self, code: &str) -> String { - // Extract the actual statement for the debug message + if !self.debug { + return code.to_string(); + } + let trimmed = code.trim_end_matches('\n').trim_start(); let trimmed_no_semi = trimmed.trim_end_matches(';'); @@ -452,8 +529,10 @@ impl Transpiler { CExpr::FloatLit(f) => format!("{:.6}", f), CExpr::BoolLit(b) => format!("{}", b), CExpr::StringLit(s) => { + // For strings, we treat them as char arrays, so use a generic TypeInfo + // that marks all fields as non-pointers format!( - "suic_alloc_array(sizeof(char), {}, \"{}\")", + "suic_alloc_array(NULL, sizeof(char), {}, \"{}\")", s.len() + 1, // +1 for null terminator s ) @@ -493,19 +572,62 @@ impl Transpiler { "ode_body_get_linear_vel" => "suic_ode_body_get_linear_vel", "ode_body_get_rotation" => "suic_ode_body_get_rotation", "ode_body_set_rotation" => "suic_ode_body_set_rotation", - // Raylib functions - "init_window" => "suic_init_window", - "close_window" => "suic_close_window", - "window_should_close" => "suic_window_should_close", - "set_target_fps" => "suic_set_target_fps", + // Raylib functions + "init_window" => "suic_init_window", + "close_window" => "suic_close_window", + "window_should_close" => "suic_window_should_close", + "set_target_fps" => "suic_set_target_fps", + "enable_msaa_4x" => "suic_enable_msaa_4x", "begin_drawing" => "suic_begin_drawing", "end_drawing" => "suic_end_drawing", "clear_background" => "suic_clear_background", - "begin_mode3d" => "suic_begin_mode3d", - "end_mode3d" => "suic_end_mode3d", - "draw_cube" => "suic_draw_cube", - "draw_cube_wires" => "suic_draw_cube_wires", + "begin_mode3d" => "suic_begin_mode3d", + "end_mode3d" => "suic_end_mode3d", + "draw_cube" => "suic_draw_cube", + "draw_cube_wires" => "suic_draw_cube_wires", + "enable_msaa_4x" => "suic_enable_msaa_4x", + "enable_msaa_8x" => "suic_enable_msaa_8x", + "enable_msaa_16x" => "suic_enable_msaa_16x", + // Input - Keyboard "is_key_down" => "suic_is_key_down", + "is_key_pressed" => "suic_is_key_pressed", + "is_key_released" => "suic_is_key_released", + // Input - Mouse + "is_mouse_button_down" => "suic_is_mouse_button_down", + "is_mouse_button_pressed" => "suic_is_mouse_button_pressed", + "is_mouse_button_released" => "suic_is_mouse_button_released", + "get_mouse_position" => "suic_get_mouse_position", + "get_mouse_delta" => "suic_get_mouse_delta", + "get_mouse_x" => "suic_get_mouse_x", + "get_mouse_y" => "suic_get_mouse_y", + "get_mouse_delta_x" => "suic_get_mouse_delta_x", + "get_mouse_delta_y" => "suic_get_mouse_delta_y", + // Input - Gamedev helpers + "is_movement_input" => "suic_is_movement_input", + "is_sprint_held" => "suic_is_sprint_held", + "is_jump_pressed" => "suic_is_jump_pressed", + // Cursor management + "disable_cursor" => "suic_disable_cursor", + "enable_cursor" => "suic_enable_cursor", + "is_cursor_hidden" => "suic_is_cursor_hidden", + // Matrix operations + "rl_push_matrix" => "suic_rl_push_matrix", + "rl_pop_matrix" => "suic_rl_pop_matrix", + "rl_translate_f" => "suic_rl_translate_f", + "rl_rotate_f" => "suic_rl_rotate_f", + // Player controller functions + "player_controller_create" => "suic_player_controller_create", + "player_controller_destroy" => "suic_player_controller_destroy", + "player_controller_update" => "suic_player_controller_update", + "player_controller_set_direction" => "suic_player_controller_set_direction", + "player_controller_move_forward" => "suic_player_controller_move_forward", + "player_controller_move_right" => "suic_player_controller_move_right", + "player_controller_jump" => "suic_player_controller_jump", + "player_controller_get_position" => "suic_player_controller_get_position", + "player_controller_set_position" => "suic_player_controller_set_position", + // Math functions + "sin" => "sin", + "cos" => "cos", _ => func, }; @@ -523,7 +645,10 @@ impl Transpiler { format!("{}{}", op.to_string(), self.generate_expr(expr)) } CExpr::Cast(expr, ty) => { - format!("({}) {}", ty.to_string(), self.generate_expr(expr)) + match (*expr.clone(), ty.clone()) { + (CExpr::IntLit(0), CType::Ptr(_)) => "NULL".to_string(), + _ => format!("({}) {}", ty.to_string(), self.generate_expr(expr)), + } } CExpr::AddrOf(expr) => format!("&{}", self.generate_expr(expr)), CExpr::Deref(expr) => format!("*{}", self.generate_expr(expr)), @@ -539,7 +664,8 @@ impl Transpiler { .map(|(name, expr)| format!(".{} = {}", name, self.generate_expr(expr))) .collect(); format!( - "suic_alloc_struct(sizeof(struct {}), &(struct {}){{ {} }})", + "suic_alloc_struct(&sui_typeinfo_{}, sizeof(struct {}), &(struct {}){{ {} }})", + struct_name, struct_name, struct_name, field_inits.join(", ") @@ -571,8 +697,8 @@ impl Transpiler { }; format!( - "suic_alloc_struct(sizeof(struct {}), &(struct {}){{ .discriminant = {}, .data = {{ .{} = {} }} }})", - enum_name, enum_name, variant_index, union_field_name, variant_init + "suic_alloc_struct(&sui_typeinfo_{}, sizeof(struct {}), &(struct {}){{ .discriminant = {}, .data = {{ .{} = {} }} }})", + enum_name, enum_name, enum_name, variant_index, union_field_name, variant_init ) } @@ -585,8 +711,9 @@ impl Transpiler { .map(|expr| self.generate_expr(expr)) .collect(); // Generate heap-allocated array using helper function + // Use NULL for TypeInfo since arrays of primitives don't contain pointers format!( - "suic_alloc_array(sizeof(int), {}, (int[]){{{}}})", + "suic_alloc_array(NULL, sizeof(int), {}, (int[]){{{}}})", vec.len(), vec.join(", ") ) diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index a64b756..7cf5825 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -37,10 +37,10 @@ pub enum Token { })] String(String), - #[regex(r#"r#"([^"]*)""#, |lex| { + #[regex(r#"r"([^"]*)""#, |lex| { let s = lex.slice(); // Remove the outer r" and " (s[2..s.len() - 1]) - s[3..s.len() - 1].to_string() + s[2..s.len() - 1].to_string() })] RawString(String), diff --git a/src/lexer/tests.rs b/src/lexer/tests.rs index 6e03c88..21b0e62 100644 --- a/src/lexer/tests.rs +++ b/src/lexer/tests.rs @@ -10,9 +10,7 @@ fn test_literals() { assert_eq!(lexer.next(), Some(Ok(Token::Int(42)))); assert_eq!(lexer.next(), Some(Ok(Token::Float(2.14)))); assert_eq!(lexer.next(), Some(Ok(Token::String("hello".to_string())))); - // RawString regex seems to have issues, let's test separately - assert_eq!(lexer.next(), Some(Ok(Token::Variable("r".to_string())))); - assert_eq!(lexer.next(), Some(Ok(Token::String("raw".to_string())))); + assert_eq!(lexer.next(), Some(Ok(Token::RawString("raw".to_string())))); assert_eq!(lexer.next(), None); } diff --git a/src/main.rs b/src/main.rs index 7d454da..cd17113 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,10 @@ struct Args { #[arg(short, long)] test: bool, + /// Generate debug printf statements in the output C code + #[arg(long)] + debug: bool, + /// The Sui source file to compile file: Option, } @@ -27,7 +31,7 @@ fn main() { } else if let Some(filename) = args.file { println!("Type checking file: {}", filename); - if let Err(e) = run_file(&filename) { + if let Err(e) = run_file(&filename, args.debug) { eprintln!("Error: {}", e); } } else { @@ -53,7 +57,7 @@ fn run_test_suite() { for file in test_files { println!("Testing: {}", file); - match run_file(file) { + match run_file(file, false) { Ok(_) => println!("✓ Passed\n"), Err(e) => println!("✗ Failed: {}\n", e), } @@ -175,7 +179,7 @@ fn format_type_error(source: &str, error: &suicmez::typechecker::TypeError) -> S format!("Type error: {} (at byte {})", error.kind, error.span.start) } -fn run_file(filename: &str) -> Result<(), String> { +fn run_file(filename: &str, debug: bool) -> Result<(), String> { // ========== IMPORT RESOLUTION PHASE ========== println!("\n=== Import Resolution Phase ==="); let mut resolver = ImportResolver::new(); @@ -315,7 +319,7 @@ fn run_file(filename: &str) -> Result<(), String> { println!("Type variable check passed! No type variables remain in AST."); // Generate C code - let mut transpiler = Transpiler::new(); + let mut transpiler = Transpiler::new(debug); let c_code = transpiler .transpile_program(&mono_nodes) .map_err(|e| format!("Code generation error: {}", e))?; diff --git a/src/typechecker.rs b/src/typechecker.rs index 2dccee6..c7ac8a7 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -660,6 +660,77 @@ impl TypeChecker { return_type: Type::Unit, }, ); + self.env.functions.insert( + "enable_msaa_4x".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Unit, + }, + ); + + // Cursor management + self.env.functions.insert( + "disable_cursor".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Unit, + }, + ); + self.env.functions.insert( + "enable_cursor".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Unit, + }, + ); + + // Input helpers + self.env.functions.insert( + "is_movement_input".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Int, + }, + ); + self.env.functions.insert( + "is_sprint_held".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Int, + }, + ); + self.env.functions.insert( + "is_jump_pressed".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Int, + }, + ); + + // Key constants + let keys = vec![ + "KEY_W", "KEY_A", "KEY_S", "KEY_D", "KEY_SPACE", "KEY_LEFT_SHIFT", + "KEY_EQUAL", "KEY_MINUS", "KEY_KP_ADD", "KEY_KP_SUBTRACT", + "KEY_ESCAPE", "KEY_ENTER", "KEY_TAB", "KEY_BACKSPACE", "KEY_DELETE", + "KEY_HOME", "KEY_END", "KEY_F1" + ]; + for (i, key) in keys.iter().enumerate() { + let id = 1000 + i; + self.env.name_to_id.insert(key.to_string(), BindingId(id)); + self.env.vars.insert(BindingId(id), VarInfo { + ty: Type::Int, + kind: BindingKind::Default, + name: key.to_string(), + usage: 0, + span: Span { start: 0, end: 0, file: "builtin".to_string() }, + }); + } // Drawing self.env.functions.insert( @@ -766,6 +837,22 @@ impl TypeChecker { return_type: Type::Bool, }, ); + self.env.functions.insert( + "is_key_pressed".to_string(), + FunctionType { + type_params: vec![], + params: vec![Type::Int], // key + return_type: Type::Bool, + }, + ); + self.env.functions.insert( + "is_key_released".to_string(), + FunctionType { + type_params: vec![], + params: vec![Type::Int], // key + return_type: Type::Bool, + }, + ); // Physics integration helper self.env.functions.insert( @@ -781,6 +868,120 @@ impl TypeChecker { return_type: Type::Unit, }, ); + + // Built-in Vec2 type + self.env.add_type( + "Vec2".to_string(), + TypeInfo { + kind: TypeInfoKind::Struct(vec![ + ("x".to_string(), TypeAnnot::Var("float".to_string())), + ("y".to_string(), TypeAnnot::Var("float".to_string())), + ]), + parameters: vec![], + }, + ); + + // Mouse input functions + self.env.functions.insert( + "get_mouse_position".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Struct("Vec2".to_string(), vec![]), // suic_vec2 + }, + ); + self.env.functions.insert( + "get_mouse_delta".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Struct("Vec2".to_string(), vec![]), // suic_vec2 + }, + ); + self.env.functions.insert( + "get_mouse_x".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Float, + }, + ); + self.env.functions.insert( + "get_mouse_y".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Float, + }, + ); + self.env.functions.insert( + "get_mouse_delta_x".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Float, + }, + ); + self.env.functions.insert( + "get_mouse_delta_y".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Float, + }, + ); + + // Math functions + self.env.functions.insert( + "cos".to_string(), + FunctionType { + type_params: vec![], + params: vec![Type::Float], // angle in radians + return_type: Type::Float, + }, + ); + self.env.functions.insert( + "sin".to_string(), + FunctionType { + type_params: vec![], + params: vec![Type::Float], // angle in radians + return_type: Type::Float, + }, + ); + + // Raylib matrix operations + self.env.functions.insert( + "rl_push_matrix".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Unit, + }, + ); + self.env.functions.insert( + "rl_pop_matrix".to_string(), + FunctionType { + type_params: vec![], + params: vec![], + return_type: Type::Unit, + }, + ); + self.env.functions.insert( + "rl_translate_f".to_string(), + FunctionType { + type_params: vec![], + params: vec![Type::Float, Type::Float, Type::Float], // x, y, z + return_type: Type::Unit, + }, + ); + self.env.functions.insert( + "rl_rotate_f".to_string(), + FunctionType { + type_params: vec![], + params: vec![Type::Float, Type::Float, Type::Float, Type::Float], // angle, x, y, z + return_type: Type::Unit, + }, + ); } fn collect_definitions(&mut self, node: &ASTNode) -> Result<(), TypeError> { diff --git a/test_player.c b/test_player.c new file mode 100644 index 0000000..28c6fa0 --- /dev/null +++ b/test_player.c @@ -0,0 +1,46 @@ +#include "../libsuicmez/libsuicmez.h" +#include +#include +#include +#include + +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); + +// Helper for allocating arrays +static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) { + void* ptr = gc_alloc(type, elem_size * len); + if (init_data) memcpy(ptr, init_data, elem_size * len); + return ptr; +} + +// Helper for allocating structs +static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) { + void* ptr = gc_alloc(type, size); + if (init_data) memcpy(ptr, init_data, size); + return ptr; +} + + + + +int suic_main(void); + + +int suic_main(void) { + void* p = suic_player_controller_create(0.000000, 1.000000, 2.000000); + return 0; +} + +int main(int argc, char* argv[]) { + // Initialize GC + gc_init(); + // init globals + // init event loop + int result = suic_main(); + // Shutdown GC + gc_shutdown(); + return result; +} + diff --git a/test_player.sui b/test_player.sui new file mode 100644 index 0000000..2fb5b01 --- /dev/null +++ b/test_player.sui @@ -0,0 +1 @@ +fn main() -> int do let p = player_controller_create(0.0, 1.0, 2.0); 0 end diff --git a/test_window b/test_window new file mode 100755 index 0000000..96801af Binary files /dev/null and b/test_window differ diff --git a/test_window.c b/test_window.c new file mode 100644 index 0000000..a986976 --- /dev/null +++ b/test_window.c @@ -0,0 +1,53 @@ +#include "../libsuicmez/libsuicmez.h" +#include +#include +#include +#include + +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); + +// Helper for allocating arrays +static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) { + void* ptr = gc_alloc(type, elem_size * len); + if (init_data) memcpy(ptr, init_data, elem_size * len); + return ptr; +} + +// Helper for allocating structs +static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) { + void* ptr = gc_alloc(type, size); + if (init_data) memcpy(ptr, init_data, size); + return ptr; +} + + + + +int suic_main(void); + + +int suic_main(void) { + suic_init_window(800, 600, suic_alloc_array(NULL, sizeof(char), 5, "Test")); + suic_set_target_fps(60); + while ((suic_window_should_close() == false)) { + suic_begin_drawing(); + suic_clear_background(255, 0, 0, 255); + suic_end_drawing(); + } + suic_close_window(); + return 0; +} + +int main(int argc, char* argv[]) { + // Initialize GC + gc_init(); + // init globals + // init event loop + int result = suic_main(); + // Shutdown GC + gc_shutdown(); + return result; +} + diff --git a/test_window.sui b/test_window.sui new file mode 100644 index 0000000..6a87cfa --- /dev/null +++ b/test_window.sui @@ -0,0 +1 @@ +fn main() -> int do init_window(800, 600, "Test"); set_target_fps(60); while window_should_close() == false do begin_drawing(); clear_background(255, 0, 0, 255); end_drawing(); end; close_window(); 0 end diff --git a/tests/basic_types.c b/tests/basic_types.c new file mode 100644 index 0000000..ce4f999 --- /dev/null +++ b/tests/basic_types.c @@ -0,0 +1,49 @@ +#include "../libsuicmez/libsuicmez.h" +#include +#include +#include +#include + +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); + +// Helper for allocating arrays +static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) { + void* ptr = gc_alloc(type, elem_size * len); + if (init_data) memcpy(ptr, init_data, elem_size * len); + return ptr; +} + +// Helper for allocating structs +static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) { + void* ptr = gc_alloc(type, size); + if (init_data) memcpy(ptr, init_data, size); + return ptr; +} + + + + +int suic_main(void); + + +int suic_main(void) { + int x = 5; + float y = 10.500000; + bool z = true; + char* s = suic_alloc_array(NULL, sizeof(char), 6, "hello"); + return x; +} + +int main(int argc, char* argv[]) { + // Initialize GC + gc_init(); + // init globals + // init event loop + int result = suic_main(); + // Shutdown GC + gc_shutdown(); + return result; +} + diff --git a/tests/basic_types.o b/tests/basic_types.o new file mode 100755 index 0000000..fae5902 Binary files /dev/null and b/tests/basic_types.o differ diff --git a/tests/control_flow.c b/tests/control_flow.c new file mode 100644 index 0000000..edba436 --- /dev/null +++ b/tests/control_flow.c @@ -0,0 +1,50 @@ +#include "../libsuicmez/libsuicmez.h" +#include +#include +#include +#include + +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); + +// Helper for allocating arrays +static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) { + void* ptr = gc_alloc(type, elem_size * len); + if (init_data) memcpy(ptr, init_data, elem_size * len); + return ptr; +} + +// Helper for allocating structs +static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) { + void* ptr = gc_alloc(type, size); + if (init_data) memcpy(ptr, init_data, size); + return ptr; +} + + + + +int suic_main(void); + + +int suic_main(void) { + (true ? 1 : 0); + int i = 0; + while ((i < 5)) { + i = (i + 1); + } + return i; +} + +int main(int argc, char* argv[]) { + // Initialize GC + gc_init(); + // init globals + // init event loop + int result = suic_main(); + // Shutdown GC + gc_shutdown(); + return result; +} + diff --git a/tests/fps_game.c b/tests/fps_game.c new file mode 100644 index 0000000..cd2e145 --- /dev/null +++ b/tests/fps_game.c @@ -0,0 +1,216 @@ +#include "../libsuicmez/libsuicmez.h" +#include +#include +#include +#include + +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); + +// Helper for allocating arrays +static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) { + void* ptr = gc_alloc(type, elem_size * len); + if (init_data) memcpy(ptr, init_data, elem_size * len); + return ptr; +} + +// Helper for allocating structs +static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) { + void* ptr = gc_alloc(type, size); + if (init_data) memcpy(ptr, init_data, size); + return ptr; +} + + + + +int suic_main(void); + + +int suic_main(void) { + suic_enable_msaa_4x(); + suic_init_window(1280, 720, suic_alloc_array(NULL, sizeof(char), 75, "Sui FPS Game - WASD to move, Mouse to look, SPACE to jump, SHIFT to sprint")); + suic_set_target_fps(60); + suic_disable_cursor(); + suic_ode_init(); + void* world = suic_ode_world_create(); + void* null_space = NULL; + void* space = suic_ode_simple_space_create(null_space); + suic_ode_world_set_gravity(world, 0.000000, -9.810000, 0.000000); + void* contactgroup = suic_ode_joint_group_create(0); + void* ground_geom = suic_ode_create_plane_geom(space, 0.000000, 1.000000, 0.000000, 0.000000); + void* player_body = suic_ode_body_create(world); + suic_ode_body_set_position(player_body, 0.000000, 2.000000, 0.000000); + void* player_geom = suic_ode_create_box_geom(space, 0.800000, 1.600000, 0.800000); + suic_ode_geom_set_body(player_geom, player_body); + suic_ode_body_set_box_mass(player_body, 1.000000, 0.800000, 1.600000, 0.800000); + void* cube1_body = suic_ode_body_create(world); + suic_ode_body_set_position(cube1_body, 0.000000, 1.000000, -5.000000); + suic_ode_body_set_box_mass(cube1_body, 1.000000, 1.000000, 1.000000, 1.000000); + void* cube1_geom = suic_ode_create_box_geom(space, 1.000000, 1.000000, 1.000000); + suic_ode_geom_set_body(cube1_geom, cube1_body); + void* cube2_body = suic_ode_body_create(world); + suic_ode_body_set_position(cube2_body, 5.000000, 1.000000, -3.000000); + suic_ode_body_set_box_mass(cube2_body, 1.000000, 1.000000, 1.000000, 1.000000); + void* cube2_geom = suic_ode_create_box_geom(space, 1.000000, 1.000000, 1.000000); + suic_ode_geom_set_body(cube2_geom, cube2_body); + void* cube3_body = suic_ode_body_create(world); + suic_ode_body_set_position(cube3_body, -5.000000, 1.000000, -3.000000); + suic_ode_body_set_box_mass(cube3_body, 1.000000, 1.000000, 1.000000, 1.000000); + void* cube3_geom = suic_ode_create_box_geom(space, 1.000000, 1.000000, 1.000000); + suic_ode_geom_set_body(cube3_geom, cube3_body); + float forward_x = 0.000000; + float forward_y = 0.000000; + float forward_z = -1.000000; + float right_x = 1.000000; + float right_y = 0.000000; + float right_z = 0.000000; + float camera_x = 0.000000; + float camera_y = 2.000000; + float camera_z = 0.000000; + float target_x = 0.000000; + float target_y = 2.000000; + float target_z = -5.000000; + float yaw = 0.000000; + float pitch = 0.000000; + float mouse_sensitivity = 0.003000; + float cube1_x = 0.000000; + float cube1_y = 0.000000; + float cube1_z = 0.000000; + float cube2_x = 0.000000; + float cube2_y = 0.000000; + float cube2_z = 0.000000; + float cube3_x = 0.000000; + float cube3_y = 0.000000; + float cube3_z = 0.000000; + float player_x = 0.000000; + float player_y = 2.000000; + float player_z = 0.000000; + while ((suic_window_should_close() == false)) { + float delta_time = 0.016660; + float move_speed = 5.000000; + float target_vx = 0.000000; + float target_vz = 0.000000; + if ((suic_is_key_down(KEY_W) != 0)) { + target_vx = (target_vx + (forward_x * move_speed)); + target_vz = (target_vz + (forward_z * move_speed)); + } + if ((suic_is_key_down(KEY_S) != 0)) { + target_vx = (target_vx - (forward_x * move_speed)); + target_vz = (target_vz - (forward_z * move_speed)); + } + if ((suic_is_key_down(KEY_D) != 0)) { + target_vx = (target_vx + (right_x * move_speed)); + target_vz = (target_vz + (right_z * move_speed)); + } + if ((suic_is_key_down(KEY_A) != 0)) { + target_vx = (target_vx - (right_x * move_speed)); + target_vz = (target_vz - (right_z * move_speed)); + } + float current_vx = 0.000000; + float current_vy = 0.000000; + float current_vz = 0.000000; + suic_ode_body_get_linear_vel(player_body, ¤t_vx, ¤t_vy, ¤t_vz); + if ((suic_is_jump_pressed() != 0)) { + float dummy_x = 0.000000; + float current_y = 0.000000; + float dummy_z = 0.000000; + suic_ode_body_get_position(player_body, &dummy_x, ¤t_y, &dummy_z); + if ((current_y <= 1.300000)) { + current_vy = 8.000000; + } + } + suic_ode_body_set_linear_vel(player_body, target_vx, current_vy, target_vz); + suic_ode_body_get_position(player_body, &player_x, &player_y, &player_z); + if (((suic_is_key_pressed(KEY_EQUAL) != 0) || (suic_is_key_pressed(KEY_KP_ADD) != 0))) { + mouse_sensitivity = (mouse_sensitivity + 0.001000); + } + if (((suic_is_key_pressed(KEY_MINUS) != 0) || (suic_is_key_pressed(KEY_KP_SUBTRACT) != 0))) { + mouse_sensitivity = (mouse_sensitivity - 0.001000); + if ((mouse_sensitivity < 0.001000)) { + mouse_sensitivity = 0.001000; + } + } + if ((suic_is_key_pressed(KEY_F1) != 0)) { + suic_enable_cursor(); + } + float mouse_delta_x = suic_get_mouse_delta_x(); + float mouse_delta_y = suic_get_mouse_delta_y(); + yaw = (yaw + (mouse_delta_x * mouse_sensitivity)); + pitch = (pitch - (mouse_delta_y * mouse_sensitivity)); + if ((pitch > 1.500000)) { + pitch = 1.500000; + } + if ((pitch < -1.500000)) { + pitch = -1.500000; + } + suic_ode_space_collide(world, space, contactgroup); + suic_ode_world_step(world, delta_time); + suic_ode_joint_group_empty(contactgroup); + float cos_yaw = cos(yaw); + float sin_yaw = sin(yaw); + float cos_pitch = cos(pitch); + float sin_pitch = sin(pitch); + forward_x = sin_yaw; + forward_y = sin_pitch; + forward_z = -cos_yaw; + right_x = cos_yaw; + right_y = 0.000000; + right_z = sin_yaw; + camera_x = (player_x + (forward_x * 0.500000)); + camera_y = (player_y + 0.900000); + camera_z = (player_z + (forward_z * 0.500000)); + target_x = (player_x + (forward_x * 5.000000)); + target_y = (player_y + (forward_y * 5.000000)); + target_z = (player_z + (forward_z * 5.000000)); + suic_ode_body_get_position(cube1_body, &cube1_x, &cube1_y, &cube1_z); + suic_ode_body_get_position(cube2_body, &cube2_x, &cube2_y, &cube2_z); + suic_ode_body_get_position(cube3_body, &cube3_x, &cube3_y, &cube3_z); + suic_begin_drawing(); + suic_clear_background(135, 206, 235, 255); + suic_begin_mode3d(camera_x, camera_y, camera_z, target_x, target_y, target_z, 0.000000, 1.000000, 0.000000, 45.000000, 0); + suic_draw_cube(0.000000, -1.000000, 0.000000, 100.000000, 0.100000, 100.000000, 34, 139, 34, 255); + suic_draw_cube(cube1_x, cube1_y, cube1_z, 1.000000, 1.000000, 1.000000, 255, 0, 0, 255); + suic_draw_cube_wires(cube1_x, cube1_y, cube1_z, 1.000000, 1.000000, 1.000000, 0, 0, 0, 255); + suic_draw_cube(cube2_x, cube2_y, cube2_z, 1.000000, 1.000000, 1.000000, 0, 255, 0, 255); + suic_draw_cube_wires(cube2_x, cube2_y, cube2_z, 1.000000, 1.000000, 1.000000, 0, 0, 0, 255); + suic_draw_cube(cube3_x, cube3_y, cube3_z, 1.000000, 1.000000, 1.000000, 0, 0, 255, 255); + suic_draw_cube_wires(cube3_x, cube3_y, cube3_z, 1.000000, 1.000000, 1.000000, 0, 0, 0, 255); + suic_rl_push_matrix(); + suic_rl_translate_f(player_x, player_y, player_z); + suic_rl_rotate_f(((-yaw * 180.000000) / 3.141590), 0.000000, 1.000000, 0.000000); + suic_draw_cube(0.000000, 0.000000, 0.000000, 0.800000, 1.600000, 0.800000, 255, 255, 0, 255); + suic_draw_cube_wires(0.000000, 0.000000, 0.000000, 0.800000, 1.600000, 0.800000, 0, 0, 0, 255); + suic_rl_pop_matrix(); + suic_end_mode3d(); + suic_end_drawing(); + } + suic_ode_geom_destroy(cube3_geom); + suic_ode_body_destroy(cube3_body); + suic_ode_geom_destroy(cube2_geom); + suic_ode_body_destroy(cube2_body); + suic_ode_geom_destroy(cube1_geom); + suic_ode_body_destroy(cube1_body); + suic_ode_geom_destroy(player_geom); + suic_ode_body_destroy(player_body); + suic_ode_geom_destroy(ground_geom); + suic_ode_joint_group_destroy(contactgroup); + suic_ode_space_destroy(space); + suic_ode_world_destroy(world); + suic_ode_close(); + suic_close_window(); + return 0; +} + +int main(int argc, char* argv[]) { + // Initialize GC + gc_init(); + // init globals + // init event loop + int result = suic_main(); + // Shutdown GC + gc_shutdown(); + return result; +} + diff --git a/tests/fps_game.o b/tests/fps_game.o new file mode 100755 index 0000000..3b3e29a Binary files /dev/null and b/tests/fps_game.o differ diff --git a/tests/fps_game.sui b/tests/fps_game.sui new file mode 100644 index 0000000..4ca9474 --- /dev/null +++ b/tests/fps_game.sui @@ -0,0 +1,271 @@ +# FPS-Style 3D Game with Sui Language +# Demonstrates WASD movement, mouse look, jumping, sprinting, and physics-based gameplay + +fn main() -> int do + # Enable antialiasing + enable_msaa_4x() + + # Initialize graphics + init_window(1280, 720, "Sui FPS Game - WASD to move, Mouse to look, SPACE to jump, SHIFT to sprint") + defer close_window() + set_target_fps(60) + + # Hide cursor and capture mouse for FPS controls + disable_cursor() + + # Initialize physics + ode_init() + defer ode_close() + + # Create physics world + let world = ode_world_create() + defer ode_world_destroy(world) + let null_space = 0 as *() + let space = ode_simple_space_create(null_space) + defer ode_space_destroy(space) + + # Set gravity + ode_world_set_gravity(world, 0.0, -9.81, 0.0) + + # Create contact joint group + let contactgroup = ode_joint_group_create(0) + defer ode_joint_group_destroy(contactgroup) + + # Create ground plane + let ground_geom = ode_create_plane_geom(space, 0.0, 1.0, 0.0, 0.0) + defer ode_geom_destroy(ground_geom) + + # Create player physics body (capsule shape) + let player_body = ode_body_create(world) + defer ode_body_destroy(player_body) + ode_body_set_position(player_body, 0.0, 2.0, 0.0) + + # Create box geometry for player (0.8 x 1.6 x 0.8) + let player_geom = ode_create_box_geom(space, 0.8, 1.6, 0.8) + defer ode_geom_destroy(player_geom) + ode_geom_set_body(player_geom, player_body) + + # Set player mass (box with density 1.0) + ode_body_set_box_mass(player_body, 1.0, 0.8, 1.6, 0.8) + + # Create cube physics bodies + let cube1_body = ode_body_create(world) + defer ode_body_destroy(cube1_body) + ode_body_set_position(cube1_body, 0.0, 1.0, -5.0) + ode_body_set_box_mass(cube1_body, 1.0, 1.0, 1.0, 1.0) + let cube1_geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) + defer ode_geom_destroy(cube1_geom) + ode_geom_set_body(cube1_geom, cube1_body) + + let cube2_body = ode_body_create(world) + defer ode_body_destroy(cube2_body) + ode_body_set_position(cube2_body, 5.0, 1.0, -3.0) + ode_body_set_box_mass(cube2_body, 1.0, 1.0, 1.0, 1.0) + let cube2_geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) + defer ode_geom_destroy(cube2_geom) + ode_geom_set_body(cube2_geom, cube2_body) + + let cube3_body = ode_body_create(world) + defer ode_body_destroy(cube3_body) + ode_body_set_position(cube3_body, -5.0, 1.0, -3.0) + ode_body_set_box_mass(cube3_body, 1.0, 1.0, 1.0, 1.0) + let cube3_geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) + defer ode_geom_destroy(cube3_geom) + ode_geom_set_body(cube3_geom, cube3_body) + + # Set player movement direction (looking down -Z axis) + let mut forward_x = 0.0 + let mut forward_y = 0.0 + let mut forward_z = -1.0 + let mut right_x = 1.0 + let mut right_y = 0.0 + let mut right_z = 0.0 + + # ==== CAMERA AND PLAYER STATE ==== + let mut camera_x = 0.0 + let mut camera_y = 2.0 + let mut camera_z = 0.0 + let mut target_x = 0.0 + let mut target_y = 2.0 + let mut target_z = -5.0 + + # Mouse look state + let mut yaw = 0.0 + let mut pitch = 0.0 + let mut mouse_sensitivity = 0.003 + + # Cube position variables + let mut cube1_x = 0.0 + let mut cube1_y = 0.0 + let mut cube1_z = 0.0 + let mut cube2_x = 0.0 + let mut cube2_y = 0.0 + let mut cube2_z = 0.0 + let mut cube3_x = 0.0 + let mut cube3_y = 0.0 + let mut cube3_z = 0.0 + + # Player position (initial values) + let mut player_x = 0.0 + let mut player_y = 2.0 + let mut player_z = 0.0 + + # Main game loop + while window_should_close() == false do + # Input handling + let delta_time = 0.01666 # ~60 FPS + + # WASD movement - set velocities on physics body + let move_speed = 5.0 # Velocity applied to body + let mut target_vx = 0.0 + let mut target_vz = 0.0 + + if is_key_down(KEY_W) != 0 do + target_vx = target_vx + forward_x * move_speed + target_vz = target_vz + forward_z * move_speed + end + + if is_key_down(KEY_S) != 0 do + target_vx = target_vx - forward_x * move_speed + target_vz = target_vz - forward_z * move_speed + end + + if is_key_down(KEY_D) != 0 do + target_vx = target_vx + right_x * move_speed + target_vz = target_vz + right_z * move_speed + end + + if is_key_down(KEY_A) != 0 do + target_vx = target_vx - right_x * move_speed + target_vz = target_vz - right_z * move_speed + end + + # Get current velocity for Y (preserve gravity) + let mut current_vx = 0.0 + let mut current_vy = 0.0 + let mut current_vz = 0.0 + ode_body_get_linear_vel(player_body, ¤t_vx, ¤t_vy, ¤t_vz) + + # Jump - set upward velocity + if is_jump_pressed() != 0 do + # Get current position to check if on ground + let mut dummy_x = 0.0 + let mut current_y = 0.0 + let mut dummy_z = 0.0 + ode_body_get_position(player_body, &dummy_x, ¤t_y, &dummy_z) + if current_y <= 1.3 do # On ground (box bottom is at y - 0.8 from center) + current_vy = 8.0 # Jump velocity + end + end + + # Set new velocity (keep Y velocity for gravity/jumping) + ode_body_set_linear_vel(player_body, target_vx, current_vy, target_vz) + + # Get player position from physics body + ode_body_get_position(player_body, &player_x, &player_y, &player_z) + + # Adjust mouse sensitivity + if is_key_pressed(KEY_EQUAL) != 0 or is_key_pressed(KEY_KP_ADD) != 0 do # + key + mouse_sensitivity = mouse_sensitivity + 0.001 + end + if is_key_pressed(KEY_MINUS) != 0 or is_key_pressed(KEY_KP_SUBTRACT) != 0 do # - key + mouse_sensitivity = mouse_sensitivity - 0.001 + if mouse_sensitivity < 0.001 do + mouse_sensitivity = 0.001 # Minimum sensitivity + end + end + + # Show cursor with F1 (useful for debugging) + if is_key_pressed(KEY_F1) != 0 do + enable_cursor() + end + + # Mouse look + let mouse_delta_x = get_mouse_delta_x() + let mouse_delta_y = get_mouse_delta_y() + + yaw = yaw + (mouse_delta_x * mouse_sensitivity) + pitch = pitch - (mouse_delta_y * mouse_sensitivity) # Negate Y for natural FPS controls + + # Clamp pitch to prevent flipping + if pitch > 1.5 do + pitch = 1.5 + end + if pitch < -1.5 do + pitch = -1.5 + end + + # Update physics (just for cubes) + ode_space_collide(world, space, contactgroup) + ode_world_step(world, delta_time) + ode_joint_group_empty(contactgroup) + + # Calculate camera direction from yaw and pitch + let cos_yaw = cos(yaw) + let sin_yaw = sin(yaw) + let cos_pitch = cos(pitch) + let sin_pitch = sin(pitch) + + # Update forward and right vectors + forward_x = sin_yaw + forward_y = sin_pitch + forward_z = -cos_yaw + + right_x = cos_yaw + right_y = 0.0 + right_z = sin_yaw + + # Direction vectors are updated above + + # Camera follows player (at eye position, slightly in front) + camera_x = player_x + forward_x * 0.5 # Offset forward + camera_y = player_y + 0.9 # Eye height + camera_z = player_z + forward_z * 0.5 # Offset forward + + # Camera looks where player is looking + target_x = player_x + forward_x * 5.0 + target_y = player_y + forward_y * 5.0 + target_z = player_z + forward_z * 5.0 + + # Player rotation is handled visually during rendering + + # Get cube positions from physics bodies + ode_body_get_position(cube1_body, &cube1_x, &cube1_y, &cube1_z) + ode_body_get_position(cube2_body, &cube2_x, &cube2_y, &cube2_z) + ode_body_get_position(cube3_body, &cube3_x, &cube3_y, &cube3_z) + + # ==== RENDERING ==== + begin_drawing() + clear_background(135, 206, 235, 255) # Sky blue + + # 3D mode with calculated camera + begin_mode3d(camera_x, camera_y, camera_z, target_x, target_y, target_z, 0.0, 1.0, 0.0, 45.0, 0) + + # Draw ground plane + draw_cube(0.0, -1.0, 0.0, 100.0, 0.1, 100.0, 34, 139, 34, 255) # Green ground + + # Draw cubes + draw_cube(cube1_x, cube1_y, cube1_z, 1.0, 1.0, 1.0, 255, 0, 0, 255) # Red + draw_cube_wires(cube1_x, cube1_y, cube1_z, 1.0, 1.0, 1.0, 0, 0, 0, 255) + + draw_cube(cube2_x, cube2_y, cube2_z, 1.0, 1.0, 1.0, 0, 255, 0, 255) # Green + draw_cube_wires(cube2_x, cube2_y, cube2_z, 1.0, 1.0, 1.0, 0, 0, 0, 255) + + draw_cube(cube3_x, cube3_y, cube3_z, 1.0, 1.0, 1.0, 0, 0, 255, 255) # Blue + draw_cube_wires(cube3_x, cube3_y, cube3_z, 1.0, 1.0, 1.0, 0, 0, 0, 255) + + # Draw player model with rotation (yellow cube to represent the player) + rl_push_matrix() + rl_translate_f(player_x, player_y, player_z) + rl_rotate_f(-yaw * 180.0 / 3.14159, 0.0, 1.0, 0.0) # Convert radians to degrees for Y-axis rotation, negate for correct direction + draw_cube(0.0, 0.0, 0.0, 0.8, 1.6, 0.8, 255, 255, 0, 255) # Yellow player + draw_cube_wires(0.0, 0.0, 0.0, 0.8, 1.6, 0.8, 0, 0, 0, 255) + rl_pop_matrix() + + end_mode3d() + + end_drawing() + end + + 0 +end diff --git a/tests/functions.c b/tests/functions.c new file mode 100644 index 0000000..08378bb --- /dev/null +++ b/tests/functions.c @@ -0,0 +1,52 @@ +#include "../libsuicmez/libsuicmez.h" +#include +#include +#include +#include + +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); + +// Helper for allocating arrays +static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) { + void* ptr = gc_alloc(type, elem_size * len); + if (init_data) memcpy(ptr, init_data, elem_size * len); + return ptr; +} + +// Helper for allocating structs +static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) { + void* ptr = gc_alloc(type, size); + if (init_data) memcpy(ptr, init_data, size); + return ptr; +} + + + + +int add(int x, int y); +int suic_main(void); + + +int add(int x, int y) { + return (x + y); +} + +int suic_main(void) { + int sum = add(5, 3); + struct T id = identity(42); + return sum; +} + +int main(int argc, char* argv[]) { + // Initialize GC + gc_init(); + // init globals + // init event loop + int result = suic_main(); + // Shutdown GC + gc_shutdown(); + return result; +} + diff --git a/tests/game_3d_improved.c b/tests/game_3d_improved.c new file mode 100644 index 0000000..6ab3df2 --- /dev/null +++ b/tests/game_3d_improved.c @@ -0,0 +1,89 @@ +#include "../libsuicmez/libsuicmez.h" +#include +#include +#include +#include + +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); + +// Helper for allocating arrays +static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) { + void* ptr = gc_alloc(type, elem_size * len); + if (init_data) memcpy(ptr, init_data, elem_size * len); + return ptr; +} + +// Helper for allocating structs +static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) { + void* ptr = gc_alloc(type, size); + if (init_data) memcpy(ptr, init_data, size); + return ptr; +} + + + + +int suic_main(void); + + +int suic_main(void) { + suic_init_window(800, 600, suic_alloc_array(NULL, sizeof(char), 27, "3D Physics Game - Improved")); + suic_set_target_fps(60); + suic_ode_init(); + void* world = suic_ode_world_create(); + void* null_space = (struct unit**) 0; + void* space = suic_ode_simple_space_create(null_space); + suic_ode_world_set_gravity(world, 0.000000, -9.810000, 0.000000); + void* contactgroup = suic_ode_joint_group_create(0); + void* body = suic_ode_body_create(world); + suic_ode_body_set_box_mass(body, 1.000000, 1.000000, 1.000000, 1.000000); + suic_ode_body_set_position(body, 0.000000, 5.000000, 0.000000); + void* geom = suic_ode_create_box_geom(space, 1.000000, 1.000000, 1.000000); + suic_ode_geom_set_body(geom, body); + void* ground_geom = suic_ode_create_plane_geom(space, 0.000000, 1.000000, 0.000000, 0.000000); + float camera_pos_x = 0.000000; + float camera_pos_y = 2.000000; + float camera_pos_z = 10.000000; + float cube_x = 0.000000; + float cube_y = 0.000000; + float cube_z = 0.000000; + int frame_count = 0; + while ((suic_window_should_close() == false)) { + suic_ode_space_collide(world, space, contactgroup); + suic_ode_world_step(world, (1.000000 / 60.000000)); + suic_ode_joint_group_empty(contactgroup); + suic_ode_body_get_position(body, &cube_x, &cube_y, &cube_z); + suic_begin_drawing(); + suic_clear_background(135, 206, 235, 255); + suic_begin_mode3d(camera_pos_x, camera_pos_y, camera_pos_z, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 45.000000, 0); + suic_draw_cube(0.000000, -1.000000, 0.000000, 20.000000, 0.100000, 20.000000, 34, 139, 34, 255); + suic_draw_cube(cube_x, cube_y, cube_z, 1.000000, 1.000000, 1.000000, 255, 0, 0, 255); + suic_draw_cube_wires(cube_x, cube_y, cube_z, 1.000000, 1.000000, 1.000000, 0, 0, 0, 255); + suic_end_mode3d(); + suic_end_drawing(); + frame_count = (frame_count + 1); + } + suic_ode_geom_destroy(ground_geom); + suic_ode_geom_destroy(geom); + suic_ode_body_destroy(body); + suic_ode_joint_group_destroy(contactgroup); + suic_ode_space_destroy(space); + suic_ode_world_destroy(world); + suic_ode_close(); + suic_close_window(); + return 0; +} + +int main(int argc, char* argv[]) { + // Initialize GC + gc_init(); + // init globals + // init event loop + int result = suic_main(); + // Shutdown GC + gc_shutdown(); + return result; +} + diff --git a/tests/game_3d_improved.o b/tests/game_3d_improved.o new file mode 100755 index 0000000..e857ff8 Binary files /dev/null and b/tests/game_3d_improved.o differ diff --git a/tests/ode_test.c b/tests/ode_test.c new file mode 100644 index 0000000..0204442 --- /dev/null +++ b/tests/ode_test.c @@ -0,0 +1,51 @@ +#include "../libsuicmez/libsuicmez.h" +#include +#include +#include +#include + +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); + +// Helper for allocating arrays +static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) { + void* ptr = gc_alloc(type, elem_size * len); + if (init_data) memcpy(ptr, init_data, elem_size * len); + return ptr; +} + +// Helper for allocating structs +static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) { + void* ptr = gc_alloc(type, size); + if (init_data) memcpy(ptr, init_data, size); + return ptr; +} + + + + +int suic_main(void); + + +int suic_main(void) { + suic_ode_init(); + void* world = suic_ode_world_create(); + suic_ode_world_set_gravity(world, 0.000000, -9.810000, 0.000000); + suic_ode_world_step(world, 0.016000); + suic_ode_world_destroy(world); + suic_ode_close(); + return 0; +} + +int main(int argc, char* argv[]) { + // Initialize GC + gc_init(); + // init globals + // init event loop + int result = suic_main(); + // Shutdown GC + gc_shutdown(); + return result; +} + diff --git a/tests/ode_test.o b/tests/ode_test.o new file mode 100755 index 0000000..0589469 Binary files /dev/null and b/tests/ode_test.o differ diff --git a/tests/ode_voxel_example.c b/tests/ode_voxel_example.c new file mode 100644 index 0000000..796d3ed --- /dev/null +++ b/tests/ode_voxel_example.c @@ -0,0 +1,64 @@ +#include "../libsuicmez/libsuicmez.h" +#include +#include +#include +#include + +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); + +// Helper for allocating arrays +static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) { + void* ptr = gc_alloc(type, elem_size * len); + if (init_data) memcpy(ptr, init_data, elem_size * len); + return ptr; +} + +// Helper for allocating structs +static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) { + void* ptr = gc_alloc(type, size); + if (init_data) memcpy(ptr, init_data, size); + return ptr; +} + + + + +int suic_main(void); + + +int suic_main(void) { + suic_ode_init(); + void* world = suic_ode_world_create(); + void* space = suic_ode_simple_space_create(NULL); + suic_ode_world_set_gravity(world, 0.000000, -9.810000, 0.000000); + void* body = suic_ode_body_create(world); + suic_ode_body_set_box_mass(body, 1.000000, 1.000000, 1.000000, 1.000000); + suic_ode_body_set_position(body, 0.000000, 5.000000, 0.000000); + void* geom = suic_ode_create_box_geom(space, 1.000000, 1.000000, 1.000000); + suic_ode_geom_set_body(geom, body); + int i = 0; + while ((i < 10)) { + suic_ode_world_step(world, 0.016000); + i = (i + 1); + } + suic_ode_geom_destroy(geom); + suic_ode_body_destroy(body); + suic_ode_space_destroy(space); + suic_ode_world_destroy(world); + suic_ode_close(); + return 0; +} + +int main(int argc, char* argv[]) { + // Initialize GC + gc_init(); + // init globals + // init event loop + int result = suic_main(); + // Shutdown GC + gc_shutdown(); + return result; +} + diff --git a/tests/ode_voxel_example.o b/tests/ode_voxel_example.o new file mode 100755 index 0000000..850967d Binary files /dev/null and b/tests/ode_voxel_example.o differ diff --git a/tests/structs.c b/tests/structs.c new file mode 100644 index 0000000..54d0ea1 --- /dev/null +++ b/tests/structs.c @@ -0,0 +1,68 @@ +#include "../libsuicmez/libsuicmez.h" +#include +#include +#include +#include + +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); + +// Helper for allocating arrays +static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) { + void* ptr = gc_alloc(type, elem_size * len); + if (init_data) memcpy(ptr, init_data, elem_size * len); + return ptr; +} + +// Helper for allocating structs +static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) { + void* ptr = gc_alloc(type, size); + if (init_data) memcpy(ptr, init_data, size); + return ptr; +} + + +struct Point { + int x; + int y; +}; +struct Person { + char* name; + int age; +}; + +static const uint8_t sui_bitmap_Point[] = { 0, 0 }; +static const TypeInfo sui_typeinfo_Point = { + .field_count = 2, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Point +}; +static const uint8_t sui_bitmap_Person[] = { 1, 0 }; +static const TypeInfo sui_typeinfo_Person = { + .field_count = 2, + .pointer_count = 1, + .pointer_bitmap = sui_bitmap_Person +}; + +int suic_main(void); + + +int suic_main(void) { + struct Point* p = suic_alloc_struct(&sui_typeinfo_Point, sizeof(struct Point), &(struct Point){ .x = 5, .y = 10 }); + struct Person* person = suic_alloc_struct(&sui_typeinfo_Person, sizeof(struct Person), &(struct Person){ .name = suic_alloc_array(NULL, sizeof(char), 6, "Alice"), .age = 30 }); + int _ = ((*p).x + (*person).age); + return 0; +} + +int main(int argc, char* argv[]) { + // Initialize GC + gc_init(); + // init globals + // init event loop + int result = suic_main(); + // Shutdown GC + gc_shutdown(); + return result; +} + diff --git a/tests/structs.o b/tests/structs.o new file mode 100755 index 0000000..13e75a4 Binary files /dev/null and b/tests/structs.o differ