added anti aliasing. new fps game

This commit is contained in:
Masashi 2025-12-17 15:38:06 +05:30
commit 7b73c86113
40 changed files with 2386 additions and 564 deletions

View file

@ -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!</content>
<parameter name="filePath">ODE_INTEGRATION.md

View file

@ -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 <sui_source.sui> [output_name]"
echo "Usage: ./compile.sh [--debug] <sui_source.sui> [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"

View file

@ -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 <sui_source.sui> [program_args...]"
echo "Usage: ./compile_and_run.sh [--debug] <sui_source.sui> [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

BIN
fishsoup/main Executable file

Binary file not shown.

141
fishsoup/main.c Normal file
View file

@ -0,0 +1,141 @@
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
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;
}

BIN
fishsoup/main.o Executable file

Binary file not shown.

158
fishsoup/main.sui Normal file
View file

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

BIN
fps_game Executable file

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,10 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
// 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

View file

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

View file

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

View file

@ -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<CExpr>,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct CStructDecl {
pub name: String,
pub fields: Vec<CVarDecl>,
}
#[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<Vec<CStmt>>,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum CExpr {
IntLit(i64),
FloatLit(f64),
@ -99,7 +99,7 @@ pub enum CExpr {
Ternary(Box<CExpr>, Box<CExpr>, Box<CExpr>), // 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<CStmt>),
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum CToplevel {
StructDecl(CStructDecl),
FuncDecl(CFuncDecl),

View file

@ -179,6 +179,7 @@ pub fn convert_to_c_type(name: &String) -> Result<CType, String> {
"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
}
}

View file

@ -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)?))]),
}
}

View file

@ -41,10 +41,12 @@ pub struct Transpiler {
stmt_transpiler: StatementsTranspiler,
array_types: std::collections::HashSet<String>, // Track array types we need to generate
has_main: bool, // Track if we found a main function
typeinfo_map: std::collections::HashMap<String, Vec<u8>>, // 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<u8> {
fields
.iter()
.map(|field| if Self::is_pointer_type(&field.ty) { 1u8 } else { 0u8 })
.collect()
}
pub fn transpile_program(&mut self, nodes: &[TypedASTNode]) -> Result<String, String> {
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::<Vec<_>>()
.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(", ")
)

View file

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

View file

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

View file

@ -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<String>,
}
@ -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))?;

View file

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

46
test_player.c Normal file
View file

@ -0,0 +1,46 @@
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
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;
}

1
test_player.sui Normal file
View file

@ -0,0 +1 @@
fn main() -> int do let p = player_controller_create(0.0, 1.0, 2.0); 0 end

BIN
test_window Executable file

Binary file not shown.

53
test_window.c Normal file
View file

@ -0,0 +1,53 @@
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
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;
}

1
test_window.sui Normal file
View file

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

49
tests/basic_types.c Normal file
View file

@ -0,0 +1,49 @@
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
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;
}

BIN
tests/basic_types.o Executable file

Binary file not shown.

50
tests/control_flow.c Normal file
View file

@ -0,0 +1,50 @@
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
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;
}

216
tests/fps_game.c Normal file
View file

@ -0,0 +1,216 @@
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
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, &current_vx, &current_vy, &current_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, &current_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;
}

BIN
tests/fps_game.o Executable file

Binary file not shown.

271
tests/fps_game.sui Normal file
View file

@ -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, &current_vx, &current_vy, &current_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, &current_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

52
tests/functions.c Normal file
View file

@ -0,0 +1,52 @@
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
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;
}

89
tests/game_3d_improved.c Normal file
View file

@ -0,0 +1,89 @@
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
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;
}

BIN
tests/game_3d_improved.o Executable file

Binary file not shown.

51
tests/ode_test.c Normal file
View file

@ -0,0 +1,51 @@
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
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;
}

BIN
tests/ode_test.o Executable file

Binary file not shown.

64
tests/ode_voxel_example.c Normal file
View file

@ -0,0 +1,64 @@
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
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;
}

BIN
tests/ode_voxel_example.o Executable file

Binary file not shown.

68
tests/structs.c Normal file
View file

@ -0,0 +1,68 @@
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
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;
}

BIN
tests/structs.o Executable file

Binary file not shown.