flan/vendor/raylib/shim.c
Joseph Ferano a178135143 Textures, which cannot be tested without a GPU
LoadTexture, UnloadTexture, the four DrawTexture variants and IsTextureValid.
Nothing about them pushes against the aggregate rule: every raylib signature
here takes its structs by value, and every one has an obvious pointer form the
shim dereferences, so the declarations are scalars and pointers as before.

The predicate is IsTextureValid and not IsTextureReady, which this version of
raylib does not export at all — 5.5 renamed it, and calling the old name would
be a link error rather than a silent miss. It is bound because the failure it
reports is otherwise invisible: LoadTexture on a missing file returns a texture
with an id of 0 and says so only on the trace log, and then every draw with it
is a no-op that looks like a drawing bug.

cstr's one caller used to be the window title, and its comment said so. A path
is the second caller and wants far more than 256 bytes, so each caller now
passes a buffer sized for what it holds. Truncating still beats reading past
the end: a truncated path simply fails to open, and texture-valid? is how the
program notices.

None of this is in the acceptance table, and deliberately. Loading a texture
needs a GL context, so anything headless would be asserting on the failure
path while appearing to test the working one. It is exercised by sand.flan.
2026-09-11 17:52:51 +07:00

149 lines
6.2 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;
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);
/* 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);
}