/* 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 #include #include #include 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); extern bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); extern bool CheckCollisionCircles(Vector2 c1, float r1, Vector2 c2, float r2); extern bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); extern bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2); extern bool CheckCollisionPointRec(Vector2 point, Rectangle rec); extern bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); extern bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); extern bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold); extern bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCount); extern bool CheckCollisionLines(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2, Vector2 *collisionPoint); /* 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); } bool flan_rl_check_collision_recs(const Rectangle *a, const Rectangle *b) { return CheckCollisionRecs(*a, *b); } bool flan_rl_check_collision_circles(const Vector2 *c1, float r1, const Vector2 *c2, float r2) { return CheckCollisionCircles(*c1, r1, *c2, r2); } bool flan_rl_check_collision_circle_rec(const Vector2 *center, float radius, const Rectangle *rec) { return CheckCollisionCircleRec(*center, radius, *rec); } bool flan_rl_check_collision_circle_line(const Vector2 *center, float radius, const Vector2 *p1, const Vector2 *p2) { return CheckCollisionCircleLine(*center, radius, *p1, *p2); } bool flan_rl_check_collision_point_rec(const Vector2 *point, const Rectangle *rec) { return CheckCollisionPointRec(*point, *rec); } bool flan_rl_check_collision_point_circle(const Vector2 *point, const Vector2 *center, float radius) { return CheckCollisionPointCircle(*point, *center, radius); } bool flan_rl_check_collision_point_triangle(const Vector2 *point, const Vector2 *a, const Vector2 *b, const Vector2 *c) { return CheckCollisionPointTriangle(*point, *a, *b, *c); } bool flan_rl_check_collision_point_line(const Vector2 *point, const Vector2 *p1, const Vector2 *p2, int threshold) { return CheckCollisionPointLine(*point, *p1, *p2, threshold); } /* A Flan slice arrives as ptr+len, the same shape a string does. raylib wants * an int count, and a polygon with more than INT_MAX points is not a thing * that happens; the clamp is there so the conversion is not silent. */ bool flan_rl_check_collision_point_poly(const Vector2 *point, const Vector2 *points, long long n) { if (n > INT_MAX) n = INT_MAX; return CheckCollisionPointPoly(*point, points, (int)n); } bool flan_rl_check_collision_lines(const Vector2 *a1, const Vector2 *a2, const Vector2 *b1, const Vector2 *b2, Vector2 *out) { return CheckCollisionLines(*a1, *a2, *b1, *b2, out); } /* ── Images ───────────────────────────────────────────────────────── * * An Image is pixels in RAM, so all of this runs with no window and no GL * context — which is why it is the part of the package that a headless test * can actually assert rather than merely link. `data` is the pixel buffer * raylib owns; `format` is a PixelFormat enum and GenImageColor makes 7 * (uncompressed R8G8B8A8). * * raylib 5.5 spells the predicate IsImageValid. IsImageReady, which the 5.1 * header still had, is gone — checked with nm -D, not remembered. */ typedef struct { void *data; int width, height, mipmaps, format; } Image; extern Image LoadImage(const char *fileName); extern bool IsImageValid(Image image); extern void UnloadImage(Image image); extern bool ExportImage(Image image, const char *fileName); extern Image GenImageColor(int width, int height, Color color); extern void ImageResize(Image *image, int newWidth, int newHeight); extern void ImageResizeNN(Image *image, int newWidth, int newHeight); extern void ImageCrop(Image *image, Rectangle crop); extern void ImageFlipHorizontal(Image *image); extern void ImageFlipVertical(Image *image); extern void ImageDrawPixel(Image *dst, int posX, int posY, Color color); extern Color GetImageColor(Image image, int x, int y); extern Texture2D LoadTextureFromImage(Image image); void flan_rl_load_image(const char *path, long long n, Image *out) { char buf[PATH_MAX]; *out = LoadImage(cstr(path, n, buf, sizeof buf)); } bool flan_rl_is_image_valid(const Image *image) { return IsImageValid(*image); } void flan_rl_unload_image(const Image *image) { UnloadImage(*image); } bool flan_rl_export_image(const Image *image, const char *path, long long n) { char buf[PATH_MAX]; return ExportImage(*image, cstr(path, n, buf, sizeof buf)); } void flan_rl_gen_image_color(int width, int height, const Color *color, Image *out) { *out = GenImageColor(width, height, *color); } void flan_rl_image_resize(Image *image, int w, int h) { ImageResize(image, w, h); } void flan_rl_image_resize_nn(Image *image, int w, int h) { ImageResizeNN(image, w, h); } void flan_rl_image_crop(Image *image, const Rectangle *crop) { ImageCrop(image, *crop); } void flan_rl_image_flip_horizontal(Image *image) { ImageFlipHorizontal(image); } void flan_rl_image_flip_vertical(Image *image) { ImageFlipVertical(image); } void flan_rl_image_draw_pixel(Image *dst, int x, int y, const Color *color) { ImageDrawPixel(dst, x, y, *color); } void flan_rl_get_image_color(const Image *image, int x, int y, Color *out) { *out = GetImageColor(*image, x, y); } void flan_rl_load_texture_from_image(const Image *image, Texture2D *out) { *out = LoadTextureFromImage(*image); } /* ── Shapes, text and timing ───────────────────────────────────────── * * All of the drawing below needs a GL context and therefore a window, so none * of it can be in the acceptance table — it is exercised by running sand.flan * and looking. The three prototypes most likely to be remembered wrong were * checked against nm -D on libraylib.so.550 rather than against a header: * raylib 5.5 moved the line thickness off DrawRectangleRoundedLines onto * DrawRectangleRoundedLinesEx, so the four-argument form here is the 5.5 one * and not the 5.1 one. * * MeasureText, GetFrameTime, GetTime and GetScreenWidth/Height need no GL * context but do need InitWindow: the first reads the default font, which * only InitWindow loads, and the others read window state. Headless they all * answer 0 — measured, not assumed — so they are no more assertable than the * drawing is. */ extern void DrawPixel(int posX, int posY, Color color); extern void DrawPixelV(Vector2 position, Color color); extern void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); extern void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); extern void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); extern void DrawCircle(int centerX, int centerY, float radius, Color color); extern void DrawCircleV(Vector2 center, float radius, Color color); extern void DrawCircleLines(int centerX, int centerY, float radius, Color color); extern void DrawCircleLinesV(Vector2 center, float radius, Color color); extern void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); extern void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); extern void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); extern void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); extern void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); extern void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); extern void DrawRectangleV(Vector2 position, Vector2 size, Color color); extern void DrawRectangleRec(Rectangle rec, Color color); extern void DrawRectangleLines(int posX, int posY, int width, int height, Color color); extern void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); extern void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); extern void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color); extern void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float lineThick, Color color); extern void DrawText(const char *text, int posX, int posY, int fontSize, Color color); extern int MeasureText(const char *text, int fontSize); extern float GetFrameTime(void); extern double GetTime(void); extern int GetScreenWidth(void); extern int GetScreenHeight(void); void flan_rl_draw_pixel(int x, int y, const Color *c) { DrawPixel(x, y, *c); } void flan_rl_draw_pixel_v(const Vector2 *p, const Color *c) { DrawPixelV(*p, *c); } void flan_rl_draw_line(int x1, int y1, int x2, int y2, const Color *c) { DrawLine(x1, y1, x2, y2, *c); } void flan_rl_draw_line_v(const Vector2 *a, const Vector2 *b, const Color *c) { DrawLineV(*a, *b, *c); } void flan_rl_draw_line_ex(const Vector2 *a, const Vector2 *b, float thick, const Color *c) { DrawLineEx(*a, *b, thick, *c); } void flan_rl_draw_circle(int x, int y, float radius, const Color *c) { DrawCircle(x, y, radius, *c); } void flan_rl_draw_circle_v(const Vector2 *center, float radius, const Color *c) { DrawCircleV(*center, radius, *c); } void flan_rl_draw_circle_lines(int x, int y, float radius, const Color *c) { DrawCircleLines(x, y, radius, *c); } void flan_rl_draw_circle_lines_v(const Vector2 *center, float radius, const Color *c) { DrawCircleLinesV(*center, radius, *c); } void flan_rl_draw_ellipse(int x, int y, float rh, float rv, const Color *c) { DrawEllipse(x, y, rh, rv, *c); } void flan_rl_draw_ellipse_lines(int x, int y, float rh, float rv, const Color *c) { DrawEllipseLines(x, y, rh, rv, *c); } void flan_rl_draw_ring(const Vector2 *center, float inner, float outer, float start, float end, int segments, const Color *c) { DrawRing(*center, inner, outer, start, end, segments, *c); } void flan_rl_draw_ring_lines(const Vector2 *center, float inner, float outer, float start, float end, int segments, const Color *c) { DrawRingLines(*center, inner, outer, start, end, segments, *c); } void flan_rl_draw_triangle(const Vector2 *a, const Vector2 *b, const Vector2 *d, const Color *c) { DrawTriangle(*a, *b, *d, *c); } void flan_rl_draw_triangle_lines(const Vector2 *a, const Vector2 *b, const Vector2 *d, const Color *c) { DrawTriangleLines(*a, *b, *d, *c); } void flan_rl_draw_rectangle_v(const Vector2 *position, const Vector2 *size, const Color *c) { DrawRectangleV(*position, *size, *c); } void flan_rl_draw_rectangle_rec(const Rectangle *rec, const Color *c) { DrawRectangleRec(*rec, *c); } void flan_rl_draw_rectangle_lines(int x, int y, int w, int h, const Color *c) { DrawRectangleLines(x, y, w, h, *c); } void flan_rl_draw_rectangle_lines_ex(const Rectangle *rec, float thick, const Color *c) { DrawRectangleLinesEx(*rec, thick, *c); } void flan_rl_draw_rectangle_rounded(const Rectangle *rec, float roundness, int segments, const Color *c) { DrawRectangleRounded(*rec, roundness, segments, *c); } /* Four arguments, not five: 5.5's DrawRectangleRoundedLines has no thickness * and the Ex variant below is where it went. Getting this wrong links fine. */ void flan_rl_draw_rectangle_rounded_lines(const Rectangle *rec, float roundness, int segments, const Color *c) { DrawRectangleRoundedLines(*rec, roundness, segments, *c); } void flan_rl_draw_rectangle_rounded_lines_ex(const Rectangle *rec, float roundness, int segments, float thick, const Color *c) { DrawRectangleRoundedLinesEx(*rec, roundness, segments, thick, *c); } void flan_rl_draw_text(const char *text, long long n, int x, int y, int font_size, const Color *c) { char buf[512]; DrawText(cstr(text, n, buf, sizeof buf), x, y, font_size, *c); } int flan_rl_measure_text(const char *text, long long n, int font_size) { char buf[512]; return MeasureText(cstr(text, n, buf, sizeof buf), font_size); } float flan_rl_get_frame_time(void) { return GetFrameTime(); } double flan_rl_get_time(void) { return GetTime(); } int flan_rl_get_screen_width(void) { return GetScreenWidth(); } int flan_rl_get_screen_height(void) { return GetScreenHeight(); }