diff --git a/game/client b/game/client index 989692a..673d436 100755 Binary files a/game/client and b/game/client differ diff --git a/game/client.c b/game/client.c index eb6df46..a5a5599 100644 --- a/game/client.c +++ b/game/client.c @@ -1,1174 +1,344 @@ -#include "raylib.h" -#include -#include +#include "libsuicmez/libsuicmez.h" #include +#include +#include #include -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#include -#pragma comment(lib, "ws2_32.lib") -typedef int socklen_t; -#define CLOSESOCK closesocket -#else -#include -#include -#include -#include -#include -#define CLOSESOCK close -#endif +void* gc_alloc(const TypeInfo* type, size_t size); +void gc_init(void); +void gc_shutdown(void); -#define PROTOCOL_VERSION 67 -#define SERVER_PORT 27015 -#define MAX_PLAYERS 16 -#define USERNAME_MAX 16 - -#define WEAPON_PISTOL 0 -#define WEAPON_RIFLE 1 - -#define ITEM_NONE 0 -#define ITEM_MEDKIT 1 -#define ITEM_AMMO_PISTOL 2 -#define ITEM_AMMO_RIFLE 3 - -#define MAX_ITEMS 64 - -#define BTN_RELOAD (1u << 0) -#define BTN_SWITCH_PISTOL (1u << 1) -#define BTN_SWITCH_RIFLE (1u << 2) -#define BTN_PICK (1u << 3) -#define BTN_USE_MEDKIT (1u << 4) -#define BTN_JUMP (1u << 5) - -typedef struct { - Vector3 direction; // Normalized light direction - Vector3 color; // RGB color (0-1 range) - float intensity; // Light intensity multiplier - float ambientIntensity; // Ambient light strength - float shadowBias; // Shadow bias to prevent z-fighting - float shadowIntensity; // How dark shadows are (0-1) -} DirectionalLight; - -typedef struct { - Shader shader; - int locViewPos; - int locLightDir; - int locLightColor; - int locLightIntensity; - int locAmbientIntensity; - int locTerrainColor; -} TerrainShader; - -static TerrainShader load_terrain_shader(void) { - TerrainShader ts = {0}; - ts.shader = LoadShader("terrain.vs", "terrain.fs"); - - // Get uniform locations - ts.locViewPos = GetShaderLocation(ts.shader, "viewPos"); - ts.locLightDir = GetShaderLocation(ts.shader, "lightDir"); - ts.locLightColor = GetShaderLocation(ts.shader, "lightColor"); - ts.locLightIntensity = GetShaderLocation(ts.shader, "lightIntensity"); - ts.locAmbientIntensity = GetShaderLocation(ts.shader, "ambientIntensity"); - ts.locTerrainColor = GetShaderLocation(ts.shader, "terrainColor"); - - return ts; +// 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; } -static void unload_terrain_shader(TerrainShader *ts) { - if (ts && ts->shader.id != 0) { - UnloadShader(ts->shader); - ts->shader.id = 0; - } +// 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; } -static const uint8_t perm[512] = { - 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, - 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, - 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, - 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, - 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, - 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, - 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, - 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, - 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, - 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, - 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, - 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, - 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, - 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, - 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, - 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, - 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, - 180, 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, - 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, - 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, - 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, - 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, - 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, - 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, - 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, - 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, - 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, - 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, - 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, - 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, - 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, - 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, - 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, - 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, - 156, 180}; -static float grad2(int hash, float x, float y) { - int h = hash & 7; - float u = h < 4 ? x : y; - float v = h < 4 ? y : x; - return ((h & 1) ? -u : u) + ((h & 2) ? -2.0f * v : 2.0f * v); +struct DirectionalLight { + struct Vector3* direction; + struct Vector3* color; + float intensity; + float ambientIntensity; + float shadowBias; + float shadowIntensity; +}; +struct TerrainShader { + int shader; + int locViewPos; + int locLightDir; + int locLightColor; + int locLightIntensity; + int locAmbientIntensity; + int locTerrainColor; +}; +struct MsgType_MSG_HELLO { +}; +struct MsgType_MSG_WELCOME { +}; +struct MsgType_MSG_INPUT { +}; +struct MsgType_MSG_SNAPSHOT { +}; +struct MsgType_MSG_SHOOT { +}; +struct MsgType_MSG_ITEMS { +}; +struct MsgType_MSG_ROOM_STATE { +}; +struct MsgType_union { + struct MsgType_MSG_HELLO msg_hello; + struct MsgType_MSG_WELCOME msg_welcome; + struct MsgType_MSG_INPUT msg_input; + struct MsgType_MSG_SNAPSHOT msg_snapshot; + struct MsgType_MSG_SHOOT msg_shoot; + struct MsgType_MSG_ITEMS msg_items; + struct MsgType_MSG_ROOM_STATE msg_room_state; +}; +struct MsgType { + int discriminant; + struct MsgType_union data; +}; +struct MsgHello { + uint8_t type; + struct u32* protocol; + char* username; +}; +struct MsgWelcome { + uint8_t type; + uint8_t playerId; + struct u32* serverTick; +}; +struct MsgInput { + uint8_t type; + uint8_t playerId; + struct u32* clientTick; + float moveX; + float moveZ; + float yaw; + float pitch; + uint8_t buttons; +}; +struct MsgShoot { + uint8_t type; + uint8_t playerId; + struct u32* clientTick; +}; +struct PlayerStateNet { + uint8_t id; + uint8_t alive; + struct i16* hp; + float x; + float y; + float z; + float yaw; + float pitch; + uint8_t weapon; + struct i16* pistolMag; + struct i16* rifleMag; + struct i16* pistolAmmo; + struct i16* rifleAmmo; + struct i16* medkits; + struct i16* reloadTimeLeft; + char* username; +}; +struct MsgSnapshot { + uint8_t type; + struct u32* serverTick; + uint8_t count; + struct PlayerStateNet** p; +}; +struct ItemNet { + struct u16* id; + uint8_t type; + struct i16* qty; + float x; + float y; + float z; +}; +struct MsgItems { + uint8_t type; + struct u32* serverTick; + uint8_t count; + struct ItemNet** items; +}; +struct MsgRoomState { + uint8_t type; + uint8_t state; + float countdownRemaining; + uint8_t winnerId; + char* winnerName; +}; +struct RemotePlayer { + int present; + int alive; + int hp; + struct Vector3* pos; + struct Vector3* prevPos; + float yaw; + float pitch; + uint8_t weapon; + struct i16* pistolMag; + struct i16* rifleMag; + struct i16* pistolAmmo; + struct i16* rifleAmmo; + struct i16* medkits; + struct i16* reloadTimeLeft; + char* username; +}; +struct WorldItem { + int present; + struct u16* id; + uint8_t type; + struct i16* qty; + struct Vector3* pos; +}; + +static const uint8_t sui_bitmap_DirectionalLight[] = { 1, 1, 0, 0, 0, 0 }; +static const TypeInfo sui_typeinfo_DirectionalLight = { + .field_count = 6, + .pointer_count = 2, + .pointer_bitmap = sui_bitmap_DirectionalLight +}; +static const uint8_t sui_bitmap_TerrainShader[] = { 0, 0, 0, 0, 0, 0, 0 }; +static const TypeInfo sui_typeinfo_TerrainShader = { + .field_count = 7, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_TerrainShader +}; +static const uint8_t sui_bitmap_MsgType_MSG_HELLO[] = { }; +static const TypeInfo sui_typeinfo_MsgType_MSG_HELLO = { + .field_count = 0, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_MsgType_MSG_HELLO +}; +static const uint8_t sui_bitmap_MsgType_MSG_WELCOME[] = { }; +static const TypeInfo sui_typeinfo_MsgType_MSG_WELCOME = { + .field_count = 0, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_MsgType_MSG_WELCOME +}; +static const uint8_t sui_bitmap_MsgType_MSG_INPUT[] = { }; +static const TypeInfo sui_typeinfo_MsgType_MSG_INPUT = { + .field_count = 0, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_MsgType_MSG_INPUT +}; +static const uint8_t sui_bitmap_MsgType_MSG_SNAPSHOT[] = { }; +static const TypeInfo sui_typeinfo_MsgType_MSG_SNAPSHOT = { + .field_count = 0, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_MsgType_MSG_SNAPSHOT +}; +static const uint8_t sui_bitmap_MsgType_MSG_SHOOT[] = { }; +static const TypeInfo sui_typeinfo_MsgType_MSG_SHOOT = { + .field_count = 0, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_MsgType_MSG_SHOOT +}; +static const uint8_t sui_bitmap_MsgType_MSG_ITEMS[] = { }; +static const TypeInfo sui_typeinfo_MsgType_MSG_ITEMS = { + .field_count = 0, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_MsgType_MSG_ITEMS +}; +static const uint8_t sui_bitmap_MsgType_MSG_ROOM_STATE[] = { }; +static const TypeInfo sui_typeinfo_MsgType_MSG_ROOM_STATE = { + .field_count = 0, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_MsgType_MSG_ROOM_STATE +}; +static const uint8_t sui_bitmap_MsgType_union[] = { 1, 1, 1, 1, 1, 1, 1 }; +static const TypeInfo sui_typeinfo_MsgType_union = { + .field_count = 7, + .pointer_count = 7, + .pointer_bitmap = sui_bitmap_MsgType_union +}; +static const uint8_t sui_bitmap_MsgType[] = { 0, 1 }; +static const TypeInfo sui_typeinfo_MsgType = { + .field_count = 2, + .pointer_count = 1, + .pointer_bitmap = sui_bitmap_MsgType +}; +static const uint8_t sui_bitmap_MsgHello[] = { 0, 1, 1 }; +static const TypeInfo sui_typeinfo_MsgHello = { + .field_count = 3, + .pointer_count = 2, + .pointer_bitmap = sui_bitmap_MsgHello +}; +static const uint8_t sui_bitmap_MsgWelcome[] = { 0, 0, 1 }; +static const TypeInfo sui_typeinfo_MsgWelcome = { + .field_count = 3, + .pointer_count = 1, + .pointer_bitmap = sui_bitmap_MsgWelcome +}; +static const uint8_t sui_bitmap_MsgInput[] = { 0, 0, 1, 0, 0, 0, 0, 0 }; +static const TypeInfo sui_typeinfo_MsgInput = { + .field_count = 8, + .pointer_count = 1, + .pointer_bitmap = sui_bitmap_MsgInput +}; +static const uint8_t sui_bitmap_MsgShoot[] = { 0, 0, 1 }; +static const TypeInfo sui_typeinfo_MsgShoot = { + .field_count = 3, + .pointer_count = 1, + .pointer_bitmap = sui_bitmap_MsgShoot +}; +static const uint8_t sui_bitmap_PlayerStateNet[] = { 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }; +static const TypeInfo sui_typeinfo_PlayerStateNet = { + .field_count = 16, + .pointer_count = 8, + .pointer_bitmap = sui_bitmap_PlayerStateNet +}; +static const uint8_t sui_bitmap_MsgSnapshot[] = { 0, 1, 0, 0 }; +static const TypeInfo sui_typeinfo_MsgSnapshot = { + .field_count = 4, + .pointer_count = 1, + .pointer_bitmap = sui_bitmap_MsgSnapshot +}; +static const uint8_t sui_bitmap_ItemNet[] = { 1, 0, 1, 0, 0, 0 }; +static const TypeInfo sui_typeinfo_ItemNet = { + .field_count = 6, + .pointer_count = 2, + .pointer_bitmap = sui_bitmap_ItemNet +}; +static const uint8_t sui_bitmap_MsgItems[] = { 0, 1, 0, 0 }; +static const TypeInfo sui_typeinfo_MsgItems = { + .field_count = 4, + .pointer_count = 1, + .pointer_bitmap = sui_bitmap_MsgItems +}; +static const uint8_t sui_bitmap_MsgRoomState[] = { 0, 0, 0, 0, 1 }; +static const TypeInfo sui_typeinfo_MsgRoomState = { + .field_count = 5, + .pointer_count = 1, + .pointer_bitmap = sui_bitmap_MsgRoomState +}; +static const uint8_t sui_bitmap_RemotePlayer[] = { 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }; +static const TypeInfo sui_typeinfo_RemotePlayer = { + .field_count = 15, + .pointer_count = 9, + .pointer_bitmap = sui_bitmap_RemotePlayer +}; +static const uint8_t sui_bitmap_WorldItem[] = { 0, 1, 0, 1, 1 }; +static const TypeInfo sui_typeinfo_WorldItem = { + .field_count = 5, + .pointer_count = 3, + .pointer_bitmap = sui_bitmap_WorldItem +}; + +char* item_name(uint8_t t); +struct Color* apply_directional_lighting(struct Color* baseColor, struct Vector3* normal, struct DirectionalLight* light); +int suic_main(void); + + +char* item_name(uint8_t t) { + return ((t == 1) ? suic_alloc_array(NULL, sizeof(char), 7, "Medkit") : ((t == 2) ? suic_alloc_array(NULL, sizeof(char), 12, "Pistol ammo") : ((t == 3) ? suic_alloc_array(NULL, sizeof(char), 11, "Rifle ammo") : suic_alloc_array(NULL, sizeof(char), 2, "-")))); } -static float simplex_noise_2d(float x, float y) { - const float F2 = 0.366025403f; - const float G2 = 0.211324865f; - float s = (x + y) * F2; - int i = (int)floorf(x + s); - int j = (int)floorf(y + s); - float t = (i + j) * G2; - float X0 = i - t, Y0 = j - t; - float x0 = x - X0, y0 = y - Y0; - int i1 = (x0 > y0) ? 1 : 0; - int j1 = (x0 > y0) ? 0 : 1; - float x1 = x0 - i1 + G2, y1 = y0 - j1 + G2; - float x2 = x0 - 1.0f + 2.0f * G2, y2 = y0 - 1.0f + 2.0f * G2; - int ii = i & 255, jj = j & 255; - float n0 = 0.0f, n1 = 0.0f, n2 = 0.0f; - float t0 = 0.5f - x0 * x0 - y0 * y0; - if (t0 >= 0.0f) { - t0 *= t0; - n0 = t0 * t0 * grad2(perm[ii + perm[jj]], x0, y0); - } - float t1 = 0.5f - x1 * x1 - y1 * y1; - if (t1 >= 0.0f) { - t1 *= t1; - n1 = t1 * t1 * grad2(perm[ii + i1 + perm[jj + j1]], x1, y1); - } - float t2 = 0.5f - x2 * x2 - y2 * y2; - if (t2 >= 0.0f) { - t2 *= t2; - n2 = t2 * t2 * grad2(perm[ii + 1 + perm[jj + 1]], x2, y2); - } - return 45.0f * (n0 + n1 + n2); +struct Color* apply_directional_lighting(struct Color* baseColor, struct Vector3* normal, struct DirectionalLight* light) { + struct Vector3* lightDir = (*light).direction; + float diff = fmaxf(0.000000, -((((*lightDir).x * (*normal).x) + ((*lightDir).y * (*normal).y)) + ((*lightDir).z * (*normal).z))); + float brightness = ((*light).ambientIntensity + ((diff * (*light).intensity) * (1.000000 - (*light).ambientIntensity))); + uint8_t r = (uint8_t) ((float) (*baseColor).r * brightness); + uint8_t g = (uint8_t) ((float) (*baseColor).g * brightness); + uint8_t b = (uint8_t) ((float) (*baseColor).b * brightness); + return suic_alloc_struct(&sui_typeinfo_Color, sizeof(struct Color), &(struct Color){ .r = r, .g = g, .b = b, .a = (*baseColor).a }); } -static float fbm_noise(float x, float y, int octaves) { - float value = 0.0f, amplitude = 1.0f, frequency = 1.0f, max_value = 0.0f; - for (int i = 0; i < octaves; i++) { - value += simplex_noise_2d(x * frequency, y * frequency) * amplitude; - max_value += amplitude; - amplitude *= 0.5f; - frequency *= 2.0f; - } - return value / max_value; -} - -float get_terrain_height(float x, float z) { - float height = fbm_noise(x * 0.05f, z * 0.05f, 2); - height += fbm_noise(x * 0.01f, z * 0.01f, 2) * 1.5f; - return height * 4.0f + 2.0f; -} - -#define TERRAIN_SIZE 256 -#define TERRAIN_SCALE 1.0f -#define TERRAIN_MIN (-TERRAIN_SIZE * TERRAIN_SCALE / 2.0f) -#define TERRAIN_MAX (TERRAIN_SIZE * TERRAIN_SCALE / 2.0f) - -static Mesh generate_terrain_mesh(void) { - int size = TERRAIN_SIZE; - Mesh mesh = {0}; - - int vertexCount = size * size; - int triangleCount = (size - 1) * (size - 1) * 2; - - mesh.vertexCount = vertexCount; - mesh.triangleCount = triangleCount; - - mesh.vertices = (float *)MemAlloc(vertexCount * 3 * sizeof(float)); - mesh.texcoords = (float *)MemAlloc(vertexCount * 2 * sizeof(float)); - mesh.normals = (float *)MemAlloc(vertexCount * 3 * sizeof(float)); - mesh.indices = - (unsigned short *)MemAlloc(triangleCount * 3 * sizeof(unsigned short)); - - // Generate vertices - for (int z = 0; z < size; z++) { - for (int x = 0; x < size; x++) { - int idx = z * size + x; - float wx = ((float)x - size / 2.0f) * TERRAIN_SCALE; - float wz = ((float)z - size / 2.0f) * TERRAIN_SCALE; - float wy = get_terrain_height(wx, wz); - - mesh.vertices[idx * 3 + 0] = wx; - mesh.vertices[idx * 3 + 1] = wy; - mesh.vertices[idx * 3 + 2] = wz; - - mesh.texcoords[idx * 2 + 0] = (float)x / (float)(size - 1); - mesh.texcoords[idx * 2 + 1] = (float)z / (float)(size - 1); +int suic_main(void) { + int sw = 1280; + int sh = 720; + suic_init_window(sw, sh, suic_alloc_array(NULL, sizeof(char), 23, "Voxel Shooter - Client")); + suic_set_target_fps(120); + suic_disable_cursor(); + while ((suic_window_should_close() == false)) { + suic_begin_drawing(); + suic_clear_background(135, 206, 235, 255); + suic_draw_text(suic_alloc_array(NULL, sizeof(char), 14, "Hello Suicmez"), 10, 10, 20, 255, 255, 255, 255); + draw_fps(10, 40); + suic_end_drawing(); } - } - - // Generate indices - int triIdx = 0; - for (int z = 0; z < size - 1; z++) { - for (int x = 0; x < size - 1; x++) { - int i0 = z * size + x; - int i1 = z * size + (x + 1); - int i2 = (z + 1) * size + x; - int i3 = (z + 1) * size + (x + 1); - - mesh.indices[triIdx * 3 + 0] = i0; - mesh.indices[triIdx * 3 + 1] = i2; - mesh.indices[triIdx * 3 + 2] = i1; - triIdx++; - - mesh.indices[triIdx * 3 + 0] = i1; - mesh.indices[triIdx * 3 + 1] = i2; - mesh.indices[triIdx * 3 + 2] = i3; - triIdx++; - } - } - - // Calculate normals using tangent plane approximation from terrain gradients - // This preserves terrain curvature better than simple triangle averaging - for (int z = 0; z < size; z++) { - for (int x = 0; x < size; x++) { - int idx = z * size + x; - float wx = ((float)x - size / 2.0f) * TERRAIN_SCALE; - float wz = ((float)z - size / 2.0f) * TERRAIN_SCALE; - - // Sample height gradients to compute terrain normal - // Use neighboring vertices for finite difference approximation - float h_right = (x + 1 < size) - ? mesh.vertices[(z * size + (x + 1)) * 3 + 1] - : mesh.vertices[idx * 3 + 1]; - float h_left = (x - 1 >= 0) ? mesh.vertices[(z * size + (x - 1)) * 3 + 1] - : mesh.vertices[idx * 3 + 1]; - float h_down = (z + 1 < size) - ? mesh.vertices[((z + 1) * size + x) * 3 + 1] - : mesh.vertices[idx * 3 + 1]; - float h_up = (z - 1 >= 0) ? mesh.vertices[((z - 1) * size + x) * 3 + 1] - : mesh.vertices[idx * 3 + 1]; - - // Compute finite differences - float dh_dx = (h_right - h_left) / (2.0f * TERRAIN_SCALE); - float dh_dz = (h_down - h_up) / (2.0f * TERRAIN_SCALE); - - // Normal from height field: (-dh/dx, 1, -dh/dz) then normalized - float nx = -dh_dx; - float ny = 1.0f; - float nz = -dh_dz; - - float len = sqrtf(nx * nx + ny * ny + nz * nz); - if (len > 0.0001f) { - mesh.normals[idx * 3 + 0] = nx / len; - mesh.normals[idx * 3 + 1] = ny / len; - mesh.normals[idx * 3 + 2] = nz / len; - } else { - mesh.normals[idx * 3 + 0] = 0; - mesh.normals[idx * 3 + 1] = 1; - mesh.normals[idx * 3 + 2] = 0; - } - } - } - - UploadMesh(&mesh, false); - return mesh; + suic_close_window(); + return 0; } -// apply_directional_lighting: Basic Lambertian diffuse lighting -// Applies directional light with diffuse component based on surface normal -static Color apply_directional_lighting(Color baseColor, Vector3 normal, - DirectionalLight light) { - // Normalize light direction (it's already normalized, but for safety) - Vector3 lightDir = light.direction; - - // Calculate diffuse component: dot product of negative light direction and - // surface normal We use negative because light travels opposite to its - // direction vector - float diff = fmaxf(0.0f, -(lightDir.x * normal.x + lightDir.y * normal.y + - lightDir.z * normal.z)); - - // Combine diffuse with ambient light - // Ambient provides minimum brightness even in shadow - float brightness = light.ambientIntensity + - (diff * light.intensity * (1.0f - light.ambientIntensity)); - - // Apply brightness multiplier to base color - int r = (int)(baseColor.r * brightness); - int g = (int)(baseColor.g * brightness); - int b = (int)(baseColor.b * brightness); - - // Clamp RGB to valid range [0, 255] - if (r > 255) - r = 255; - if (g > 255) - g = 255; - if (b > 255) - b = 255; - - return (Color){r, g, b, baseColor.a}; +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; } -// calculate_shadow_factor: Distance-based shadow softening -// Objects at higher elevations or farther from ground get softer, less -// pronounced shadows This simulates how shadows fade with distance and -// atmospheric scattering -static float calculate_shadow_factor(Vector3 worldPos, Vector3 lightDir, - float maxShadowDistance) { - // Calculate height above ground (approximate) - float distFromLight = fmaxf(0.0f, worldPos.y - 2.0f); - - // Fade out shadow strength with distance (max 15% darkening) - float shadowIntensity = - fmaxf(0.0f, 1.0f - (distFromLight / maxShadowDistance)); - return 1.0f - (shadowIntensity * 0.15f); -} - -// calculate_temporal_shadow: Time-based shadow variance for anti-aliasing -// Simulates subtle shadow movement to avoid banding artifacts -static float calculate_temporal_shadow(Vector3 worldPos, float timePhase) { - // Add subtle time-based variation to shadow boundaries - float noiseVal = - sinf(worldPos.x * 0.5f + timePhase) * cosf(worldPos.z * 0.5f + timePhase); - return 1.0f + (noiseVal * 0.02f); // Very subtle variation -} - -// apply_lighting_with_shadows: Full lighting calculation with shadows -// Combines directional light, ambient light, shadows, and temporal variation -static Color apply_lighting_with_shadows(Color baseColor, Vector3 normal, - Vector3 worldPos, - DirectionalLight light) { - // Calculate base shadow factor (distance-based) - float shadowFactor = - calculate_shadow_factor(worldPos, light.direction, 10.0f); - - // Apply shadow to intensity - float adjustedIntensity = light.intensity * shadowFactor; - - // Calculate diffuse component with adjusted intensity - Vector3 lightDir = light.direction; - float diff = fmaxf(0.0f, -(lightDir.x * normal.x + lightDir.y * normal.y + - lightDir.z * normal.z)); - - // Combine with ambient using adjusted intensity - float brightness = light.ambientIntensity + (diff * adjustedIntensity * - (1.0f - light.ambientIntensity)); - - // Apply brightness to base color - int r = (int)(baseColor.r * brightness); - int g = (int)(baseColor.g * brightness); - int b = (int)(baseColor.b * brightness); - - // Clamp values to valid RGB range - if (r > 255) - r = 255; - if (g > 255) - g = 255; - if (b > 255) - b = 255; - - return (Color){r, g, b, baseColor.a}; -} - -static Vector3 v3_normalize(Vector3 v) { - float len = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); - if (len < 0.0001f) - return (Vector3){0, 1, 0}; - return (Vector3){v.x / len, v.y / len, v.z / len}; -} - -static Vector3 v3(float x, float y, float z) { - Vector3 v = {x, y, z}; - return v; -} -static Vector3 v3_add(Vector3 a, Vector3 b) { - return v3(a.x + b.x, a.y + b.y, a.z + b.z); -} -static Vector3 v3_sub(Vector3 a, Vector3 b) { - return v3(a.x - b.x, a.y - b.y, a.z - b.z); -} -static Vector3 v3_mul(Vector3 a, float s) { - return v3(a.x * s, a.y * s, a.z * s); -} -static float v3_dot(Vector3 a, Vector3 b) { - return a.x * b.x + a.y * b.y + a.z * b.z; -} -static float v3_len(Vector3 a) { - return sqrtf(a.x * a.x + a.y * a.y + a.z * a.z); -} -static Vector3 v3_norm(Vector3 a) { - float l = v3_len(a); - if (l <= 1e-6f) - return v3(0, 0, 1); - return v3(a.x / l, a.y / l, a.z / l); -} - -// calculate_ambient_occlusion: Estimates how occluded a point is based on -// terrain curvature Samples heights in cardinal directions and computes horizon -// angle to terrain Returns occlusion factor from 0 (fully occluded) to 1 (fully -// lit) -static float calculate_ambient_occlusion(Vector3 worldPos, Vector3 normal) { - // AO based on terrain curvature: check if terrain rises around the point - float sampleRadius = 3.0f; - float aoAccum = 0.0f; - int numSamples = 8; - - float centerHeight = worldPos.y; - - // Sample 8 directions around the point - for (int i = 0; i < numSamples; i++) { - float angle = (2.0f * 3.14159265f * (float)i) / (float)numSamples; - float sx = worldPos.x + cosf(angle) * sampleRadius; - float sz = worldPos.z + sinf(angle) * sampleRadius; - float sh = get_terrain_height(sx, sz); - - // Check if terrain is higher relative to surface normal - // Higher terrain in shadow-casting areas reduces occlusion - float heightDiff = sh - centerHeight; - if (heightDiff > 0.1f) { - // Terrain is higher, contributes to shadow - float aoAmount = fminf(1.0f, heightDiff / 2.0f); - aoAccum += aoAmount; - } - } - - float aoFactor = - 1.0f - (aoAccum / (float)numSamples) * 0.6f; // 60% max occlusion - return fmaxf(0.2f, aoFactor); // Min 20% brightness -} - -// apply_phong_lighting_per_pixel: Advanced Phong lighting with per-pixel -// normals Includes diffuse, specular highlight, and ambient occlusion for -// geometry detail -static Color apply_phong_lighting_per_pixel(Color baseColor, Vector3 normal, - Vector3 worldPos, Vector3 camPos, - DirectionalLight light) { - // Normalize inputs - Vector3 lightDir = v3_normalize(light.direction); - Vector3 normal_norm = v3_normalize(normal); - - // Compute view direction (from surface to camera) - Vector3 viewDir = v3_normalize(v3_sub(camPos, worldPos)); - - // Diffuse component: Lambertian shading - float diffuse = fmaxf(0.0f, -v3_dot(lightDir, normal_norm)); - - // Specular component: Blinn-Phong specular highlight - Vector3 halfVec = v3_normalize(v3_add( - v3_norm((Vector3){-lightDir.x, -lightDir.y, -lightDir.z}), viewDir)); - float specular = - powf(fmaxf(0.0f, v3_dot(halfVec, normal_norm)), 32.0f) * 0.5f; - - // Ambient occlusion from terrain geometry - float ao = calculate_ambient_occlusion(worldPos, normal_norm); - - // Shadow based on height (distant higher terrain casts softer shadows) - float shadowFactor = - calculate_shadow_factor(worldPos, light.direction, 10.0f); - - // Combine lighting components - float brightness = light.ambientIntensity * ao; - brightness += diffuse * light.intensity * shadowFactor * - (1.0f - light.ambientIntensity) * ao; - brightness += specular * light.intensity * shadowFactor * - 0.6f; // Specular less affected by AO - - brightness = fminf(1.0f, brightness); - - // Apply brightness to base color - int r = (int)(baseColor.r * brightness); - int g = (int)(baseColor.g * brightness); - int b = (int)(baseColor.b * brightness); - - // Clamp to valid RGB range - if (r > 255) - r = 255; - if (g > 255) - g = 255; - if (b > 255) - b = 255; - - return (Color){r, g, b, baseColor.a}; -} - -static void set_nonblocking(int sock) { -#ifdef _WIN32 - u_long mode = 1; - ioctlsocket(sock, FIONBIO, &mode); -#else - int flags = fcntl(sock, F_GETFL, 0); - fcntl(sock, F_SETFL, flags | O_NONBLOCK); -#endif -} - -#pragma pack(push, 1) -typedef enum MsgType : uint8_t { - MSG_HELLO = 1, - MSG_WELCOME = 2, - MSG_INPUT = 3, - MSG_SNAPSHOT = 4, - MSG_SHOOT = 5, - MSG_ITEMS = 6, - MSG_ROOM_STATE = 7 -} MsgType; - -typedef struct MsgHello { - uint8_t type; - uint32_t protocol; - char username[USERNAME_MAX]; -} MsgHello; - -typedef struct MsgWelcome { - uint8_t type; - uint8_t playerId; - uint32_t serverTick; -} MsgWelcome; - -typedef struct MsgInput { - uint8_t type; - uint8_t playerId; - uint32_t clientTick; - float moveX, moveZ, yaw, pitch; - uint8_t buttons; -} MsgInput; - -typedef struct MsgShoot { - uint8_t type; - uint8_t playerId; - uint32_t clientTick; -} MsgShoot; - -typedef struct PlayerStateNet { - uint8_t id, alive; - int16_t hp; - float x, y, z, yaw, pitch; - uint8_t weapon; - int16_t pistolMag, rifleMag, pistolAmmo, rifleAmmo, medkits; - int16_t reloadTimeLeft; - char username[USERNAME_MAX]; -} PlayerStateNet; - -typedef struct MsgSnapshot { - uint8_t type; - uint32_t serverTick; - uint8_t count; - PlayerStateNet p[MAX_PLAYERS]; -} MsgSnapshot; - -typedef struct ItemNet { - uint16_t id; - uint8_t type; - int16_t qty; - float x, y, z; -} ItemNet; - -typedef struct MsgItems { - uint8_t type; - uint32_t serverTick; - uint8_t count; - ItemNet items[MAX_ITEMS]; -} MsgItems; - -typedef struct MsgRoomState { - uint8_t type; - uint8_t state; - float countdownRemaining; - uint8_t winnerId; - char winnerName[USERNAME_MAX]; -} MsgRoomState; -#pragma pack(pop) - -typedef struct RemotePlayer { - int present, alive, hp; - Vector3 pos; - Vector3 prevPos; - float yaw, pitch; - uint8_t weapon; - int16_t pistolMag, rifleMag, pistolAmmo, rifleAmmo, medkits; - int16_t reloadTimeLeft; - char username[USERNAME_MAX]; -} RemotePlayer; - -typedef struct WorldItem { - int present; - uint16_t id; - uint8_t type; - int16_t qty; - Vector3 pos; -} WorldItem; - -static const char *ItemName(uint8_t t) { - switch (t) { - case ITEM_MEDKIT: - return "Medkit"; - case ITEM_AMMO_PISTOL: - return "Pistol ammo"; - case ITEM_AMMO_RIFLE: - return "Rifle ammo"; - default: - return "-"; - } -} - -static void ui_username_prompt(char outName[USERNAME_MAX]) { - memset(outName, 0, USERNAME_MAX); - while (!WindowShouldClose()) { - int ch = GetCharPressed(); - while (ch > 0) { - int len = (int)strlen(outName); - if (ch >= 32 && ch <= 126) { - if (len < USERNAME_MAX - 1) { - outName[len] = (char)ch; - outName[len + 1] = '\0'; - } - } - ch = GetCharPressed(); - } - if (IsKeyPressed(KEY_BACKSPACE)) { - int len = (int)strlen(outName); - if (len > 0) - outName[len - 1] = '\0'; - } - if (IsKeyPressed(KEY_ENTER) && strlen(outName) > 0) - return; - - BeginDrawing(); - ClearBackground((Color){20, 24, 32, 255}); - DrawText("Enter username (press ENTER):", 60, 80, 28, RAYWHITE); - DrawRectangle(60, 130, 420, 48, (Color){40, 48, 64, 255}); - DrawRectangleLines(60, 130, 420, 48, (Color){120, 140, 170, 255}); - DrawText(outName[0] ? outName : "_", 72, 142, 24, - (Color){230, 230, 240, 255}); - EndDrawing(); - } -} - -int main(void) { -#ifdef _WIN32 - WSADATA wsa; - WSAStartup(MAKEWORD(2, 2), &wsa); -#endif - - const int sw = 1280, sh = 720; - InitWindow(sw, sh, "Voxel Shooter - Client (SMOOTH TERRAIN WITH SHADOWS)"); - SetTargetFPS(120); - - char myName[USERNAME_MAX]; - ui_username_prompt(myName); - - DisableCursor(); - - // Generate terrain mesh - Mesh terrainMesh = generate_terrain_mesh(); - Model terrainModel = LoadModelFromMesh(terrainMesh); - terrainModel.materials[0].maps[MATERIAL_MAP_DIFFUSE].color = - (Color){80, 140, 70, 255}; - - // Setup directional light - DirectionalLight dirLight = {0}; - dirLight.direction = - v3_normalize(v3(-0.8f, -1.0f, -0.6f)); // Coming from upper-left-back - dirLight.color = v3(1.0f, 1.0f, 1.0f); - dirLight.intensity = 1.2f; - dirLight.ambientIntensity = 0.3f; - dirLight.shadowBias = 0.005f; - dirLight.shadowIntensity = 0.4f; - - // Load terrain shader - TerrainShader terrainShader = load_terrain_shader(); - if (terrainShader.shader.id == 0) { - fprintf( - stderr, - "Warning: Failed to load terrain shader, using default rendering\n"); - // Fallback: Make terrain very bright red to show shader failed - terrainModel.materials[0].maps[MATERIAL_MAP_DIFFUSE].color = - (Color){255, 100, 100, 255}; - } else { - terrainModel.materials[0].shader = terrainShader.shader; - fprintf(stderr, "Shader loaded successfully!\n"); - } - - int sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sock < 0) { - perror("socket"); - return 1; - } - set_nonblocking(sock); - - struct sockaddr_in srv = {0}; - srv.sin_family = AF_INET; - srv.sin_port = htons(SERVER_PORT); - inet_pton(AF_INET, "127.0.0.1", &srv.sin_addr); - - uint8_t myId = 255; - uint32_t clientTick = 0; - - RemotePlayer rp[MAX_PLAYERS] = {0}; - WorldItem wi[MAX_ITEMS] = {0}; - - // Room state - int roomState = 0; - float countdownRemaining = 0.0f; - char winnerName[USERNAME_MAX] = {0}; - - Vector3 camPos = v3(0, 5.0f, 6); - float yaw = 0.0f, pitch = 0.0f; - - Vector3 prevBodyPos = v3(0, 5.0f, 6); - Vector3 currentTargetBody = v3(0, 5.0f, 6); - float interpTimer = 0.0f; - - float recoilYaw = 0.0f, recoilPitch = 0.0f, crossSpread = 0.0f; - int scoped = 0; - float fireCooldown = 0.0f; - int shotsInBurst = 0; - float burstResetTimer = 0.0f; - - const float pistolFireRate = 4.0f, rifleFireRate = 12.0f; - const float recoilReturn = 18.0f, crossReturn = 14.0f; - const float pistolKickPitch = 0.010f, pistolKickYaw = 0.004f; - const float rifleKickPitch = 0.018f, rifleKickYaw = 0.010f; - const float pistolCrossKick = 2.0f, rifleCrossKick = 4.0f; - const float pistolSprayGrow = 0.4f, rifleSprayGrow = 1.2f; - const float burstResetTime = 0.18f; - - MsgHello hello = {0}; - hello.type = MSG_HELLO; - hello.protocol = PROTOCOL_VERSION; - strncpy(hello.username, myName, USERNAME_MAX - 1); - sendto(sock, (const char *)&hello, (int)sizeof(hello), 0, - (const struct sockaddr *)&srv, sizeof(srv)); - - while (!WindowShouldClose()) { - clientTick++; - float dt = GetFrameTime(); - - fireCooldown -= dt; - if (fireCooldown < 0.0f) - fireCooldown = 0.0f; - burstResetTimer -= dt; - if (burstResetTimer <= 0.0f) - shotsInBurst = 0; - - { - float k = 1.0f - expf(-recoilReturn * dt); - recoilYaw += (0.0f - recoilYaw) * k; - recoilPitch += (0.0f - recoilPitch) * k; - } - { - float k = 1.0f - expf(-crossReturn * dt); - crossSpread += (0.0f - crossSpread) * k; - if (crossSpread < 0.01f) - crossSpread = 0.0f; - } - - for (;;) { - uint8_t buf[1400]; - struct sockaddr_in from = {0}; - socklen_t fromLen = sizeof(from); - int n = (int)recvfrom(sock, (char *)buf, (int)sizeof(buf), 0, - (struct sockaddr *)&from, &fromLen); - if (n <= 0) { -#ifdef _WIN32 - if (WSAGetLastError() == WSAEWOULDBLOCK) - break; -#else - if (errno == EWOULDBLOCK || errno == EAGAIN) - break; -#endif - break; - } - - uint8_t type = buf[0]; - if (type == MSG_WELCOME && n >= (int)sizeof(MsgWelcome)) { - MsgWelcome *w = (MsgWelcome *)buf; - myId = w->playerId; - } else if (type == MSG_SNAPSHOT && n >= (int)sizeof(MsgSnapshot)) { - MsgSnapshot *s = (MsgSnapshot *)buf; - for (int i = 0; i < MAX_PLAYERS; i++) - rp[i].present = 0; - - for (int i = 0; i < (int)s->count && i < MAX_PLAYERS; i++) { - PlayerStateNet *ps = &s->p[i]; - if (ps->id >= MAX_PLAYERS) - continue; - - RemotePlayer *p = &rp[ps->id]; - p->prevPos = p->pos; - p->present = 1; - p->alive = ps->alive; - p->hp = ps->hp; - p->pos = v3(ps->x, ps->y, ps->z); - p->yaw = ps->yaw; - p->pitch = ps->pitch; - p->weapon = ps->weapon; - p->pistolMag = ps->pistolMag; - p->rifleMag = ps->rifleMag; - p->pistolAmmo = ps->pistolAmmo; - p->rifleAmmo = ps->rifleAmmo; - p->medkits = ps->medkits; - p->reloadTimeLeft = ps->reloadTimeLeft; - memset(p->username, 0, USERNAME_MAX); - strncpy(p->username, ps->username, USERNAME_MAX - 1); - } - - if (myId != 255 && rp[myId].present) { - prevBodyPos = currentTargetBody; - currentTargetBody = rp[myId].pos; - interpTimer = 0.0f; - } - } else if (type == MSG_ITEMS && n >= (int)sizeof(MsgItems)) { - MsgItems *m = (MsgItems *)buf; - for (int i = 0; i < MAX_ITEMS; i++) - wi[i].present = 0; - - for (int i = 0; i < (int)m->count && i < MAX_ITEMS; i++) { - wi[i].present = 1; - wi[i].id = m->items[i].id; - wi[i].type = m->items[i].type; - wi[i].qty = m->items[i].qty; - wi[i].pos = v3(m->items[i].x, m->items[i].y, m->items[i].z); - } - } else if (type == MSG_ROOM_STATE && n >= (int)sizeof(MsgRoomState)) { - const MsgRoomState *rs = (const MsgRoomState *)buf; - roomState = rs->state; - countdownRemaining = rs->countdownRemaining; - memset(winnerName, 0, USERNAME_MAX); - if (rs->winnerId < 255) { - strncpy(winnerName, rs->winnerName, USERNAME_MAX - 1); - } - } - } - - // Interpolate camera position - if (myId != 255 && rp[myId].present) { - float interpFactor = interpTimer / (1.0f / 20.0f); - if (interpFactor > 1.0f) - interpFactor = 1.0f; - Vector3 interpBody = v3_add(v3_mul(prevBodyPos, 1.0f - interpFactor), - v3_mul(currentTargetBody, interpFactor)); - camPos.x = interpBody.x; - camPos.y = interpBody.y + 1.0f; - camPos.z = interpBody.z + 0.0001f; - - // Prevent camera from clipping into terrain - float terrain_h = get_terrain_height(camPos.x, camPos.z); - camPos.y = fmaxf(camPos.y, terrain_h + 1.5f); - } - interpTimer += dt; - - Vector2 md = GetMouseDelta(); - const float sens = 0.0025f; - yaw -= md.x * sens; - pitch -= md.y * sens; - if (pitch < -1.5f) - pitch = -1.5f; - if (pitch > 1.5f) - pitch = 1.5f; - - float viewYaw = yaw + recoilYaw; - float viewPitch = pitch + recoilPitch; - if (viewPitch < -1.5f) - viewPitch = -1.5f; - if (viewPitch > 1.5f) - viewPitch = 1.5f; - - float moveX = 0.0f, moveZ = 0.0f; - if (IsKeyDown(KEY_A)) - moveX += 1.0f; - if (IsKeyDown(KEY_D)) - moveX -= 1.0f; - if (IsKeyDown(KEY_W)) - moveZ += 1.0f; - if (IsKeyDown(KEY_S)) - moveZ -= 1.0f; - - uint8_t buttons = 0; - if (IsKeyPressed(KEY_ONE)) - buttons |= BTN_SWITCH_PISTOL; - if (IsKeyPressed(KEY_TWO)) - buttons |= BTN_SWITCH_RIFLE; - if (IsKeyPressed(KEY_R)) - buttons |= BTN_RELOAD; - if (IsKeyPressed(KEY_F)) - buttons |= BTN_PICK; - if (IsKeyPressed(KEY_H)) - buttons |= BTN_USE_MEDKIT; - if (IsKeyPressed(KEY_SPACE)) - buttons |= BTN_JUMP; - if (IsKeyPressed(KEY_Z)) - scoped = !scoped; - - if (myId != 255) { - MsgInput in = {0}; - in.type = MSG_INPUT; - in.playerId = myId; - in.clientTick = clientTick; - in.moveX = moveX; - in.moveZ = moveZ; - in.yaw = viewYaw; - in.pitch = viewPitch; - in.buttons = buttons; - sendto(sock, (const char *)&in, (int)sizeof(in), 0, - (const struct sockaddr *)&srv, sizeof(srv)); - } - - if (myId != 255 && IsMouseButtonDown(MOUSE_BUTTON_LEFT) && - fireCooldown <= 0.0f && rp[myId].present) { - int wpn = rp[myId].weapon; - float rate = (wpn == WEAPON_PISTOL) ? pistolFireRate : rifleFireRate; - fireCooldown = 1.0f / rate; - - shotsInBurst++; - burstResetTimer = burstResetTime; - - if (wpn == WEAPON_PISTOL) { - recoilPitch += pistolKickPitch; - recoilYaw += - (((float)GetRandomValue(-1000, 1000)) / 1000.0f) * pistolKickYaw; - crossSpread += pistolCrossKick + shotsInBurst * pistolSprayGrow; - } else { - recoilPitch += rifleKickPitch; - recoilYaw += - (((float)GetRandomValue(-1000, 1000)) / 1000.0f) * rifleKickYaw; - crossSpread += rifleCrossKick + shotsInBurst * rifleSprayGrow; - } - - MsgShoot shmsg = {0}; - shmsg.type = MSG_SHOOT; - shmsg.playerId = myId; - shmsg.clientTick = clientTick; - sendto(sock, (const char *)&shmsg, (int)sizeof(shmsg), 0, - (const struct sockaddr *)&srv, sizeof(srv)); - } - - Vector3 forward = v3(sinf(viewYaw) * cosf(viewPitch), sinf(viewPitch), - cosf(viewYaw) * cosf(viewPitch)); - - // Offset camera position: 0.3m in front, 0.2m below - camPos = v3_add(camPos, v3_mul(forward, 0.3f)); - camPos.y -= 0.2f; - - // Ensure camera doesn't clip into terrain after offset - float terrain_h = get_terrain_height(camPos.x, camPos.z); - camPos.y = fmaxf(camPos.y, terrain_h + 1.5f); - - Camera3D cam = {0}; - cam.position = camPos; - cam.target = v3_add(camPos, forward); - cam.up = v3(0, 1, 0); - cam.fovy = scoped ? 30.0f : 75.0f; - cam.projection = CAMERA_PERSPECTIVE; - - BeginDrawing(); - ClearBackground((Color){135, 206, 235, 255}); - - BeginMode3D(cam); - - // Set up shader uniforms for terrain rendering - if (terrainShader.shader.id != 0) { - // Convert light direction to shader format (should be pointing TO the - // light) - float lightDirArray[3] = {-dirLight.direction.x, -dirLight.direction.y, - -dirLight.direction.z}; - float lightColorArray[3] = {dirLight.color.x, dirLight.color.y, - dirLight.color.z}; - float viewPosArray[3] = {camPos.x, camPos.y, camPos.z}; - // Terrain color in 0-1 range (80, 140, 70) / 255 - float terrainColorArray[3] = {80.0f / 255.0f, 140.0f / 255.0f, - 70.0f / 255.0f}; - - // Debug mode: 0=normal lighting, 1=show normals as colors, 2=show AO only - - SetShaderValue(terrainShader.shader, terrainShader.locViewPos, - viewPosArray, SHADER_UNIFORM_VEC3); - SetShaderValue(terrainShader.shader, terrainShader.locLightDir, - lightDirArray, SHADER_UNIFORM_VEC3); - SetShaderValue(terrainShader.shader, terrainShader.locLightColor, - lightColorArray, SHADER_UNIFORM_VEC3); - SetShaderValue(terrainShader.shader, terrainShader.locLightIntensity, - &dirLight.intensity, SHADER_UNIFORM_FLOAT); - SetShaderValue(terrainShader.shader, terrainShader.locAmbientIntensity, - &dirLight.ambientIntensity, SHADER_UNIFORM_FLOAT); - SetShaderValue(terrainShader.shader, terrainShader.locTerrainColor, - terrainColorArray, SHADER_UNIFORM_VEC3); - } - - // Draw terrain with shader - terrainModel.materials[0].maps[MATERIAL_MAP_DIFFUSE].color = - (Color){80, 140, 70, 255}; - DrawModel(terrainModel, (Vector3){0, 0, 0}, 1.0f, WHITE); - - // Draw border - float borderSize = TERRAIN_MAX - TERRAIN_MIN; - DrawCube((Vector3){0, 0, 0}, borderSize, 1000, borderSize, (Color){255, 0, 0, 100}); - - // Items with basic lighting (no shader for now to keep it simple) - for (int i = 0; i < MAX_ITEMS; i++) { - if (!wi[i].present) - continue; - Color ic = (Color){220, 220, 220, 255}; - if (wi[i].type == ITEM_MEDKIT) - ic = (Color){120, 255, 120, 255}; - if (wi[i].type == ITEM_AMMO_PISTOL) - ic = (Color){255, 220, 120, 255}; - if (wi[i].type == ITEM_AMMO_RIFLE) - ic = (Color){255, 180, 120, 255}; - - // Apply basic lighting to items - Vector3 itemNormal = v3(0, 1, 0); - Color litColor = - apply_lighting_with_shadows(ic, itemNormal, wi[i].pos, dirLight); - DrawSphere(wi[i].pos, 0.3f, litColor); - } - - // Players with basic lighting - for (int i = 0; i < MAX_PLAYERS; i++) { - if (!rp[i].present) - continue; - float interpFactor = interpTimer / (1.0f / 20.0f); - if (interpFactor > 1.0f) - interpFactor = 1.0f; - Vector3 p = v3_add(v3_mul(rp[i].prevPos, 1.0f - interpFactor), - v3_mul(rp[i].pos, interpFactor)); - Color c = - (i == myId) ? (Color){80, 180, 255, 255} : (Color){255, 80, 80, 255}; - if (!rp[i].alive) - c = (Color){120, 120, 120, 255}; - - // Apply basic lighting to players - Vector3 playerNormal = v3(0, 1, 0); - Color litPlayerColor = - apply_lighting_with_shadows(c, playerNormal, p, dirLight); - DrawCapsule(v3(p.x, p.y - 0.5f, p.z), v3(p.x, p.y + 0.5f, p.z), 0.35f, 8, - 8, litPlayerColor); - } - - EndMode3D(); - - // Nameplates - for (int i = 0; i < MAX_PLAYERS; i++) { - if (!rp[i].present || !rp[i].username[0]) - continue; - float interpFactor = interpTimer / (1.0f / 20.0f); - if (interpFactor > 1.0f) - interpFactor = 1.0f; - Vector3 p = v3_add(v3_mul(rp[i].prevPos, 1.0f - interpFactor), - v3_mul(rp[i].pos, interpFactor)); - Vector3 head = v3(p.x, p.y + 1.2f, p.z); - Vector3 camForward = v3_norm(v3_sub(cam.target, cam.position)); - Vector3 toHead = v3_sub(head, cam.position); - if (v3_dot(camForward, toHead) <= 0.0f) - continue; - Vector2 s = GetWorldToScreen(head, cam); - if (s.x < -200 || s.x > sw + 200 || s.y < -200 || s.y > sh + 200) - continue; - int fontSize = 18; - int w = MeasureText(rp[i].username, fontSize); - Color tc = (i == myId) ? (Color){180, 230, 255, 255} : RAYWHITE; - DrawText(rp[i].username, (int)(s.x - w / 2), (int)(s.y - fontSize), - fontSize, tc); - } - - // HUD - if (myId == 255 || !rp[myId].present) { - DrawText("Connecting...", 10, 10, 20, RAYWHITE); - } else { - DrawRectangle(10, 10, 280, 110, (Color){0, 0, 0, 120}); - DrawText("HP", 20, 20, 20, RAYWHITE); - int healthBarWidth = (rp[myId].hp * 220) / 100; - Color healthColor = (rp[myId].hp > 60) ? (Color){80, 255, 80, 120} - : (rp[myId].hp > 30) ? (Color){255, 200, 80, 120} - : (Color){255, 80, 80, 120}; - DrawRectangle(20, 45, 220, 20, (Color){40, 40, 40, 255}); - DrawRectangle(20, 45, healthBarWidth, 20, healthColor); - DrawText(TextFormat("%d", rp[myId].hp), 250, 47, 18, RAYWHITE); - DrawText(TextFormat("Medkits: %d (H to use)", rp[myId].medkits), 20, 75, - 18, - (rp[myId].medkits > 0) ? (Color){120, 255, 120, 120} - : (Color){120, 120, 120, 120}); - DrawText("1=Pistol 2=Rifle R=Reload F=Pick SPACE=Jump", 20, 95, 12, - (Color){150, 150, 150, 150}); - - const char *weaponName = - (rp[myId].weapon == WEAPON_PISTOL) ? "PISTOL" : "RIFLE"; - Color weaponColor = (rp[myId].weapon == WEAPON_PISTOL) - ? (Color){100, 200, 255, 255} - : (Color){255, 150, 100, 255}; - int currentMag = (rp[myId].weapon == WEAPON_PISTOL) ? rp[myId].pistolMag - : rp[myId].rifleMag; - int reserveAmmo = (rp[myId].weapon == WEAPON_PISTOL) ? rp[myId].pistolAmmo - : rp[myId].rifleAmmo; - - DrawRectangle(sw - 260, sh - 120, 250, 110, (Color){0, 0, 0, 180}); - DrawText(weaponName, sw - 250, sh - 110, 28, weaponColor); - DrawText(TextFormat("%d", currentMag), sw - 250, sh - 75, 40, RAYWHITE); - DrawText(TextFormat("/ %d", reserveAmmo), sw - 140, sh - 65, 24, - (Color){180, 180, 180, 255}); - if (rp[myId].reloadTimeLeft > 0) - DrawText("RELOADING...", sw - 250, sh - 30, 20, - (Color){255, 200, 80, 255}); - else if (currentMag == 0) - DrawText("RELOAD!", sw - 250, sh - 30, 20, (Color){255, 80, 80, 255}); - } - - DrawFPS(sw - 90, 10); - - // Room state overlay - if (roomState == 0) { // Waiting - DrawRectangle(sw / 2 - 150, sh / 2 - 50, 350, 100, (Color){0, 0, 0, 200}); - DrawText("WAITING FOR PLAYERS", sw / 2 - 120, sh / 2 - 30, 24, RAYWHITE); - DrawText("Need at least 2 players", sw / 2 - 100, sh / 2 - 5, 18, - (Color){200, 200, 200, 255}); - } else if (roomState == 1) { // Counting down - DrawRectangle(sw / 2 - 150, sh / 2 - 50, 350, 100, (Color){0, 0, 0, 200}); - DrawText("GAME STARTING SOON", sw / 2 - 120, sh / 2 - 30, 24, - (Color){255, 255, 80, 255}); - DrawText(TextFormat("%.1f seconds", countdownRemaining), sw / 2 - 60, - sh / 2 - 5, 20, RAYWHITE); - } else if (roomState == 3) { // Finished - DrawRectangle(sw / 2 - 200, sh / 2 - 50, 450, 100, (Color){0, 0, 0, 200}); - DrawText("GAME FINISHED", sw / 2 - 80, sh / 2 - 30, 28, - (Color){255, 80, 80, 255}); - if (winnerName[0]) { - DrawText(TextFormat("Winner: %s", winnerName), sw / 2 - 100, sh / 2 - 5, - 24, (Color){255, 255, 80, 255}); - } else { - DrawText("No winner", sw / 2 - 50, sh / 2 - 5, 24, RAYWHITE); - } - } - - // Crosshair - { - int cx = sw / 2, cy = sh / 2; - int gap = scoped ? 2 : 6 + (int)crossSpread; - int len = scoped ? 5 : 10, thick = 2; - Color col = (Color){240, 240, 245, 220}; - DrawRectangle(cx - gap - len, cy - thick / 2, len, thick, col); - DrawRectangle(cx + gap, cy - thick / 2, len, thick, col); - DrawRectangle(cx - thick / 2, cy - gap - len, thick, len, col); - DrawRectangle(cx - thick / 2, cy + gap, thick, len, col); - DrawCircleLines(cx, cy, scoped ? 1.5f : 3.0f, - (Color){240, 240, 245, 160}); - } - - EndDrawing(); - } - - UnloadModel(terrainModel); - unload_terrain_shader(&terrainShader); - CloseWindow(); - CLOSESOCK(sock); -#ifdef _WIN32 - WSACleanup(); -#endif - return 0; -} diff --git a/game/client_backup.sui b/game/client_backup.sui deleted file mode 100644 index 096511e..0000000 --- a/game/client_backup.sui +++ /dev/null @@ -1,549 +0,0 @@ -# Suicmez port of game/client.c - -# Constants -const PROTOCOL_VERSION = 67 -const SERVER_PORT = 27015 -const MAX_PLAYERS = 16 -const USERNAME_MAX = 16 -const TERRAIN_SIZE = 256 -const TERRAIN_SCALE = 1.0 -const TERRAIN_MIN = - (TERRAIN_SIZE * TERRAIN_SCALE / 2.0) -const TERRAIN_MAX = TERRAIN_SIZE * TERRAIN_SCALE / 2.0 - -const WEAPON_PISTOL = 0 -const WEAPON_RIFLE = 1 - -const ITEM_NONE = 0 -const ITEM_MEDKIT = 1 -const ITEM_AMMO_PISTOL = 2 -const ITEM_AMMO_RIFLE = 3 - -const MAX_ITEMS = 64 - -const BTN_RELOAD = (1 << 0) -const BTN_SWITCH_PISTOL = (1 << 1) -const BTN_SWITCH_RIFLE = (1 << 2) -const BTN_PICK = (1 << 3) -const BTN_USE_MEDKIT = (1 << 4) -const BTN_JUMP = (1 << 5) - -# Structs -struct DirectionalLight - direction: suic_vector3 - color: suic_vector3 - intensity: float - ambient_intensity: float - shadow_bias: float - shadow_intensity: float -end - -struct TerrainShader - shader: suic_shader_handle - loc_view_pos: int - loc_light_dir: int - loc_light_color: int - loc_light_intensity: int - loc_ambient_intensity: int - loc_terrain_color: int -end - -# Network message types -enum MsgType - MSG_HELLO - MSG_WELCOME - MSG_INPUT - MSG_SNAPSHOT - MSG_SHOOT - MSG_ITEMS - MSG_ROOM_STATE -end - -struct MsgHello - type_: u8 - protocol: u32 - username: string -end - -struct MsgWelcome - type_: u8 - player_id: u8 - server_tick: u32 -end - -struct MsgInput - type_: u8 - player_id: u8 - client_tick: u32 - move_x: float - move_z: float - yaw: float - pitch: float - buttons: u8 -end - -struct MsgShoot - type_: u8 - player_id: u8 - client_tick: u32 -end - -struct PlayerStateNet - id: u8 - alive: u8 - hp: i16 - x: float - y: float - z: float - yaw: float - pitch: float - weapon: u8 - pistol_mag: i16 - rifle_mag: i16 - pistol_ammo: i16 - rifle_ammo: i16 - medkits: i16 - reload_time_left: i16 - username: string -end - -struct MsgSnapshot - type_: u8 - server_tick: u32 - count: u8 - p: [PlayerStateNet] -end - -struct ItemNet - id: u16 - type_: u8 - qty: i16 - x: float - y: float - z: float -end - -struct MsgItems - type_: u8 - server_tick: u32 - count: u8 - items: [ItemNet] -end - -struct MsgRoomState - type_: u8 - state: u8 - countdown_remaining: float - winner_id: u8 - winner_name: string -end - -struct RemotePlayer - present: int - alive: int - hp: int - pos: suic_vector3 - prev_pos: suic_vector3 - yaw: float - pitch: float - weapon: u8 - pistol_mag: i16 - rifle_mag: i16 - pistol_ammo: i16 - rifle_ammo: i16 - medkits: i16 - reload_time_left: i16 - username: [u8; 16] -end - -struct WorldItem - present: int - id: u16 - type_: u8 - qty: i16 - pos: suic_vector3 -end - -# Main function -fn main() -> int do - let sw = 1280 - let sh = 720 - suic_init_window(sw, sh, "Voxel Shooter - Client (Suicmez)") - suic_set_target_fps(120) - - # Username prompt - let my_name = [0; 16] - suic_username_prompt(my_name) - - suic_disable_cursor() - - # Generate terrain mesh - let terrain_mesh = suic_generate_terrain_mesh() - let terrain_model = suic_load_model_from_mesh(terrain_mesh) - - # Setup directional light - let dir_light = DirectionalLight { - direction: suic_vector3 { x: -0.8, y: -1.0, z: -0.6 }, - color: suic_vector3 { x: 1.0, y: 1.0, z: 1.0 }, - intensity: 1.2, - ambient_intensity: 0.3, - shadow_bias: 0.005, - shadow_intensity: 0.4 - } - - let sock = suic_udp_socket_create() - if sock < 0 do - return 1 - end - suic_udp_set_nonblocking(sock) - - let my_id = 255 - let client_tick = 0 - - let rp = [RemotePlayer { present: 0 }; 16] - let wi = [WorldItem { present: 0 }; 64] - - # Room state - let room_state = 0 - let countdown_remaining = 0.0 - let winner_name = [0; 16] - - let cam_pos = suic_vector3 { x: 0, y: 5.0, z: 6 } - let yaw = 0.0 - let pitch = 0.0 - - let prev_body_pos = suic_vector3 { x: 0, y: 5.0, z: 6 } - let current_target_body = suic_vector3 { x: 0, y: 5.0, z: 6 } - let interp_timer = 0.0 - - let recoil_yaw = 0.0 - let recoil_pitch = 0.0 - let cross_spread = 0.0 - let scoped = 0 - let fire_cooldown = 0.0 - let shots_in_burst = 0 - let burst_reset_timer = 0.0 - - let pistol_fire_rate = 4.0 - let rifle_fire_rate = 12.0 - let recoil_return = 18.0 - let cross_return = 14.0 - let pistol_kick_pitch = 0.010 - let pistol_kick_yaw = 0.004 - let rifle_kick_pitch = 0.018 - let rifle_kick_yaw = 0.010 - let pistol_cross_kick = 2.0 - let rifle_cross_kick = 4.0 - let pistol_spray_grow = 0.4 - let rifle_spray_grow = 1.2 - let burst_reset_time = 0.18 - - let hello_buf = [0; 21] # sizeof(MsgHello) - suic_msg_hello_pack(hello_buf, MSG_HELLO, PROTOCOL_VERSION, my_name) - suic_udp_sendto(sock, hello_buf, 21, "127.0.0.1", SERVER_PORT) - - while not suic_window_should_close() do - client_tick = client_tick + 1 - let dt = suic_get_frame_time() - - fire_cooldown = fire_cooldown - dt - if fire_cooldown < 0.0 do fire_cooldown = 0.0 end - burst_reset_timer = burst_reset_timer - dt - if burst_reset_timer <= 0.0 do shots_in_burst = 0 end - - let k = 1.0 - suic_expf(-recoil_return * dt) - recoil_yaw = recoil_yaw + (0.0 - recoil_yaw) * k - recoil_pitch = recoil_pitch + (0.0 - recoil_pitch) * k - - k = 1.0 - suic_expf(-cross_return * dt) - cross_spread = cross_spread + (0.0 - cross_spread) * k - if cross_spread < 0.01 do cross_spread = 0.0 end - - # Network receive - let buf = [0; 1400] - let from_host = [0; 256] - let from_port = 0 - let n = suic_udp_recvfrom(sock, buf, 1400, from_host, from_port) - if n > 0 do - let type_ = buf[0] - if type_ == MSG_WELCOME do - my_id = suic_msg_welcome_unpack(buf) - end else if type_ == MSG_SNAPSHOT do - suic_msg_snapshot_unpack(buf, rp, 16) - if my_id != 255 and rp[my_id].present do - prev_body_pos = current_target_body - current_target_body = rp[my_id].pos - interp_timer = 0.0 - end - end else if type_ == MSG_ITEMS do - suic_msg_items_unpack(buf, wi, 64) - end else if type_ == MSG_ROOM_STATE do - suic_msg_room_state_unpack(buf, &room_state, &countdown_remaining, winner_name) - end - end - - # Interpolate camera position - if my_id != 255 and rp[my_id].present do - let interp_factor = interp_timer / (1.0 / 20.0) - if interp_factor > 1.0 do interp_factor = 1.0 end - let interp_body = suic_vector3 { - x: prev_body_pos.x * (1.0 - interp_factor) + current_target_body.x * interp_factor, - y: prev_body_pos.y * (1.0 - interp_factor) + current_target_body.y * interp_factor, - z: prev_body_pos.z * (1.0 - interp_factor) + current_target_body.z * interp_factor - } - cam_pos.x = interp_body.x - cam_pos.y = interp_body.y + 1.0 - cam_pos.z = interp_body.z + 0.0001 - - # Prevent camera from clipping into terrain - let terrain_h = suic_get_terrain_height(cam_pos.x, cam_pos.z) - cam_pos.y = suic_fmaxf(cam_pos.y, terrain_h + 1.5) - end - interp_timer = interp_timer + dt - - let md = suic_get_mouse_delta() - let sens = 0.0025 - yaw = yaw - md.x * sens - pitch = pitch - md.y * sens - if pitch < -1.5 do pitch = -1.5 end - if pitch > 1.5 do pitch = 1.5 end - - let view_yaw = yaw + recoil_yaw - let view_pitch = pitch + recoil_pitch - if view_pitch < -1.5 do view_pitch = -1.5 end - if view_pitch > 1.5 do view_pitch = 1.5 end - - let move_x = 0.0 - let move_z = 0.0 - if suic_is_key_down(KEY_W) do move_z = move_z + 1.0 end - if suic_is_key_down(KEY_A) do move_x = move_x + 1.0 end - if suic_is_key_down(KEY_S) do move_z = move_z - 1.0 end - if suic_is_key_down(KEY_D) do move_x = move_x - 1.0 end - - let buttons = 0 - if suic_is_key_pressed(KEY_ONE) do buttons = buttons bitor BTN_SWITCH_PISTOL end - if suic_is_key_pressed(KEY_TWO) do buttons = buttons bitor BTN_SWITCH_RIFLE end - if suic_is_key_pressed(KEY_R) do buttons = buttons bitor BTN_RELOAD end - if suic_is_key_pressed(KEY_F) do buttons = buttons bitor BTN_PICK end - if suic_is_key_pressed(KEY_H) do buttons = buttons bitor BTN_USE_MEDKIT end - if suic_is_key_pressed(KEY_SPACE) do buttons = buttons bitor BTN_JUMP end - if suic_is_key_pressed(KEY_Z) do scoped = not scoped end - - if my_id != 255 do - let in_buf = [0; 23] # sizeof(MsgInput) - suic_msg_input_pack(in_buf, MSG_INPUT, my_id, client_tick, move_x, move_z, view_yaw, view_pitch, buttons as u8) - suic_udp_sendto(sock, in_buf, 23, "127.0.0.1", SERVER_PORT) - end - - if my_id != 255 and suic_is_mouse_button_down(MOUSE_BUTTON_LEFT) and fire_cooldown <= 0.0 and rp[my_id].present do - let wpn = rp[my_id].weapon - let rate = rifle_fire_rate - if wpn == WEAPON_PISTOL do rate = pistol_fire_rate end - fire_cooldown = 1.0 / rate - - shots_in_burst = shots_in_burst + 1 - burst_reset_timer = burst_reset_time - - if wpn == WEAPON_PISTOL do - recoil_pitch = recoil_pitch + pistol_kick_pitch - recoil_yaw = recoil_yaw + (suic_get_random_value(-1000, 1000) as float / 1000.0) * pistol_kick_yaw - cross_spread = cross_spread + pistol_cross_kick + shots_in_burst as float * pistol_spray_grow - end else do - recoil_pitch = recoil_pitch + rifle_kick_pitch - recoil_yaw = recoil_yaw + (suic_get_random_value(-1000, 1000) as float / 1000.0) * rifle_kick_yaw - cross_spread = cross_spread + rifle_cross_kick + shots_in_burst as float * rifle_spray_grow - end - - let sh_buf = [0; 6] # sizeof(MsgShoot) - suic_msg_shoot_pack(sh_buf, MSG_SHOOT, my_id, client_tick) - suic_udp_sendto(sock, sh_buf, 6, "127.0.0.1", SERVER_PORT) - end - - let forward = suic_vector3 { - x: suic_sinf(view_yaw) * suic_cosf(view_pitch), - y: suic_sinf(view_pitch), - z: suic_cosf(view_yaw) * suic_cosf(view_pitch) - } - - # Offset camera position: 0.3m in front, 0.2m below - cam_pos = suic_vector3 { - x: cam_pos.x + forward.x * 0.3, - y: cam_pos.y + forward.y * 0.3 - 0.2, - z: cam_pos.z + forward.z * 0.3 - } - - # Ensure camera doesn't clip into terrain after offset - let terrain_h = suic_get_terrain_height(cam_pos.x, cam_pos.z) - cam_pos.y = suic_fmaxf(cam_pos.y, terrain_h + 1.5) - - suic_begin_drawing() - suic_clear_background(135, 206, 235, 255) # Sky blue - - let fovy = 75.0 - if scoped do fovy = 30.0 end - suic_begin_mode3d(cam_pos.x, cam_pos.y, cam_pos.z, forward.x, forward.y, forward.z, suic_vector3 { x: 0, y: 1, z: 0 }, fovy, 0) - - # Draw terrain - suic_draw_model(terrain_model, 0, 0, 0, 1.0, 1.0, 1.0, 80, 140, 70, 255) - - # Draw border - suic_draw_cube(0, 0, 0, 256.0, 1000.0, 256.0, 255, 0, 0, 100) - - # Items - let i = 0 - while i < 64 do - if wi[i].present do - let ic = suic_color { r: 220, g: 220, b: 220, a: 255 } - if wi[i].type_ == ITEM_MEDKIT do - ic = suic_color { r: 120, g: 255, b: 120, a: 255 } - end else do - if wi[i].type_ == ITEM_AMMO_PISTOL do - ic = suic_color { r: 255, g: 220, b: 120, a: 255 } - end else do - if wi[i].type_ == ITEM_AMMO_RIFLE do - ic = suic_color { r: 255, g: 180, b: 120, a: 255 } - end - end - end - - # Apply basic lighting - let item_normal = suic_vector3 { x: 0, y: 1, z: 0 } - let lit_color = suic_apply_lighting_with_shadows(ic, item_normal, wi[i].pos, dir_light.direction, dir_light.intensity, dir_light.ambient_intensity, dir_light.shadow_bias) - suic_draw_sphere(wi[i].pos.x, wi[i].pos.y, wi[i].pos.z, 0.3, lit_color.r, lit_color.g, lit_color.b, lit_color.a) - end - i = i + 1 - end - - # Players - let i = 0 - while i < 16 do - if rp[i].present do - let interp_factor = interp_timer / (1.0 / 20.0) - if interp_factor > 1.0 do interp_factor = 1.0 end - let p = suic_vector3 { - x: rp[i].prev_pos.x * (1.0 - interp_factor) + rp[i].pos.x * interp_factor, - y: rp[i].prev_pos.y * (1.0 - interp_factor) + rp[i].pos.y * interp_factor, - z: rp[i].prev_pos.z * (1.0 - interp_factor) + rp[i].pos.z * interp_factor - } - let c = suic_color { r: 255, g: 80, b: 80, a: 255 } - if i == my_id do - c = suic_color { r: 80, g: 180, b: 255, a: 255 } - end - if not rp[i].alive do - c = suic_color { r: 120, g: 120, b: 120, a: 255 } - end - - # Apply basic lighting - let player_normal = suic_vector3 { x: 0, y: 1, z: 0 } - let lit_player_color = suic_apply_lighting_with_shadows(c, player_normal, p, dir_light.direction, dir_light.intensity, dir_light.ambient_intensity, dir_light.shadow_bias) - suic_draw_capsule(p.x, p.y - 0.5, p.z, p.x, p.y + 0.5, p.z, 0.35, 8, 8, lit_player_color.r, lit_player_color.g, lit_player_color.b, lit_player_color.a) - end - i = i + 1 - end - - suic_end_mode3d() - - # Nameplates - removed for debugging - - # HUD - if my_id == 255 or not rp[my_id].present do - suic_draw_text("Connecting...", 10, 10, 20, 255, 255, 255, 255) - end - if my_id != 255 and rp[my_id].present do - suic_draw_rectangle(10, 10, 280, 110, 0, 0, 0, 120) - suic_draw_text("HP", 20, 20, 20, 255, 255, 255, 255) - let health_bar_width = (rp[my_id].hp * 220) / 100 - let health_color = suic_color { r: 255, g: 80, b: 80, a: 120 } - if rp[my_id].hp > 60 do - health_color = suic_color { r: 80, g: 255, b: 80, a: 120 } - end else do - if rp[my_id].hp > 30 do - health_color = suic_color { r: 255, g: 200, b: 80, a: 120 } - end - end - suic_draw_rectangle(20, 45, 220, 20, 40, 40, 40, 255) - suic_draw_rectangle(20, 45, health_bar_width, 20, health_color.r, health_color.g, health_color.b, health_color.a) - suic_draw_text(suic_text_format("%d", rp[my_id].hp), 250, 47, 18, 255, 255, 255, 255) - let medkit_color_r = 120 - let medkit_color_g = 120 - let medkit_color_b = 120 - if rp[my_id].medkits > 0 do - medkit_color_g = 255 - medkit_color_b = 120 - end - suic_draw_text(suic_text_format("Medkits: %d (H to use)", rp[my_id].medkits), 20, 75, 18, 120, medkit_color_g, medkit_color_b, 120) - suic_draw_text("1=Pistol 2=Rifle R=Reload F=Pick SPACE=Jump", 20, 95, 12, 150, 150, 150, 150) - - let weapon_name = "RIFLE" - let weapon_color = suic_color { r: 255, g: 150, b: 100, a: 255 } - let current_mag = rp[my_id].rifle_mag - let reserve_ammo = rp[my_id].rifle_ammo - if rp[my_id].weapon == WEAPON_PISTOL do - weapon_name = "PISTOL" - weapon_color = suic_color { r: 100, g: 200, b: 255, a: 255 } - current_mag = rp[my_id].pistol_mag - reserve_ammo = rp[my_id].pistol_ammo - end - - suic_draw_rectangle(sw - 260, sh - 120, 250, 110, 0, 0, 0, 180) - suic_draw_text(weapon_name, sw - 250, sh - 110, 28, weapon_color.r, weapon_color.g, weapon_color.b, weapon_color.a) - suic_draw_text(suic_text_format("%d", current_mag), sw - 250, sh - 75, 40, 255, 255, 255, 255) - suic_draw_text(suic_text_format("/ %d", reserve_ammo), sw - 140, sh - 65, 24, 180, 180, 180, 255) - if rp[my_id].reload_time_left > 0 do - suic_draw_text("RELOADING...", sw - 250, sh - 30, 20, 255, 200, 80, 255) - end else if current_mag == 0 do - suic_draw_text("RELOAD!", sw - 250, sh - 30, 20, 255, 80, 80, 255) - end - end - - suic_draw_fps(sw - 90, 10) - - # Room state overlay - if room_state == 0 do # Waiting - suic_draw_rectangle(sw / 2 - 150, sh / 2 - 50, 350, 100, 0, 0, 0, 200) - suic_draw_text("WAITING FOR PLAYERS", sw / 2 - 120, sh / 2 - 30, 24, 255, 255, 255, 255) - suic_draw_text("Need at least 2 players", sw / 2 - 100, sh / 2 - 5, 18, 200, 200, 200, 255) - end - if room_state == 1 do # Counting down - suic_draw_rectangle(sw / 2 - 150, sh / 2 - 50, 350, 100, 0, 0, 0, 200) - suic_draw_text("GAME STARTING SOON", sw / 2 - 120, sh / 2 - 30, 24, 255, 255, 80, 255) - suic_draw_text(suic_text_format("%.1f seconds", countdown_remaining), sw / 2 - 60, sh / 2 - 5, 20, 255, 255, 255, 255) - end - if room_state == 3 do # Finished - suic_draw_rectangle(sw / 2 - 200, sh / 2 - 50, 450, 100, 0, 0, 0, 200) - suic_draw_text("GAME FINISHED", sw / 2 - 80, sh / 2 - 30, 28, 255, 80, 80, 255) - if winner_name[0] do - suic_draw_text(suic_text_format("Winner: %s", winner_name), sw / 2 - 100, sh / 2 - 5, 24, 255, 255, 80, 255) - end - if not winner_name[0] do - suic_draw_text("No winner", sw / 2 - 50, sh / 2 - 5, 24, 255, 255, 255, 255) - end - end - - # Crosshair - let cx = sw / 2 - let cy = sh / 2 - let gap = 6 + cross_spread as int - let len = 10 - let radius = 3.0 - if scoped do - gap = 2 - len = 5 - radius = 1.5 - end - let thick = 2 - let col = suic_color { r: 240, g: 240, b: 245, a: 220 } - suic_draw_line(cx - gap - len, cy - thick / 2, cx - gap, cy - thick / 2, col.r, col.g, col.b, col.a) - suic_draw_line(cx + gap, cy - thick / 2, cx + gap + len, cy - thick / 2, col.r, col.g, col.b, col.a) - suic_draw_line(cx - thick / 2, cy - gap - len, cx - thick / 2, cy - gap, col.r, col.g, col.b, col.a) - suic_draw_line(cx - thick / 2, cy + gap, cx - thick / 2, cy + gap + len, col.r, col.g, col.b, col.a) - suic_draw_circle(cx, cy, radius, 240, 240, 245, 160) - - suic_end_drawing() - end - - suic_unload_model(terrain_model) - suic_unload_mesh(terrain_mesh) - suic_close_window() - suic_udp_socket_close(sock) - 0 -end diff --git a/src/codegen/transpiler.rs b/src/codegen/transpiler.rs index ec2a448..79772fe 100644 --- a/src/codegen/transpiler.rs +++ b/src/codegen/transpiler.rs @@ -337,10 +337,6 @@ impl Transpiler { } fn generate_struct_decl(&self, struct_decl: &CStructDecl) -> String { - // Skip predefined structs that are already declared in included headers - if matches!(struct_decl.name.as_str(), "Shader" | "Color") { - return String::new(); - } let mut output = format!("struct {} {{\n", struct_decl.name); for field in &struct_decl.fields { output.push_str(&format!(" {} {};\n", field.ty.to_string(), field.name)); @@ -350,10 +346,6 @@ impl Transpiler { } fn generate_typeinfo_decl(&self, struct_decl: &CStructDecl) -> String { - // Skip predefined structs - if matches!(struct_decl.name.as_str(), "Shader" | "Color") { - return String::new(); - } if let Some(bitmap) = self.typeinfo_map.get(&struct_decl.name) { // Generate pointer bitmap as a C array let bitmap_str = bitmap @@ -804,7 +796,7 @@ impl Transpiler { "Vec3" => "suic_vec3".to_string(), _ => format!("struct {}", struct_name), }; - format!("suic_alloc_struct(&sui_typeinfo_{}, sizeof({}), &(({}){{ {} }}))", struct_name, c_type_name, c_type_name, field_inits.join(", ")) + format!("({}){{ {} }}", c_type_name, field_inits.join(", ")) } CExpr::EnumLit(enum_name, variant_name, args) => { // Find the variant index - for simplicity, assume variants are in order diff --git a/src/import_resolver.rs b/src/import_resolver.rs index 067e276..4c3a360 100644 --- a/src/import_resolver.rs +++ b/src/import_resolver.rs @@ -81,8 +81,6 @@ struct ParsedFile { nodes: Vec, /// Hash of the file content at parse time content_hash: u64, - /// Whether this file is in unsafe mode - is_unsafe: bool, } /// Tracks global symbols and their definitions @@ -126,8 +124,6 @@ pub struct ImportResolver { processing_stack: HashSet, /// Dependency graph: file -> list of files it depends on dependency_graph: HashMap>, - /// Whether any file in the current compilation is unsafe - has_unsafe_files: bool, } impl ImportResolver { @@ -137,7 +133,6 @@ impl ImportResolver { symbol_registry: GlobalSymbolRegistry::default(), processing_stack: HashSet::new(), dependency_graph: HashMap::new(), - has_unsafe_files: false, } } @@ -196,7 +191,6 @@ impl ImportResolver { })?; let content_hash = Self::hash_content(&source); - let is_unsafe = source.trim_start().starts_with("# UNSAFE"); // Check if we have a valid cached version if let Some(cached) = self.parse_cache.get(filename) { @@ -217,7 +211,6 @@ impl ImportResolver { ParsedFile { nodes: nodes.clone(), content_hash, - is_unsafe, }, ); @@ -302,13 +295,6 @@ impl ImportResolver { let nodes = self.parse_file(filename)?; let mut result = Vec::new(); - // Check if this file is unsafe - if let Some(cached) = self.parse_cache.get(filename) { - if cached.is_unsafe { - self.has_unsafe_files = true; - } - } - // Collect dependencies let deps = self.collect_dependencies(filename, &nodes); self.dependency_graph @@ -407,23 +393,10 @@ impl ImportResolver { Ok(result) } - /// Check if the current compilation contains any unsafe files - pub fn has_unsafe_files(&self) -> bool { - self.has_unsafe_files - } - /// Resolve all imports starting from the given file pub fn resolve(&mut self, filename: &str) -> Result, ImportError> { println!("Starting import resolution..."); - self.has_unsafe_files = false; // Reset for new compilation - let result = self.resolve_imports_recursive(filename); - // Check if the main file is unsafe - if let Ok(source) = fs::read_to_string(filename) { - if source.trim_start().starts_with("# UNSAFE") { - self.has_unsafe_files = true; - } - } - result + self.resolve_imports_recursive(filename) } } diff --git a/src/main.rs b/src/main.rs index 85f7886..83cd7c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,103 +1,13 @@ use clap::Parser; use std::fs; use suicmez::{ - ast::*, codegen::transpiler::Transpiler, import_resolver::ImportResolver, lambda_lower::LambdaLowerer, monomorphize::{Monomorphizer, check_no_typevars}, - typechecker::{Type, TypeChecker}, + typechecker::TypeChecker, }; -/// Convert ASTNode to TypedASTNode for unsafe mode (with dummy types) -fn convert_to_typed_ast(nodes: &[ASTNode]) -> Vec { - nodes.iter().map(|node| { - let dummy_type = Type::Unit; // Use unit type as dummy - let dummy_expr = TypedExpr { - kind: TypedExprKind::Int(0), // dummy expression - span: Span::new(&(0..0), "dummy".to_string()), - attributes: vec![], - ty: dummy_type.clone(), - }; - - let kind = match &node.kind { - ASTNodeKind::Function(f) => TypedASTNodeKind::Function(TypedFunction { - name: f.name.clone(), - parameters: f.parameters.clone(), - args: f.args.iter().map(|(name, typ)| { - (BindingId(0), name.clone(), typ.clone()) // dummy binding id - }).collect(), - return_type: f.return_type.clone(), - body: dummy_expr.clone(), - ty: dummy_type.clone(), - }), - ASTNodeKind::Const(c) => TypedASTNodeKind::Const(TypedConst { - name: c.name.clone(), - typ: c.typ.clone(), - value: dummy_expr.clone(), - }), - ASTNodeKind::Struct(s) => TypedASTNodeKind::Struct(TypedStruct { - name: s.name.clone(), - parameters: s.parameters.clone(), - fields: s.fields.iter().map(|f| TypedField { - name: f.name.clone(), - field_type: f.field_type.clone(), - span: f.span.clone(), - }).collect(), - }), - ASTNodeKind::Enum(e) => TypedASTNodeKind::Enum(TypedEnum { - name: e.name.clone(), - parameters: e.parameters.clone(), - variants: e.variants.iter().map(|v| TypedVariant { - name: v.name.clone(), - fields: v.fields.clone(), - span: v.span.clone(), - }).collect(), - }), - ASTNodeKind::Impl(i) => TypedASTNodeKind::Impl(TypedImpl { - target: i.target.clone(), - trait_name: i.trait_name.clone(), - methods: i.methods.iter().map(|m| TypedFunction { - name: m.name.clone(), - parameters: m.parameters.clone(), - args: m.args.iter().map(|(name, typ)| { - (BindingId(0), name.clone(), typ.clone()) - }).collect(), - return_type: m.return_type.clone(), - body: dummy_expr.clone(), - ty: dummy_type.clone(), - }).collect(), - }), - ASTNodeKind::Trait(t) => TypedASTNodeKind::Trait(TypedTrait { - name: t.name.clone(), - methods: t.methods.clone(), - parameters: t.parameters.clone(), - associated_types: vec![], - }), - ASTNodeKind::Extern(e) => TypedASTNodeKind::Extern(TypedExtern { - name: e.name.clone(), - args: e.args.clone(), - return_type: e.return_type.clone(), - from: e.from.clone(), - span: e.span.clone(), - }), - ASTNodeKind::Load(l) => TypedASTNodeKind::Load(TypedLoad { - library: l.library.clone(), - alias: l.alias.clone(), - span: l.span.clone(), - }), - ASTNodeKind::Use(u) => TypedASTNodeKind::Use(u.clone()), - }; - - TypedASTNode { - kind, - span: node.span.clone(), - attributes: node.attributes.clone(), - ty: dummy_type, - } - }).collect() -} - #[derive(Parser)] #[command(author, version, about = "A compiler for the Sui language")] struct Args { @@ -296,8 +206,6 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> { } })?; - let is_unsafe = resolver.has_unsafe_files(); - println!( "Import resolution complete! {} total nodes loaded", ast_nodes.len() @@ -318,126 +226,59 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> { lowered_nodes.len() ); - let typed_nodes = if is_unsafe { - println!("Unsafe mode detected - skipping type checking"); - // Convert AST nodes to typed nodes with dummy types - convert_to_typed_ast(&lowered_nodes) - } else { - // Typecheck the AST - let mut typechecker = TypeChecker::new(); - typechecker - .typecheck_program(&lowered_nodes) - .map_err(|e| format_type_error(&source, &e))? - }; + // Typecheck the AST + let mut typechecker = TypeChecker::new(); + let typed_nodes = typechecker + .typecheck_program(&lowered_nodes) + .map_err(|e| format_type_error(&source, &e))?; - if is_unsafe { - println!("Unsafe mode - skipping monomorphization and type variable checks"); - } else { - println!( - "Type checking passed! {} nodes typechecked.", - typed_nodes.len() - ); + println!( + "Type checking passed! {} nodes typechecked.", + typed_nodes.len() + ); - // Debug: show typed nodes - println!("\nTyped AST nodes before monomorphization:"); - for (i, node) in typed_nodes.iter().enumerate() { - let node_type = match &node.kind { - suicmez::ast::TypedASTNodeKind::Function(f) => { - format!("Function({})", f.name) - } - suicmez::ast::TypedASTNodeKind::Const(c) => { - format!("Const({})", c.name) - } - suicmez::ast::TypedASTNodeKind::Struct(s) => { - format!("Struct({}) with {} params", s.name, s.parameters.len()) - } - suicmez::ast::TypedASTNodeKind::Enum(e) => { - format!("Enum({}) with {} params", e.name, e.parameters.len()) - } - suicmez::ast::TypedASTNodeKind::Impl(imp) => { - format!("Impl({})", imp.target) - } - suicmez::ast::TypedASTNodeKind::Trait(t) => { - format!("Trait({})", t.name) - } - suicmez::ast::TypedASTNodeKind::Extern(e) => { - format!("Extern({})", e.name) - } - suicmez::ast::TypedASTNodeKind::Load(l) => { - format!("Load({})", l.alias) - } - suicmez::ast::TypedASTNodeKind::Use(u) => { - format!("Use({})", u.path) - } - }; - println!(" [{}] {}", i, node_type); - } + // Debug: show typed nodes + println!("\nTyped AST nodes before monomorphization:"); + for (i, node) in typed_nodes.iter().enumerate() { + let node_type = match &node.kind { + suicmez::ast::TypedASTNodeKind::Function(f) => { + format!("Function({})", f.name) + } + suicmez::ast::TypedASTNodeKind::Const(c) => { + format!("Const({})", c.name) + } + suicmez::ast::TypedASTNodeKind::Struct(s) => { + format!("Struct({}) with {} params", s.name, s.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Enum(e) => { + format!("Enum({}) with {} params", e.name, e.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Impl(imp) => { + format!("Impl({})", imp.target) + } + suicmez::ast::TypedASTNodeKind::Trait(t) => { + format!("Trait({})", t.name) + } + suicmez::ast::TypedASTNodeKind::Extern(e) => { + format!("Extern({})", e.name) + } + suicmez::ast::TypedASTNodeKind::Load(l) => { + format!("Load({})", l.alias) + } + suicmez::ast::TypedASTNodeKind::Use(u) => { + format!("Use({})", u.path) + } + }; + println!(" [{}] {}", i, node_type); } - let final_nodes = if is_unsafe { - // Skip monomorphization for unsafe mode - typed_nodes - } else { - // Monomorphize the AST - let monomorphizer = Monomorphizer::new(); - let mono_nodes = monomorphizer - .monomorphize_program(&typed_nodes) - .map_err(|e| { - format!( - "Monomorphization error: {}{}", - e.message, - if let Some(span) = &e.span { - format!(" at {}:{}", span.file, span.start) - } else { - String::new() - } - ) - })?; - - println!( - "Monomorphization passed! {} nodes after specialization.", - mono_nodes.len() - ); - - // Print detailed info about each node - println!("\nMonomorphized AST nodes:"); - for (i, node) in mono_nodes.iter().enumerate() { - let node_type = match &node.kind { - suicmez::ast::TypedASTNodeKind::Function(f) => { - format!("Function({})", f.name) - } - suicmez::ast::TypedASTNodeKind::Const(c) => { - format!("Const({})", c.name) - } - suicmez::ast::TypedASTNodeKind::Struct(s) => { - format!("Struct({}) with {} params", s.name, s.parameters.len()) - } - suicmez::ast::TypedASTNodeKind::Enum(e) => { - format!("Enum({}) with {} params", e.name, e.parameters.len()) - } - suicmez::ast::TypedASTNodeKind::Impl(imp) => { - format!("Impl({})", imp.target) - } - suicmez::ast::TypedASTNodeKind::Trait(t) => { - format!("Trait({})", t.name) - } - suicmez::ast::TypedASTNodeKind::Extern(e) => { - format!("Extern({})", e.name) - } - suicmez::ast::TypedASTNodeKind::Load(l) => { - format!("Load({})", l.alias) - } - suicmez::ast::TypedASTNodeKind::Use(u) => { - format!("Use({})", u.path) - } - }; - println!(" [{}] {}", i, node_type); - } - - // Check that no type variables remain - check_no_typevars(&mono_nodes).map_err(|e| { + // Monomorphize the AST + let monomorphizer = Monomorphizer::new(); + let mono_nodes = monomorphizer + .monomorphize_program(&typed_nodes) + .map_err(|e| { format!( - "Type variable check failed: {}{}", + "Monomorphization error: {}{}", e.message, if let Some(span) = &e.span { format!(" at {}:{}", span.file, span.start) @@ -447,15 +288,65 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> { ) })?; - println!("Type variable check passed! No type variables remain in AST."); + println!( + "Monomorphization passed! {} nodes after specialization.", + mono_nodes.len() + ); - mono_nodes - }; + // Print detailed info about each node + println!("\nMonomorphized AST nodes:"); + for (i, node) in mono_nodes.iter().enumerate() { + let node_type = match &node.kind { + suicmez::ast::TypedASTNodeKind::Function(f) => { + format!("Function({})", f.name) + } + suicmez::ast::TypedASTNodeKind::Const(c) => { + format!("Const({})", c.name) + } + suicmez::ast::TypedASTNodeKind::Struct(s) => { + format!("Struct({}) with {} params", s.name, s.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Enum(e) => { + format!("Enum({}) with {} params", e.name, e.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Impl(imp) => { + format!("Impl({})", imp.target) + } + suicmez::ast::TypedASTNodeKind::Trait(t) => { + format!("Trait({})", t.name) + } + suicmez::ast::TypedASTNodeKind::Extern(e) => { + format!("Extern({})", e.name) + } + suicmez::ast::TypedASTNodeKind::Load(l) => { + format!("Load({})", l.alias) + } + suicmez::ast::TypedASTNodeKind::Use(u) => { + format!("Use({})", u.path) + } + }; + println!(" [{}] {}", i, node_type); + } + + // Check that no type variables remain + check_no_typevars(&mono_nodes).map_err(|e| { + format!( + "Type variable check failed: {}{}", + e.message, + if let Some(span) = &e.span { + format!(" at {}:{}", span.file, span.start) + } else { + String::new() + } + ) + })?; + + println!("Type variable check passed! No type variables remain in AST."); // Generate C code let mut transpiler = Transpiler::new(debug); let c_code = transpiler - .transpile_program(&final_nodes) + .transpile_program(&mono_nodes) .map_err(|e| format!("Code generation error: {}", e))?; // Write C code to file diff --git a/tests/arrays.c b/tests/arrays.c index 7e33cc5..e9aed4f 100644 --- a/tests/arrays.c +++ b/tests/arrays.c @@ -23,28 +23,7 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat } -struct Color { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; -}; -struct Shader { - int id; -}; -static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 }; -static const TypeInfo sui_typeinfo_Color = { - .field_count = 4, - .pointer_count = 0, - .pointer_bitmap = sui_bitmap_Color -}; -static const uint8_t sui_bitmap_Shader[] = { 0 }; -static const TypeInfo sui_typeinfo_Shader = { - .field_count = 1, - .pointer_count = 0, - .pointer_bitmap = sui_bitmap_Shader -}; int suic_main(void); diff --git a/tests/basic_types.c b/tests/basic_types.c index eb6eb33..27443d9 100644 --- a/tests/basic_types.c +++ b/tests/basic_types.c @@ -23,28 +23,7 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat } -struct Color { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; -}; -struct Shader { - int id; -}; -static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 }; -static const TypeInfo sui_typeinfo_Color = { - .field_count = 4, - .pointer_count = 0, - .pointer_bitmap = sui_bitmap_Color -}; -static const uint8_t sui_bitmap_Shader[] = { 0 }; -static const TypeInfo sui_typeinfo_Shader = { - .field_count = 1, - .pointer_count = 0, - .pointer_bitmap = sui_bitmap_Shader -}; int suic_main(void); diff --git a/tests/control_flow.c b/tests/control_flow.c index 69edccc..edba436 100644 --- a/tests/control_flow.c +++ b/tests/control_flow.c @@ -1,4 +1,4 @@ -#include "libsuicmez/libsuicmez.h" +#include "../libsuicmez/libsuicmez.h" #include #include #include @@ -23,38 +23,13 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat } -struct Color { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; -}; -struct Shader { - int id; -}; -static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 }; -static const TypeInfo sui_typeinfo_Color = { - .field_count = 4, - .pointer_count = 0, - .pointer_bitmap = sui_bitmap_Color -}; -static const uint8_t sui_bitmap_Shader[] = { 0 }; -static const TypeInfo sui_typeinfo_Shader = { - .field_count = 1, - .pointer_count = 0, - .pointer_bitmap = sui_bitmap_Shader -}; int suic_main(void); int suic_main(void) { - if (true) { - 1; - } else { - 0; - } + (true ? 1 : 0); int i = 0; while ((i < 5)) { i = (i + 1); diff --git a/tests/functions.c b/tests/functions.c index ec00f8d..08378bb 100644 --- a/tests/functions.c +++ b/tests/functions.c @@ -1,4 +1,4 @@ -#include "libsuicmez/libsuicmez.h" +#include "../libsuicmez/libsuicmez.h" #include #include #include @@ -23,28 +23,7 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat } -struct Color { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; -}; -struct Shader { - int id; -}; -static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 }; -static const TypeInfo sui_typeinfo_Color = { - .field_count = 4, - .pointer_count = 0, - .pointer_bitmap = sui_bitmap_Color -}; -static const uint8_t sui_bitmap_Shader[] = { 0 }; -static const TypeInfo sui_typeinfo_Shader = { - .field_count = 1, - .pointer_count = 0, - .pointer_bitmap = sui_bitmap_Shader -}; int add(int x, int y); int suic_main(void); diff --git a/tests/structs.c b/tests/structs.c index 5f9a149..6faa376 100644 --- a/tests/structs.c +++ b/tests/structs.c @@ -31,8 +31,6 @@ struct Person { char* name; int age; }; -; -; static const uint8_t sui_bitmap_Point[] = { 0, 0 }; static const TypeInfo sui_typeinfo_Point = { @@ -47,14 +45,12 @@ static const TypeInfo sui_typeinfo_Person = { .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 })); + 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; } diff --git a/tests/structs.o b/tests/structs.o index 81c4f34..13e75a4 100755 Binary files a/tests/structs.o and b/tests/structs.o differ