Gama C Library
Gama C API Documentation
image.h
Go to the documentation of this file.
1#pragma once
2
3#include "../color.h"
4
5#include "../gapi.h"
6#include "../position.h"
7#include "./position.h"
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13// --- Image Structure ---
14
15/**
16 * @brief Structure representing the 2D projected output of a 3D scene.
17 *
18 * This struct acts as a buffer containing the 2D screen-space coordinates,
19 * colors, and indices of triangles generated by the 3D projection pipeline.
20 * It also manages internal scratch buffers for optimization.
21 */
22typedef struct {
23 // Public Data: Result of projection
24 gmPos *vertices; /**< Array of 2D screen-space vertex positions. */
25 gmColor *colors; /**< Array of colors, one per triangle. */
26 size_t *triangles; /**< Array of vertex indices, 3 per triangle. */
27 double *depths; /**< Array of average Z-depths, one per triangle, used for sorting. */
28
29 // Active counts for the current frame
30 size_t n_vertices; /**< Current number of vertices stored. */
31 size_t n_colors; /**< Current number of colors stored (should match n_triangles). */
32 size_t n_triangles; /**< Current number of triangles stored. */
33
34 // Actual allocated memory size (Capacity)
35 size_t cap_vertices; /**< Allocated capacity for vertices array. */
36 size_t cap_colors; /**< Allocated capacity for colors array. */
37 size_t cap_triangles; /**< Allocated capacity for triangles (indices) array. */
38 size_t cap_depths; /**< Allocated capacity for depths array. */
39
40 // --- Optimization: Per-Image Scratch Buffers ---
41 // These allow us to reuse memory across frames for THIS specific image
42 // without using global variables that break when multiple images exist.
43 struct {
44 gm3Pos *world_verts; /**< Temp storage for 3D world coordinates before projection. */
45 size_t cap_world; /**< Allocated capacity for world_verts. */
46
47 void *sort_buf; /**< Temp storage for sorting triangles by depth. */
48 size_t cap_sort; /**< Allocated capacity for sort_buf. */
49
50 double *tri; /**< Temp storage for sorted triangle vertex data (x1,y1,x2,y2,x3,y3). */
51 gmColor *cols; /**< Temp storage for sorted triangle colors. */
52 size_t cap_tri; /**< Allocated capacity for tri and cols. */
53
54 } _internal; /**< Internal scratch buffers for rendering optimizations. */
55
56} gm3Image;
57
58/**
59 * @brief Initializes a new `gm3Image` struct.
60 *
61 * This function creates a `gm3Image` instance and ensures all its internal
62 * pointers are NULL and counts are zero, preventing undefined behavior.
63 *
64 * @return A new, zero-initialized `gm3Image` instance.
65 */
66static inline gm3Image gm3_image() {
67 return (gm3Image){0}; // Zero-init guarantees NULL pointers
68}
69
70/**
71 * Call this at the start of a new frame.
72 * It resets the counters so you can overwrite data,
73 * but keeps the heavy memory allocations alive for speed.
74 */
75static inline void gm3_image_reset(gm3Image *i) {
76 i->n_vertices = 0;
77 i->n_triangles = 0;
78 i->n_colors = 0;
79 // We do NOT free the arrays here. That's the optimization.
80}
81
82/**
83 * Call this when you are completely done with the image object
84 * and want to release memory to the OS.
85 */
87 if (i->vertices)
88 free(i->vertices);
89 if (i->colors)
90 free(i->colors);
91 if (i->triangles)
92 free(i->triangles);
93 if (i->depths)
94 free(i->depths);
95
96 // Free the scratch buffers too
99 if (i->_internal.sort_buf)
101 if (i->_internal.tri)
102 free(i->_internal.tri);
103 if (i->_internal.cols)
104 free(i->_internal.cols);
105
106 memset(i, 0, sizeof(gm3Image));
107}
108
109/**
110 * @internal
111 * @brief Ensures the allocated capacity for `gm3Image` buffers is sufficient.
112 *
113 * This helper function reallocates internal buffers (vertices, triangles, colors, depths)
114 * if the `new_v` (new vertex count) or `new_t` (new triangle count) exceeds
115 * the current capacity. It uses a doubling strategy for efficiency.
116 *
117 * @param img Pointer to the `gm3Image` to check/resize.
118 * @param new_v The minimum required vertex capacity.
119 * @param new_t The minimum required triangle capacity.
120 * @return 1 on success, 0 on memory allocation failure.
121 */
122static inline int gm3_image_ensure_cap(gm3Image *img, size_t new_v,
123 size_t new_t) {
124 // 1. Resize Vertex buffer if needed
125 if (new_v > img->cap_vertices) {
126 size_t new_cap = img->cap_vertices == 0 ? new_v : img->cap_vertices * 2;
127 if (new_cap < new_v)
128 new_cap = new_v + 128; // Padding
129
130 void *tmp = realloc(img->vertices, new_cap * sizeof(gmPos));
131 if (!tmp)
132 return 0;
133 img->vertices = tmp;
134 img->cap_vertices = new_cap;
135 }
136
137 // 2. Resize Triangle buffers (indices, colors, depths) if needed
138 if (new_t > img->cap_triangles) {
139 size_t new_cap = img->cap_triangles == 0 ? new_t : img->cap_triangles * 2;
140 if (new_cap < new_t)
141 new_cap = new_t + 128;
142
143 void *t_ptr = realloc(img->triangles, new_cap * 3 * sizeof(size_t));
144 void *c_ptr = realloc(img->colors, new_cap * sizeof(gmColor));
145 void *d_ptr = realloc(img->depths, new_cap * sizeof(double));
146
147 if (!t_ptr || !c_ptr || !d_ptr)
148 return 0;
149
150 img->triangles = t_ptr;
151 img->colors = c_ptr;
152 img->depths = d_ptr;
153 img->cap_triangles = new_cap;
154 img->cap_colors = new_cap;
155 img->cap_depths = new_cap;
156 }
157 return 1;
158}
159
160// --- Drawing Logic ---
161
162/**
163 * @internal
164 * @brief Helper struct for sorting triangles by depth.
165 */
166typedef struct {
167 size_t tri_idx; /**< The index of the triangle in the original arrays. */
168 double z; /**< The Z-depth of the triangle. */
170
171/**
172 * @internal
173 * @brief Comparison function for `qsort` to sort `_gmImageDepthEntry` by Z-depth.
174 *
175 * Sorts triangles from farthest Z to nearest Z (Painter's Algorithm).
176 *
177 * @param a Pointer to the first `_gmImageDepthEntry`.
178 * @param b Pointer to the second `_gmImageDepthEntry`.
179 * @return -1 if `a` is farther, 1 if `b` is farther, 0 if equal.
180 */
181int _gm3_depth_compare(const void *a, const void *b) {
184 // Sort Farthest Z to Nearest Z (Painters Algorithm)
185 if (rb->z < ra->z)
186 return -1;
187 else if (rb->z > ra->z)
188 return 1;
189 else
190 return 0;
191}
192
193#ifndef GM_NO_GAPI
194/**
195 * @brief Draws the projected 3D scene contained within a `gm3Image` onto the screen.
196 *
197 * This function sorts the projected triangles by depth (Painter's Algorithm)
198 * and then calls the `gapi_draw_triangles` function to render them.
199 *
200 * @param img Pointer to the `gm3Image` containing the projected scene data.
201 * @param x The X-offset for drawing the entire image.
202 * @param y The Y-offset for drawing the entire image.
203 * @param scale The scaling factor to apply to the projected image.
204 * @return 1 on successful drawing, 0 if no triangles to draw, -1 on memory allocation failure.
205 */
206int gm3_draw_image(gm3Image *img, double x, double y, double scale) {
207 if (!img || img->n_triangles == 0)
208 return 0;
209
210 // 1. Ensure Sort Buffer Capacity (stored in the image struct)
211 if (img->n_triangles > img->_internal.cap_sort) {
212 size_t new_cap = img->n_triangles + 512;
213 void *tmp =
214 realloc(img->_internal.sort_buf, new_cap * sizeof(_gmImageDepthEntry));
215 if (!tmp)
216 return -1;
217 img->_internal.sort_buf = tmp;
218 img->_internal.cap_sort = new_cap;
219 }
220
222
223 // 2. Fill Sort Buffer
224 for (size_t i = 0; i < img->n_triangles; i++) {
225 sort_arr[i].tri_idx = i;
226 sort_arr[i].z = img->depths[i];
227 }
228
229 // 3. Sort
230 qsort(sort_arr, img->n_triangles, sizeof(_gmImageDepthEntry),
232
233 // 4. Draw Loop
234 gmPos *verts = img->vertices;
235 gmColor *cols = img->colors;
236 size_t *indices = img->triangles;
237
238 if (img->_internal.cap_tri < img->n_triangles) {
239 if (img->_internal.tri) {
240 free(img->_internal.tri);
241 free(img->_internal.cols);
242 }
243 img->_internal.tri = malloc(img->n_triangles * 6 * sizeof(double));
244 img->_internal.cols = malloc(img->n_triangles * sizeof(gmColor));
245 img->_internal.cap_tri = img->n_triangles;
246 if (!img->_internal.tri || !img->_internal.cols) {
247 if (img->_internal.tri)
248 free(img->_internal.tri);
249 if (img->_internal.cols)
250 free(img->_internal.cols);
251 return -1;
252 }
253 }
254
255 for (size_t i = 0; i < img->n_triangles; i++) {
256 size_t tidx = sort_arr[i].tri_idx;
257 size_t idx_base = tidx * 3;
258 img->_internal.cols[i] = img->colors[tidx];
259
260 for (size_t j = 0; j < 3; j++) {
261 img->_internal.tri[i * 6 + j * 2 + 0] =
262 verts[indices[idx_base + j]].x * scale + x;
263 img->_internal.tri[i * 6 + j * 2 + 1] =
264 verts[indices[idx_base + j]].y * scale + y;
265 }
266 }
268 img->_internal.cols);
269 return 1;
270}
271#endif
void gm3_image_free(gm3Image *i)
Definition image.h:86
int gm3_draw_image(gm3Image *img, double x, double y, double scale)
Draws the projected 3D scene contained within a gm3Image onto the screen.
Definition image.h:206
int _gm3_depth_compare(const void *a, const void *b)
Definition image.h:181
uint32_t gmColor
Type definition for color values, stored as a 32-bit unsigned integer. The color components are packe...
Definition color.h:13
Graphics API (GAPI) abstraction layer for Gama.
int32_t gapi_draw_triangles(uint32_t n_triangles, double *points, gmColor *colors)
Draws a batch of triangles on the screen.
void * malloc(size_t size)
Custom implementation of malloc using a static memory pool.
Definition malloc.h:144
void * realloc(void *ptr, size_t size)
Custom implementation of realloc for memory allocated by malloc (this custom version).
Definition malloc.h:236
void free(void *ptr)
Custom implementation of free for memory allocated by malloc (this custom version).
Definition malloc.h:189
Definition image.h:166
size_t tri_idx
Definition image.h:167
double z
Definition image.h:168
Structure representing the 2D projected output of a 3D scene.
Definition image.h:22
size_t cap_depths
Definition image.h:38
size_t cap_sort
Definition image.h:48
size_t cap_colors
Definition image.h:36
void * sort_buf
Definition image.h:47
gmColor * cols
Definition image.h:51
size_t n_colors
Definition image.h:31
double * depths
Definition image.h:27
gmColor * colors
Definition image.h:25
double * tri
Definition image.h:50
size_t cap_triangles
Definition image.h:37
gmPos * vertices
Definition image.h:24
size_t * triangles
Definition image.h:26
size_t n_vertices
Definition image.h:30
size_t cap_vertices
Definition image.h:35
size_t cap_world
Definition image.h:45
gm3Pos * world_verts
Definition image.h:44
size_t n_triangles
Definition image.h:32
struct gm3Image::@171174116104107177311324262265324115365007060225 _internal
size_t cap_tri
Definition image.h:52
Represents a 3D position or vector.
Definition position.h:11
Represents a 2D position or vector.
Definition position.h:8
double x
Definition position.h:9
double y
Definition position.h:9