flan/vendor/raylib/shim.c
Joseph Ferano 856f7dad7b A camera whose layout a round trip could not have pinned
GetScreenToWorld2D and GetWorldToScreen2D are pure arithmetic over every
field of a Camera2D, so they run with no window at all — the best headless
material the package has had. Both directions are asserted as absolute
answers rather than as a round trip, because an inverse cancels a permuted
layout exactly the way store-and-return does.

The rotated case earns its awkwardness: exchanging x and y in Vector2
mirrors every component-wise formula and the answer comes back mirrored
too, so nothing until now could tell the two floats apart. A rotation mixes
them. It reports ok/bad against a tolerance because 90 degrees goes through
sinf and the answer is 27.9999981, and the table compares stdout byte for
byte at -O0 and -O2.
2026-09-11 18:48:57 +07:00

167 lines
7.0 KiB
C

/* The C half of the raylib binding: one wrapper per `declare` in raylib.flan.
*
* The wrappers exist so that no aggregate is ever passed or returned across
* the Flan/C boundary. raylib takes Color by value and returns Vector2 by
* value, and a small aggregate is passed differently on x86-64 (<2 x float>,
* i32), on arm64, and on wasm32. Here, clang classifies each one correctly for
* whichever target the build is for; in the Flan backend it would be three
* conventions to reimplement. Everything below therefore trades in scalars and
* pointers only — see raylib.flan.
*
* raylib's own headers are not needed and not used: these prototypes are the
* declarations, so the build has no dependency on raylib-devel being
* installed, only on the shared library being linkable.
*/
#include <stdbool.h>
#include <stddef.h>
#include <limits.h>
#include <string.h>
typedef struct { float x, y; } Vector2;
typedef struct { unsigned char r, g, b, a; } Color;
typedef struct { unsigned int id; int width, height, mipmaps, format; } Texture2D;
typedef struct { float x, y, width, height; } Rectangle;
typedef struct { Vector2 offset, target; float rotation, zoom; } Camera2D;
extern void InitWindow(int width, int height, const char *title);
extern void CloseWindow(void);
extern bool WindowShouldClose(void);
extern void SetTargetFPS(int fps);
extern void SetTraceLogLevel(int level);
extern bool IsKeyPressed(int key);
extern bool IsKeyDown(int key);
extern bool IsKeyReleased(int key);
extern bool IsMouseButtonPressed(int button);
extern bool IsMouseButtonDown(int button);
extern bool IsMouseButtonReleased(int button);
extern Vector2 GetMousePosition(void);
extern Color GetColor(unsigned int hex);
extern void BeginDrawing(void);
extern void EndDrawing(void);
extern void DrawFPS(int x, int y);
extern void ClearBackground(Color color);
extern void DrawRectangle(int x, int y, int width, int height, Color color);
extern void SetShapesTexture(Texture2D texture, Rectangle source);
extern Texture2D GetShapesTexture(void);
extern Rectangle GetShapesTextureRectangle(void);
extern Rectangle GetCollisionRec(Rectangle a, Rectangle b);
extern Texture2D LoadTexture(const char *fileName);
extern bool IsTextureValid(Texture2D texture);
extern void UnloadTexture(Texture2D texture);
extern void DrawTexture(Texture2D texture, int posX, int posY, Color tint);
extern void DrawTextureV(Texture2D texture, Vector2 position, Color tint);
extern void DrawTextureEx(Texture2D texture, Vector2 position, float rotation,
float scale, Color tint);
extern void DrawTextureRec(Texture2D texture, Rectangle source,
Vector2 position, Color tint);
extern void BeginMode2D(Camera2D camera);
extern void EndMode2D(void);
extern Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera);
extern Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera);
/* A Flan string arrives as ptr+len and is not NUL-terminated, so a C API that
* wants a C string needs a copy. Two callers want one: the window title and a
* texture's file path. Each passes a buffer big enough for what it is — 256
* for a title, PATH_MAX for a path — and truncating is better than reading
* past the end. A truncated path fails to open and LoadTexture returns an id
* of 0, which is what texture-valid? is for. */
static const char *cstr(const char *p, long long n, char *buf, size_t cap) {
size_t k = (size_t)n < cap - 1 ? (size_t)n : cap - 1;
memcpy(buf, p, k);
buf[k] = '\0';
return buf;
}
void flan_rl_init_window(int width, int height, const char *title, long long n) {
char buf[256];
InitWindow(width, height, cstr(title, n, buf, sizeof buf));
}
void flan_rl_close_window(void) { CloseWindow(); }
bool flan_rl_window_should_close(void) { return WindowShouldClose(); }
void flan_rl_set_target_fps(int fps) { SetTargetFPS(fps); }
void flan_rl_set_trace_log_level(int l) { SetTraceLogLevel(l); }
bool flan_rl_is_key_pressed(int key) { return IsKeyPressed(key); }
bool flan_rl_is_key_down(int key) { return IsKeyDown(key); }
bool flan_rl_is_key_released(int key) { return IsKeyReleased(key); }
bool flan_rl_is_mouse_button_pressed(int b) { return IsMouseButtonPressed(b); }
bool flan_rl_is_mouse_button_down(int b) { return IsMouseButtonDown(b); }
bool flan_rl_is_mouse_button_released(int b) { return IsMouseButtonReleased(b); }
void flan_rl_get_mouse_position(Vector2 *out) { *out = GetMousePosition(); }
void flan_rl_get_color(unsigned int hex, Color *out) { *out = GetColor(hex); }
void flan_rl_begin_drawing(void) { BeginDrawing(); }
void flan_rl_end_drawing(void) { EndDrawing(); }
void flan_rl_draw_fps(int x, int y) { DrawFPS(x, y); }
void flan_rl_clear_background(const Color *color) { ClearBackground(*color); }
void flan_rl_draw_rectangle(int x, int y, int width, int height,
const Color *color) {
DrawRectangle(x, y, width, height, *color);
}
void flan_rl_set_shapes_texture(const Texture2D *texture, const Rectangle *source) {
SetShapesTexture(*texture, *source);
}
void flan_rl_get_shapes_texture(Texture2D *out) { *out = GetShapesTexture(); }
void flan_rl_get_shapes_texture_rectangle(Rectangle *out) {
*out = GetShapesTextureRectangle();
}
void flan_rl_get_collision_rec(const Rectangle *a, const Rectangle *b,
Rectangle *out) {
*out = GetCollisionRec(*a, *b);
}
void flan_rl_load_texture(const char *path, long long n, Texture2D *out) {
char buf[PATH_MAX];
*out = LoadTexture(cstr(path, n, buf, sizeof buf));
}
bool flan_rl_is_texture_valid(const Texture2D *texture) {
return IsTextureValid(*texture);
}
void flan_rl_unload_texture(const Texture2D *texture) { UnloadTexture(*texture); }
void flan_rl_draw_texture(const Texture2D *texture, int x, int y,
const Color *tint) {
DrawTexture(*texture, x, y, *tint);
}
void flan_rl_draw_texture_v(const Texture2D *texture, const Vector2 *position,
const Color *tint) {
DrawTextureV(*texture, *position, *tint);
}
void flan_rl_draw_texture_ex(const Texture2D *texture, const Vector2 *position,
float rotation, float scale, const Color *tint) {
DrawTextureEx(*texture, *position, rotation, scale, *tint);
}
void flan_rl_draw_texture_rec(const Texture2D *texture, const Rectangle *source,
const Vector2 *position, const Color *tint) {
DrawTextureRec(*texture, *source, *position, *tint);
}
void flan_rl_begin_mode_2d(const Camera2D *camera) { BeginMode2D(*camera); }
void flan_rl_end_mode_2d(void) { EndMode2D(); }
void flan_rl_get_screen_to_world_2d(const Vector2 *position,
const Camera2D *camera, Vector2 *out) {
*out = GetScreenToWorld2D(*position, *camera);
}
void flan_rl_get_world_to_screen_2d(const Vector2 *position,
const Camera2D *camera, Vector2 *out) {
*out = GetWorldToScreen2D(*position, *camera);
}