Line data Source code
1 : #include "blaze.h"
2 : #include "./deps/SOIL/SOIL.h"
3 : #include "./glad/include/glad/glad.h"
4 :
5 : #include <math.h>
6 : #include <stdio.h>
7 : #include <stdlib.h>
8 : #include <string.h>
9 :
10 : #define calloc_one(s) calloc(1, s)
11 : #define BUFFER_COUNT 2
12 : #define HAS_FLAG(batch, flag) ((batch->flags & flag) == flag)
13 :
14 : #define return_success(result) \
15 : do \
16 : { \
17 : __lastError = NULL; \
18 : return result; \
19 : } while (0);
20 : #define success() return_success(BLZ_TRUE)
21 : #define fail(msg) \
22 : do \
23 : { \
24 : __lastError = msg; \
25 : return BLZ_FALSE; \
26 : } while (0);
27 : #define fail_cmp(val, cmp, msg) \
28 : do \
29 : { \
30 : if (val == cmp) \
31 : { \
32 : fail(msg); \
33 : } \
34 : } while (0);
35 : #define fail_if_null(val, msg) fail_cmp(val, NULL, msg)
36 : #define fail_if_false(val, msg) fail_cmp(val, BLZ_FALSE, msg)
37 : #define null_if_false(val, msg) \
38 : do \
39 : { \
40 : if (val == BLZ_FALSE) \
41 : { \
42 : __lastError = msg; \
43 : return NULL; \
44 : } \
45 : } while (0);
46 : #define check_alloc(p) fail_if_null(p, "Could not allocate memory")
47 : #define validate(expr) \
48 : do \
49 : { \
50 : if (!(expr)) \
51 : { \
52 : fail("Invalid parameter value, should be " #expr); \
53 : } \
54 : } while (0);
55 : #define null_if_invalid(expr) \
56 : do \
57 : { \
58 : if (!(expr)) \
59 : { \
60 : __lastError = "Invalid parameter value, should be " #expr; \
61 : return NULL; \
62 : } \
63 : } while (0);
64 :
65 : /* Public constants */
66 : const struct BLZ_BlendFunc BLEND_NORMAL = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA};
67 : const struct BLZ_BlendFunc BLEND_ADDITIVE = {GL_ONE, GL_ONE};
68 : const struct BLZ_BlendFunc BLEND_MULTIPLY = {GL_DST_COLOR, GL_ZERO};
69 :
70 : /* Internal values */
71 : struct Buffer
72 : {
73 : GLuint vao, vbo, ebo;
74 : };
75 :
76 : struct BLZ_StaticBatch
77 : {
78 : int sprite_count;
79 : int max_sprite_count;
80 : unsigned char is_uploaded;
81 : struct BLZ_Vertex *vertices;
82 : struct Buffer buffer;
83 : const struct BLZ_Texture *texture;
84 : };
85 :
86 : struct BLZ_SpriteBatch
87 : {
88 : int max_buckets;
89 : int max_sprites_per_bucket;
90 : unsigned char buffer_index;
91 : unsigned char frameskip;
92 : enum BLZ_InitFlags flags;
93 : struct SpriteBucket *sprite_buckets;
94 : };
95 :
96 : struct BLZ_Shader
97 : {
98 : GLuint program;
99 : GLint mvp_param;
100 : };
101 :
102 : struct SpriteBucket
103 : {
104 : GLuint texture;
105 : int sprite_count;
106 : struct BLZ_Vertex *vertices;
107 : struct Buffer buffer[BUFFER_COUNT];
108 : };
109 :
110 : static char *__lastError = NULL;
111 :
112 : #define Z_NEAR 0.9f
113 : #define Z_FAR 2.1f
114 : #define LAYER_DEPTH(depth) 1.0f + depth
115 :
116 : static GLfloat orthoMatrix[16] =
117 : {0, 0, 0, 0,
118 : 0, 0, 0, 0,
119 : 0, 0, 1, 0,
120 : -1, 1, 0, 1};
121 :
122 : static GLchar vertexSource[] =
123 : "#version 130\n"
124 : "uniform mat4 u_mvpMatrix;"
125 : "in vec2 in_Position;"
126 : "in vec2 in_Texcoord;"
127 : "in vec4 in_Color;"
128 : "out vec4 ex_Color;"
129 : "out vec2 ex_Texcoord;"
130 : "void main() {"
131 : " ex_Color = in_Color;"
132 : " ex_Texcoord = in_Texcoord;"
133 : " gl_Position = u_mvpMatrix * vec4(in_Position, 1, 1);"
134 : "}";
135 :
136 : static GLchar fragmentSource[] =
137 : "#version 130\n"
138 : "in vec4 ex_Color;"
139 : "in vec2 ex_Texcoord;"
140 : "out vec4 outColor;"
141 : "uniform sampler2D tex;"
142 : "void main() {"
143 : " outColor = texture(tex, ex_Texcoord) * ex_Color;"
144 : "}";
145 :
146 : static BLZ_Shader *SHADER_DEFAULT;
147 : static BLZ_Shader *SHADER_CURRENT;
148 : static struct Buffer immediateBuf;
149 : static GLuint tex0_override = 0;
150 :
151 : static const int VERT_SIZE = sizeof(struct BLZ_Vertex);
152 :
153 : /* TODO: Optimization: Reuse same VAO for all batches to minimize state changes */
154 56 : static struct Buffer create_buffer(int max_sprites, GLenum usage)
155 : {
156 56 : int INDICES_SIZE = max_sprites * 6 * sizeof(GLushort);
157 : int i;
158 : struct Buffer result;
159 56 : GLushort *indices = malloc(INDICES_SIZE);
160 : GLuint vao, vbo, ebo;
161 56 : glGenVertexArrays(1, &vao);
162 56 : glBindVertexArray(vao);
163 56 : glGenBuffers(1, &vbo);
164 56 : glBindBuffer(GL_ARRAY_BUFFER, vbo);
165 56 : glBufferData(GL_ARRAY_BUFFER, VERT_SIZE * 4 * max_sprites,
166 : NULL, usage);
167 : /* x|y */
168 56 : glEnableVertexAttribArray(0);
169 56 : glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, VERT_SIZE, (void *)0);
170 : /* u|v */
171 56 : glEnableVertexAttribArray(1);
172 56 : glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, VERT_SIZE, (void *)8);
173 : /* r|g|b|a */
174 56 : glEnableVertexAttribArray(2);
175 56 : glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, VERT_SIZE, (void *)16);
176 : /* indices */
177 56 : glGenBuffers(1, &ebo);
178 56 : glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
179 3768 : for (i = 0; i < max_sprites; i++)
180 : {
181 3712 : *(indices + (i * 6)) = (GLushort)(i * 4);
182 3712 : *(indices + (i * 6) + 1) = (GLushort)(i * 4 + 1);
183 3712 : *(indices + (i * 6) + 2) = (GLushort)(i * 4 + 2);
184 3712 : *(indices + (i * 6) + 3) = (GLushort)(i * 4 + 2);
185 3712 : *(indices + (i * 6) + 4) = (GLushort)(i * 4 + 1);
186 3712 : *(indices + (i * 6) + 5) = (GLushort)(i * 4 + 3);
187 : }
188 56 : glBufferData(GL_ELEMENT_ARRAY_BUFFER, INDICES_SIZE, indices, GL_STATIC_DRAW);
189 56 : free(indices);
190 56 : glBindVertexArray(0);
191 56 : result.vao = vao;
192 56 : result.vbo = vbo;
193 56 : return result;
194 : }
195 :
196 51 : static void free_buffer(struct Buffer buffer)
197 : {
198 51 : glDeleteVertexArrays(1, &buffer.vao);
199 51 : glDeleteBuffers(1, &buffer.vbo);
200 51 : }
201 :
202 : /* Public API */
203 0 : char* BLZ_GetLastError()
204 : {
205 0 : return __lastError;
206 : }
207 :
208 8 : int BLZ_Load(glGetProcAddress loader)
209 : {
210 8 : int result = gladLoadGLLoader((GLADloadproc)loader);
211 8 : fail_if_false(result, "Could not load the OpenGL library");
212 8 : SHADER_DEFAULT = BLZ_CompileShader(vertexSource, fragmentSource);
213 8 : fail_if_false(SHADER_DEFAULT, "Could not compile default shader");
214 8 : fail_if_false(BLZ_UseShader(SHADER_DEFAULT), "Could not use default shader");
215 8 : immediateBuf = create_buffer(1, GL_STREAM_DRAW);
216 8 : glDisable(GL_DEPTH_TEST);
217 8 : glDepthMask(GL_FALSE);
218 8 : glEnable(GL_BLEND);
219 8 : success();
220 : }
221 :
222 1 : int BLZ_GetMaxTextureSlots()
223 : {
224 : GLint result;
225 1 : glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &result);
226 1 : return result;
227 : }
228 :
229 4 : int BLZ_BindTexture(struct BLZ_Texture *texture, int slot)
230 : {
231 4 : GLuint id = texture == NULL ? 0 : texture->id;
232 4 : glActiveTexture(GL_TEXTURE0 + slot);
233 4 : glBindTexture(GL_TEXTURE_2D, id);
234 4 : if (slot == 0)
235 : {
236 2 : tex0_override = id;
237 : }
238 4 : success();
239 : }
240 :
241 2 : int BLZ_SetTextureFiltering(
242 : struct BLZ_Texture *texture,
243 : enum BLZ_TextureFilter minification,
244 : enum BLZ_TextureFilter magnification)
245 : {
246 2 : glBindTexture(GL_TEXTURE_2D, texture->id);
247 2 : glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minification);
248 2 : glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magnification);
249 2 : glBindTexture(GL_TEXTURE_2D, 0);
250 2 : success();
251 : }
252 :
253 1 : int BLZ_SetTextureWrap(
254 : struct BLZ_Texture *texture,
255 : enum BLZ_TextureWrap x,
256 : enum BLZ_TextureWrap y)
257 : {
258 1 : glBindTexture(GL_TEXTURE_2D, texture->id);
259 1 : glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, x);
260 1 : glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, y);
261 1 : glBindTexture(GL_TEXTURE_2D, 0);
262 1 : success();
263 : }
264 :
265 51 : static void bind_tex0(GLuint tex)
266 : {
267 51 : if (tex0_override == 0)
268 : {
269 46 : glActiveTexture(GL_TEXTURE0);
270 46 : glBindTexture(GL_TEXTURE_2D, tex);
271 : }
272 51 : }
273 :
274 3 : int BLZ_GetOptions(const struct BLZ_SpriteBatch *batch,
275 : int *max_buckets, int *max_sprites_per_bucket,
276 : enum BLZ_InitFlags *flags)
277 : {
278 3 : validate(batch != NULL);
279 3 : if (batch->max_buckets <= 0 || batch->max_sprites_per_bucket <= 0)
280 : {
281 1 : fail("Not initialized");
282 : }
283 2 : *max_buckets = batch->max_buckets;
284 2 : *max_sprites_per_bucket = batch->max_sprites_per_bucket;
285 2 : *flags = batch->flags;
286 2 : success();
287 : }
288 :
289 6 : int BLZ_SetViewport(int w, int h)
290 : {
291 6 : validate(w > 0);
292 6 : validate(h > 0);
293 6 : orthoMatrix[0] = 2.0f / (GLfloat)w;
294 6 : orthoMatrix[5] = -2.0f / (GLfloat)h;
295 6 : success();
296 : }
297 :
298 6 : void BLZ_SetClearColor(struct BLZ_Vector4 color)
299 : {
300 6 : glClearColor(color.x, color.y, color.z, color.w);
301 6 : }
302 :
303 20 : void BLZ_SetBlendMode(const struct BLZ_BlendFunc func)
304 : {
305 20 : glBlendFunc(func.source, func.destination);
306 20 : }
307 :
308 31 : void BLZ_Clear()
309 : {
310 31 : glClear(GL_COLOR_BUFFER_BIT);
311 31 : }
312 :
313 21 : static GLuint compile_shader(GLenum type, const char *src)
314 : {
315 : int compiled;
316 : int log_length;
317 : char *log_string;
318 21 : GLuint shader = glCreateShader(type);
319 21 : glShaderSource(shader, 1, (const GLchar **)&src, 0);
320 21 : glCompileShader(shader);
321 21 : glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
322 21 : if (!compiled)
323 : {
324 1 : glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
325 1 : log_string = malloc(log_length);
326 1 : glGetShaderInfoLog(shader, log_length, &log_length, log_string);
327 1 : printf("Error compiling shader: %s\n", log_string);
328 1 : free(log_string);
329 1 : return 0;
330 : }
331 20 : return shader;
332 : }
333 :
334 12 : GLint BLZ_GetUniformLocation(const struct BLZ_Shader *shader, const char *name)
335 : {
336 12 : if (shader == NULL || name == NULL)
337 : {
338 0 : return -1;
339 : }
340 12 : return glGetUniformLocation(shader->program, (const GLchar *)name);
341 : }
342 :
343 11 : BLZ_Shader *BLZ_CompileShader(const char *vert, const char *frag)
344 : {
345 : struct BLZ_Shader *shader;
346 : GLuint program, vertex_shader, fragment_shader;
347 : int is_linked, log_length;
348 : char *log_string;
349 11 : validate(vert != NULL);
350 11 : validate(frag != NULL);
351 11 : shader = malloc(sizeof(struct BLZ_Shader));
352 11 : vertex_shader = compile_shader(GL_VERTEX_SHADER, vert);
353 11 : if (!vertex_shader)
354 : {
355 1 : return NULL;
356 : }
357 10 : fragment_shader = compile_shader(GL_FRAGMENT_SHADER, frag);
358 10 : if (!fragment_shader)
359 : {
360 0 : return NULL;
361 : }
362 10 : program = glCreateProgram();
363 10 : glAttachShader(program, vertex_shader);
364 10 : glAttachShader(program, fragment_shader);
365 10 : glBindAttribLocation(program, 0, "in_Position");
366 10 : glBindAttribLocation(program, 1, "in_Texcoord");
367 10 : glBindAttribLocation(program, 2, "in_Color");
368 10 : glLinkProgram(program);
369 10 : glGetProgramiv(program, GL_LINK_STATUS, &is_linked);
370 10 : if (!is_linked)
371 : {
372 0 : glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
373 0 : log_string = malloc(log_length);
374 0 : glGetProgramInfoLog(program, log_length, &log_length, log_string);
375 0 : printf("Error linking shader: %s\n", log_string);
376 0 : free(log_string);
377 0 : return NULL;
378 : }
379 10 : shader->program = program;
380 10 : shader->mvp_param = BLZ_GetUniformLocation(shader, "u_mvpMatrix");
381 10 : return shader;
382 : }
383 :
384 10 : int BLZ_UseShader(struct BLZ_Shader *program)
385 : {
386 : GLenum result;
387 10 : validate(program != NULL);
388 : /* clear previous errors to make sure we're reading the actual one */
389 10 : while (glGetError() != GL_NO_ERROR)
390 : {
391 : };
392 10 : glUseProgram(program->program);
393 10 : result = glGetError();
394 10 : if (result == GL_NO_ERROR)
395 : {
396 10 : SHADER_CURRENT = program;
397 10 : success();
398 : }
399 0 : printf("glUseProgram: error %d\n", result);
400 0 : fail("Could not use shader program");
401 : }
402 :
403 2 : int BLZ_FreeShader(BLZ_Shader *program)
404 : {
405 2 : validate(program != NULL);
406 2 : glDeleteShader(program->program);
407 2 : free(program);
408 2 : success();
409 : }
410 :
411 1 : BLZ_Shader *BLZ_GetDefaultShader()
412 : {
413 1 : return SHADER_DEFAULT;
414 : }
415 :
416 6 : int BLZ_FreeBatch(struct BLZ_SpriteBatch *batch)
417 : {
418 : int i;
419 : struct SpriteBucket cur;
420 6 : if (batch->sprite_buckets != NULL)
421 : {
422 29 : for (i = 0; i < batch->max_buckets; i++)
423 : {
424 23 : cur = *(batch->sprite_buckets + i);
425 23 : free_buffer(cur.buffer[0]);
426 23 : if (!HAS_FLAG(batch, NO_BUFFERING))
427 : {
428 13 : free_buffer(cur.buffer[1]);
429 13 : free_buffer(cur.buffer[2]);
430 : }
431 : }
432 6 : free(batch->sprite_buckets);
433 : }
434 6 : free(batch);
435 6 : success();
436 : }
437 :
438 7 : struct BLZ_SpriteBatch *BLZ_CreateBatch(
439 : int max_buckets, int max_sprites_per_bucket, enum BLZ_InitFlags flags)
440 : {
441 : int i;
442 : struct BLZ_Vertex *vertices;
443 : struct SpriteBucket *cur;
444 7 : struct BLZ_SpriteBatch *batch = malloc(sizeof(BLZ_SpriteBatch));
445 7 : null_if_invalid(max_buckets > 0);
446 6 : null_if_invalid(max_sprites_per_bucket > 0);
447 6 : batch->max_sprites_per_bucket = max_sprites_per_bucket;
448 6 : batch->max_buckets = max_buckets;
449 6 : batch->flags = flags;
450 6 : batch->buffer_index = 0;
451 6 : if (!HAS_FLAG(batch, NO_BUFFERING))
452 : {
453 5 : batch->frameskip = 1;
454 : }
455 6 : batch->sprite_buckets = calloc(batch->max_buckets, sizeof(struct SpriteBucket));
456 6 : check_alloc(batch->sprite_buckets);
457 29 : for (i = 0; i < batch->max_buckets; i++)
458 : {
459 23 : cur = (batch->sprite_buckets + i);
460 23 : vertices = malloc(batch->max_sprites_per_bucket * 4 * sizeof(struct BLZ_Vertex));
461 23 : check_alloc(vertices);
462 23 : cur->vertices = vertices;
463 23 : cur->buffer[0] = create_buffer(max_sprites_per_bucket, GL_STREAM_DRAW);
464 23 : cur->buffer[1] = create_buffer(max_sprites_per_bucket, GL_STREAM_DRAW);
465 : }
466 6 : return batch;
467 : }
468 :
469 46 : static inline void set_mvp_matrix(const GLfloat *matrix)
470 : {
471 46 : if (SHADER_CURRENT->mvp_param > -1)
472 : {
473 46 : BLZ_UniformMatrix4fv(SHADER_CURRENT->mvp_param, 1, GL_FALSE, matrix);
474 : }
475 46 : }
476 :
477 : static struct BLZ_SpriteBatch *__lastBatch;
478 : static struct SpriteBucket *__lastBucket;
479 : static GLuint __lastTexture;
480 20 : static int flush(struct BLZ_SpriteBatch *batch)
481 : {
482 : unsigned char to_draw, to_fill;
483 : struct SpriteBucket bucket;
484 : struct SpriteBucket *bucket_ptr;
485 : int i, buf_size;
486 20 : set_mvp_matrix((const GLfloat *)&orthoMatrix);
487 20 : if (HAS_FLAG(batch, NO_BUFFERING) || batch->frameskip)
488 : {
489 4 : to_draw = to_fill = 0;
490 : }
491 : else
492 : {
493 16 : to_draw = batch->buffer_index,
494 16 : to_fill = batch->buffer_index + 1;
495 16 : if (to_fill >= BUFFER_COUNT)
496 : {
497 8 : to_fill -= BUFFER_COUNT;
498 : }
499 : }
500 45 : for (i = 0; i < batch->max_buckets; i++)
501 : {
502 40 : bucket_ptr = (batch->sprite_buckets + i);
503 40 : bucket = *bucket_ptr;
504 40 : buf_size = bucket.sprite_count * 4 * sizeof(struct BLZ_Vertex);
505 40 : if (buf_size == 0 || bucket.texture == 0)
506 : {
507 : /* we've reached the end of the batch */
508 : break;
509 : }
510 : /* fill the buffer */
511 25 : glBindBuffer(GL_ARRAY_BUFFER, bucket.buffer[to_fill].vbo);
512 25 : glBufferData(GL_ARRAY_BUFFER, buf_size, bucket.vertices, GL_STREAM_DRAW);
513 25 : glBindBuffer(GL_ARRAY_BUFFER, 0);
514 : /* bind our texture and the VAO and draw it */
515 25 : bind_tex0(bucket.texture);
516 25 : glBindVertexArray(bucket.buffer[to_draw].vao);
517 25 : glDrawElements(GL_TRIANGLES, bucket.sprite_count * 6, GL_UNSIGNED_SHORT, (void *)0);
518 25 : bucket_ptr->sprite_count = 0;
519 25 : bucket_ptr->texture = 0;
520 : }
521 20 : __lastBatch = NULL;
522 20 : __lastBucket = NULL;
523 20 : __lastTexture = 0;
524 20 : success();
525 : }
526 :
527 20 : int BLZ_Present(struct BLZ_SpriteBatch *batch)
528 : {
529 20 : fail_if_false(flush(batch), "Could not flush the sprite batch");
530 20 : if (!HAS_FLAG(batch, NO_BUFFERING) && batch->frameskip == 0)
531 : {
532 16 : batch->buffer_index++;
533 16 : if (batch->buffer_index >= BUFFER_COUNT)
534 : {
535 8 : batch->buffer_index -= BUFFER_COUNT;
536 : }
537 : }
538 20 : if (batch->frameskip > 0)
539 : {
540 4 : batch->frameskip--;
541 : }
542 20 : success();
543 : }
544 :
545 : #define set_vertex(index, field, val) \
546 : do \
547 : { \
548 : quad.vertices[index].field = val; \
549 : } while (0);
550 :
551 : #define set_all_vertices(field, val) \
552 : do \
553 : { \
554 : set_vertex(0, field, val); \
555 : set_vertex(1, field, val); \
556 : set_vertex(2, field, val); \
557 : set_vertex(3, field, val); \
558 : } while (0);
559 :
560 : #define swap(tmp, one, two) \
561 : do \
562 : { \
563 : tmp = one; \
564 : one = two; \
565 : two = tmp; \
566 : } while (0);
567 :
568 224 : static struct BLZ_SpriteQuad transform_position_fastpath(
569 : const struct BLZ_Texture *texture,
570 : const struct BLZ_Vector2 position,
571 : const struct BLZ_Vector4 color)
572 : {
573 224 : GLfloat x = position.x;
574 224 : GLfloat y = position.y;
575 224 : GLfloat w = (GLfloat)texture->width;
576 224 : GLfloat h = (GLfloat)texture->height;
577 : struct BLZ_SpriteQuad quad;
578 :
579 : /* set the vertex values */
580 224 : set_vertex(0, x, x);
581 224 : set_vertex(0, y, y);
582 224 : set_vertex(0, u, 0);
583 224 : set_vertex(0, v, 0);
584 224 : set_vertex(2, x, x + w);
585 224 : set_vertex(2, y, y);
586 224 : set_vertex(2, u, 1);
587 224 : set_vertex(2, v, 0);
588 224 : set_vertex(3, x, x + w);
589 224 : set_vertex(3, y, y + h);
590 224 : set_vertex(3, u, 1);
591 224 : set_vertex(3, v, 1);
592 224 : set_vertex(1, x, x);
593 224 : set_vertex(1, y, y + h);
594 224 : set_vertex(1, u, 0);
595 224 : set_vertex(1, v, 1);
596 :
597 224 : set_all_vertices(r, color.x);
598 224 : set_all_vertices(g, color.y);
599 224 : set_all_vertices(b, color.z);
600 224 : set_all_vertices(a, color.w);
601 224 : return quad;
602 : }
603 :
604 456 : static struct BLZ_SpriteQuad transform_full(
605 : const struct BLZ_Texture *texture,
606 : const struct BLZ_Vector2 position,
607 : const struct BLZ_Rectangle *srcRectangle,
608 : float rotation,
609 : const struct BLZ_Vector2 *origin,
610 : const struct BLZ_Vector2 *scale,
611 : const struct BLZ_Vector4 color,
612 : enum BLZ_SpriteFlip effects)
613 : {
614 : /* position: top-left, top-right, bottom-left, bottom-right */
615 : struct BLZ_Vector2 p_tl, p_tr, p_bl, p_br;
616 : /* same for texture coordinates */
617 : struct BLZ_Vector2 t_tl, t_tr, t_bl, t_br;
618 : struct BLZ_SpriteQuad quad;
619 : GLfloat dx, dy;
620 456 : GLfloat x = position.x;
621 456 : GLfloat y = position.y;
622 456 : GLfloat tw = (GLfloat)texture->width;
623 456 : GLfloat th = (GLfloat)texture->height;
624 456 : int w = srcRectangle == NULL ? tw : srcRectangle->w;
625 456 : int h = srcRectangle == NULL ? th : srcRectangle->h;
626 456 : GLfloat _sin = rotation == 0.0f ? 0.0f : sin(rotation);
627 456 : GLfloat _cos = rotation == 0.0f ? 1.0f : cos(rotation);
628 456 : GLfloat u1 = srcRectangle == NULL ? 0 : srcRectangle->x / tw;
629 456 : GLfloat v1 = srcRectangle == NULL ? 0 : srcRectangle->y / th;
630 456 : GLfloat u2 = srcRectangle == NULL ? 1 : u1 + (srcRectangle->w / tw);
631 456 : GLfloat v2 = srcRectangle == NULL ? 1 : v1 + (srcRectangle->h / th);
632 : GLfloat tmp;
633 456 : if (scale != NULL)
634 : {
635 144 : w *= scale->x;
636 144 : h *= scale->y;
637 : }
638 456 : if (origin == NULL)
639 : {
640 312 : dx = 0;
641 312 : dy = 0;
642 : }
643 : else
644 : {
645 144 : dx = -origin->x;
646 144 : dy = -origin->y;
647 : }
648 456 : p_tl.x = x + dx * _cos - dy * _sin;
649 456 : p_tl.y = y + dx * _sin + dy * _cos;
650 456 : p_tr.x = x + (dx + w) * _cos - dy * _sin;
651 456 : p_tr.y = y + (dx + w) * _sin + dy * _cos;
652 456 : p_bl.x = x + dx * _cos - (dy + h) * _sin;
653 456 : p_bl.y = y + dx * _sin + (dy + h) * _cos;
654 456 : p_br.x = x + (dx + w) * _cos - (dy + h) * _sin;
655 456 : p_br.y = y + (dx + w) * _sin + (dy + h) * _cos;
656 :
657 : /* calculate texture coordinates */
658 456 : switch (effects)
659 : {
660 : case FLIP_H:
661 12 : swap(tmp, u1, u2);
662 12 : break;
663 : case FLIP_V:
664 12 : swap(tmp, v1, v2);
665 12 : break;
666 : case BOTH:
667 12 : swap(tmp, u1, u2);
668 12 : swap(tmp, v1, v2);
669 12 : break;
670 : default:
671 420 : break;
672 : }
673 456 : t_tl.x = u1;
674 456 : t_tl.y = v1;
675 456 : t_tr.x = u2;
676 456 : t_tr.y = v1;
677 456 : t_bl.x = u1;
678 456 : t_bl.y = v2;
679 456 : t_br.x = u2;
680 456 : t_br.y = v2;
681 : /* set the vertex values */
682 456 : set_vertex(0, x, p_tl.x);
683 456 : set_vertex(0, y, p_tl.y);
684 456 : set_vertex(0, u, t_tl.x);
685 456 : set_vertex(0, v, t_tl.y);
686 456 : set_vertex(2, x, p_tr.x);
687 456 : set_vertex(2, y, p_tr.y);
688 456 : set_vertex(2, u, t_tr.x);
689 456 : set_vertex(2, v, t_tr.y);
690 456 : set_vertex(3, x, p_br.x);
691 456 : set_vertex(3, y, p_br.y);
692 456 : set_vertex(3, u, t_br.x);
693 456 : set_vertex(3, v, t_br.y);
694 456 : set_vertex(1, x, p_bl.x);
695 456 : set_vertex(1, y, p_bl.y);
696 456 : set_vertex(1, u, t_bl.x);
697 456 : set_vertex(1, v, t_bl.y);
698 :
699 456 : set_all_vertices(r, color.x);
700 456 : set_all_vertices(g, color.y);
701 456 : set_all_vertices(b, color.z);
702 456 : set_all_vertices(a, color.w);
703 456 : return quad;
704 : }
705 :
706 680 : inline static struct BLZ_SpriteQuad transform(
707 : const struct BLZ_Texture *texture,
708 : const struct BLZ_Vector2 position,
709 : const struct BLZ_Rectangle *srcRectangle,
710 : float rotation,
711 : const struct BLZ_Vector2 *origin,
712 : const struct BLZ_Vector2 *scale,
713 : const struct BLZ_Vector4 color,
714 : enum BLZ_SpriteFlip effects)
715 : {
716 680 : if (srcRectangle == NULL && rotation == 0.0f && origin == NULL &&
717 260 : scale == NULL && effects == NONE)
718 : {
719 224 : return transform_position_fastpath(texture, position, color);
720 : }
721 : else
722 : {
723 456 : return transform_full(texture, position, srcRectangle, rotation,
724 : origin, scale, color, effects);
725 : }
726 : }
727 :
728 565 : int BLZ_Draw(
729 : struct BLZ_SpriteBatch *batch,
730 : const struct BLZ_Texture *texture,
731 : const struct BLZ_Vector2 position,
732 : const struct BLZ_Rectangle *srcRectangle,
733 : float rotation,
734 : const struct BLZ_Vector2 *origin,
735 : const struct BLZ_Vector2 *scale,
736 : const struct BLZ_Vector4 color,
737 : enum BLZ_SpriteFlip effects)
738 : {
739 565 : struct BLZ_SpriteQuad quad = transform(
740 : texture,
741 : position,
742 : srcRectangle,
743 : rotation,
744 : origin,
745 : scale,
746 : color,
747 : effects);
748 565 : return BLZ_LowerDraw(batch, texture->id, &quad);
749 : }
750 :
751 565 : int BLZ_LowerDraw(
752 : struct BLZ_SpriteBatch *batch,
753 : GLuint texture, const struct BLZ_SpriteQuad *quad)
754 : {
755 565 : struct SpriteBucket *bucket = NULL;
756 565 : int i = 0;
757 : size_t offset;
758 565 : if (__lastBatch != batch)
759 : {
760 20 : __lastBatch = NULL;
761 20 : __lastBucket = NULL;
762 20 : __lastTexture = 0;
763 : }
764 565 : if (__lastTexture > 0 && texture == __lastTexture)
765 : {
766 540 : if (__lastBucket != NULL && __lastBucket->sprite_count < batch->max_sprites_per_bucket)
767 : {
768 540 : bucket = __lastBucket;
769 : }
770 : }
771 565 : if (bucket == NULL)
772 : {
773 30 : for (i = 0; i < batch->max_buckets; i++)
774 : {
775 30 : bucket = (batch->sprite_buckets + i);
776 30 : if (bucket->texture == texture &&
777 0 : bucket->sprite_count >= batch->max_sprites_per_bucket)
778 : {
779 : /* this bucket is already filled, skip it */
780 0 : continue;
781 : }
782 30 : if (bucket->texture == texture || bucket->texture == 0)
783 : {
784 : /* we found existing not-full bucket or an empty one */
785 : break;
786 : }
787 : }
788 : }
789 1130 : if (bucket->sprite_count >= batch->max_sprites_per_bucket ||
790 1105 : (bucket->texture != 0 && bucket->texture != texture))
791 : {
792 : /* we ran out of limits */
793 0 : fail("Sprite limit reached - increase limits in BLZ_CreateBatch(...)");
794 : }
795 565 : offset = bucket->sprite_count * 4;
796 : /* set the vertex data */
797 565 : memcpy((bucket->vertices + offset), quad, sizeof(struct BLZ_SpriteQuad));
798 565 : bucket->sprite_count++;
799 565 : bucket->texture = texture;
800 565 : __lastBatch = batch;
801 565 : __lastBucket = bucket;
802 565 : __lastTexture = texture;
803 565 : success();
804 : }
805 :
806 : /* Static drawing */
807 2 : static void upload_static_vertices(struct BLZ_StaticBatch *batch)
808 : {
809 2 : glBindBuffer(GL_ARRAY_BUFFER, batch->buffer.vbo);
810 4 : glBufferData(GL_ARRAY_BUFFER,
811 2 : batch->sprite_count * 4 * sizeof(struct BLZ_Vertex),
812 2 : batch->vertices, GL_STATIC_DRAW);
813 2 : glBindBuffer(GL_ARRAY_BUFFER, 0);
814 2 : batch->is_uploaded = BLZ_TRUE;
815 2 : }
816 :
817 2 : struct BLZ_StaticBatch *BLZ_CreateStatic(
818 : const struct BLZ_Texture *texture, int max_sprite_count)
819 : {
820 2 : struct BLZ_StaticBatch *result = malloc(sizeof(struct BLZ_StaticBatch));
821 2 : result->texture = texture;
822 2 : result->buffer = create_buffer(max_sprite_count, GL_STATIC_DRAW);
823 2 : result->is_uploaded = BLZ_FALSE;
824 2 : result->sprite_count = 0;
825 2 : result->max_sprite_count = max_sprite_count;
826 2 : result->vertices = malloc(max_sprite_count * 4 * sizeof(struct BLZ_Vertex));
827 2 : return result;
828 : }
829 :
830 2 : int BLZ_GetOptionsStatic(
831 : const struct BLZ_StaticBatch *batch,
832 : int *max_sprite_count)
833 : {
834 2 : validate(batch != NULL);
835 2 : *max_sprite_count = batch->max_sprite_count;
836 2 : success();
837 : }
838 :
839 2 : int BLZ_FreeBatchStatic(
840 : struct BLZ_StaticBatch *batch)
841 : {
842 2 : if (batch == NULL)
843 : {
844 0 : success();
845 : }
846 2 : free(batch->vertices);
847 2 : free_buffer(batch->buffer);
848 2 : free(batch);
849 2 : success();
850 : }
851 :
852 104 : int BLZ_DrawStatic(
853 : struct BLZ_StaticBatch *batch,
854 : const struct BLZ_Vector2 position,
855 : const struct BLZ_Rectangle *srcRectangle,
856 : float rotation,
857 : const struct BLZ_Vector2 *origin,
858 : const struct BLZ_Vector2 *scale,
859 : const struct BLZ_Vector4 color,
860 : enum BLZ_SpriteFlip effects)
861 : {
862 104 : struct BLZ_SpriteQuad quad = transform(
863 : batch->texture,
864 : position,
865 : srcRectangle,
866 : rotation,
867 : origin,
868 : scale,
869 : color,
870 : effects);
871 104 : return BLZ_LowerDrawStatic(batch, &quad);
872 : }
873 :
874 104 : int BLZ_LowerDrawStatic(
875 : struct BLZ_StaticBatch *batch,
876 : const struct BLZ_SpriteQuad *quad)
877 : {
878 104 : if (batch->is_uploaded)
879 : {
880 0 : fail("Can't push more sprites to already uploaded static batch");
881 : }
882 104 : if (batch->sprite_count >= batch->max_sprite_count)
883 : {
884 0 : fail("Sprite limit reached - increase limits in BLZ_CreateStatic(...)");
885 : }
886 : /* set the vertex data */
887 104 : memcpy((batch->vertices + batch->sprite_count * 4), quad, sizeof(struct BLZ_SpriteQuad));
888 104 : batch->sprite_count++;
889 104 : success();
890 : }
891 :
892 : static GLfloat identityMatrix[16] = {
893 : 1, 0, 0, 0,
894 : 0, 1, 0, 0,
895 : 0, 0, 1, 0,
896 : 0, 0, 0, 1};
897 :
898 : #define O(y, x) (y + (x << 2))
899 10 : static void mult_4x4_matrix(const GLfloat *restrict src1, const GLfloat *restrict src2, GLfloat *restrict dest)
900 : {
901 10 : *(dest + O(0, 0)) = (*(src1 + O(0, 0)) * *(src2 + O(0, 0))) + (*(src1 + O(0, 1)) * *(src2 + O(1, 0))) + (*(src1 + O(0, 2)) * *(src2 + O(2, 0))) + (*(src1 + O(0, 3)) * *(src2 + O(3, 0)));
902 10 : *(dest + O(0, 1)) = (*(src1 + O(0, 0)) * *(src2 + O(0, 1))) + (*(src1 + O(0, 1)) * *(src2 + O(1, 1))) + (*(src1 + O(0, 2)) * *(src2 + O(2, 1))) + (*(src1 + O(0, 3)) * *(src2 + O(3, 1)));
903 10 : *(dest + O(0, 2)) = (*(src1 + O(0, 0)) * *(src2 + O(0, 2))) + (*(src1 + O(0, 1)) * *(src2 + O(1, 2))) + (*(src1 + O(0, 2)) * *(src2 + O(2, 2))) + (*(src1 + O(0, 3)) * *(src2 + O(3, 2)));
904 10 : *(dest + O(0, 3)) = (*(src1 + O(0, 0)) * *(src2 + O(0, 3))) + (*(src1 + O(0, 1)) * *(src2 + O(1, 3))) + (*(src1 + O(0, 2)) * *(src2 + O(2, 3))) + (*(src1 + O(0, 3)) * *(src2 + O(3, 3)));
905 10 : *(dest + O(1, 0)) = (*(src1 + O(1, 0)) * *(src2 + O(0, 0))) + (*(src1 + O(1, 1)) * *(src2 + O(1, 0))) + (*(src1 + O(1, 2)) * *(src2 + O(2, 0))) + (*(src1 + O(1, 3)) * *(src2 + O(3, 0)));
906 10 : *(dest + O(1, 1)) = (*(src1 + O(1, 0)) * *(src2 + O(0, 1))) + (*(src1 + O(1, 1)) * *(src2 + O(1, 1))) + (*(src1 + O(1, 2)) * *(src2 + O(2, 1))) + (*(src1 + O(1, 3)) * *(src2 + O(3, 1)));
907 10 : *(dest + O(1, 2)) = (*(src1 + O(1, 0)) * *(src2 + O(0, 2))) + (*(src1 + O(1, 1)) * *(src2 + O(1, 2))) + (*(src1 + O(1, 2)) * *(src2 + O(2, 2))) + (*(src1 + O(1, 3)) * *(src2 + O(3, 2)));
908 10 : *(dest + O(1, 3)) = (*(src1 + O(1, 0)) * *(src2 + O(0, 3))) + (*(src1 + O(1, 1)) * *(src2 + O(1, 3))) + (*(src1 + O(1, 2)) * *(src2 + O(2, 3))) + (*(src1 + O(1, 3)) * *(src2 + O(3, 3)));
909 10 : *(dest + O(2, 0)) = (*(src1 + O(2, 0)) * *(src2 + O(0, 0))) + (*(src1 + O(2, 1)) * *(src2 + O(1, 0))) + (*(src1 + O(2, 2)) * *(src2 + O(2, 0))) + (*(src1 + O(2, 3)) * *(src2 + O(3, 0)));
910 10 : *(dest + O(2, 1)) = (*(src1 + O(2, 0)) * *(src2 + O(0, 1))) + (*(src1 + O(2, 1)) * *(src2 + O(1, 1))) + (*(src1 + O(2, 2)) * *(src2 + O(2, 1))) + (*(src1 + O(2, 3)) * *(src2 + O(3, 1)));
911 10 : *(dest + O(2, 2)) = (*(src1 + O(2, 0)) * *(src2 + O(0, 2))) + (*(src1 + O(2, 1)) * *(src2 + O(1, 2))) + (*(src1 + O(2, 2)) * *(src2 + O(2, 2))) + (*(src1 + O(2, 3)) * *(src2 + O(3, 2)));
912 10 : *(dest + O(2, 3)) = (*(src1 + O(2, 0)) * *(src2 + O(0, 3))) + (*(src1 + O(2, 1)) * *(src2 + O(1, 3))) + (*(src1 + O(2, 2)) * *(src2 + O(2, 3))) + (*(src1 + O(2, 3)) * *(src2 + O(3, 3)));
913 10 : *(dest + O(3, 0)) = (*(src1 + O(3, 0)) * *(src2 + O(0, 0))) + (*(src1 + O(3, 1)) * *(src2 + O(1, 0))) + (*(src1 + O(3, 2)) * *(src2 + O(2, 0))) + (*(src1 + O(3, 3)) * *(src2 + O(3, 0)));
914 10 : *(dest + O(3, 1)) = (*(src1 + O(3, 0)) * *(src2 + O(0, 1))) + (*(src1 + O(3, 1)) * *(src2 + O(1, 1))) + (*(src1 + O(3, 2)) * *(src2 + O(2, 1))) + (*(src1 + O(3, 3)) * *(src2 + O(3, 1)));
915 10 : *(dest + O(3, 2)) = (*(src1 + O(3, 0)) * *(src2 + O(0, 2))) + (*(src1 + O(3, 1)) * *(src2 + O(1, 2))) + (*(src1 + O(3, 2)) * *(src2 + O(2, 2))) + (*(src1 + O(3, 3)) * *(src2 + O(3, 2)));
916 10 : *(dest + O(3, 3)) = (*(src1 + O(3, 0)) * *(src2 + O(0, 3))) + (*(src1 + O(3, 1)) * *(src2 + O(1, 3))) + (*(src1 + O(3, 2)) * *(src2 + O(2, 3))) + (*(src1 + O(3, 3)) * *(src2 + O(3, 3)));
917 10 : }
918 :
919 10 : int BLZ_PresentStatic(
920 : struct BLZ_StaticBatch *batch,
921 : const GLfloat *transformMatrix4x4)
922 : {
923 10 : const GLfloat *transform = transformMatrix4x4 != NULL ? transformMatrix4x4 : (GLfloat *)&identityMatrix;
924 :
925 : GLfloat mvpMatrix[16];
926 10 : if (!batch->is_uploaded)
927 : {
928 2 : upload_static_vertices(batch);
929 : }
930 10 : if (SHADER_CURRENT->mvp_param > -1)
931 : {
932 10 : mult_4x4_matrix(transform, (GLfloat *)&orthoMatrix, (GLfloat *)&mvpMatrix);
933 10 : set_mvp_matrix((const GLfloat *)&mvpMatrix);
934 : }
935 10 : bind_tex0(batch->texture->id);
936 10 : glBindVertexArray(batch->buffer.vao);
937 10 : glDrawElements(GL_TRIANGLES, batch->sprite_count * 6, GL_UNSIGNED_SHORT, (void *)0);
938 10 : success();
939 : }
940 :
941 : /* Immediate drawing */
942 11 : int BLZ_DrawImmediate(
943 : const struct BLZ_Texture *texture,
944 : const struct BLZ_Vector2 position,
945 : const struct BLZ_Rectangle *srcRectangle,
946 : float rotation,
947 : const struct BLZ_Vector2 *origin,
948 : const struct BLZ_Vector2 *scale,
949 : const struct BLZ_Vector4 color,
950 : enum BLZ_SpriteFlip effects)
951 : {
952 11 : struct BLZ_SpriteQuad quad = transform(
953 : texture,
954 : position,
955 : srcRectangle,
956 : rotation,
957 : origin,
958 : scale,
959 : color,
960 : effects);
961 11 : return BLZ_LowerDrawImmediate(texture->id, &quad);
962 : }
963 :
964 : const int SIZE_OF_ONE_QUAD = sizeof(struct BLZ_SpriteQuad);
965 16 : int BLZ_LowerDrawImmediate(
966 : GLuint texture,
967 : const struct BLZ_SpriteQuad *quad)
968 : {
969 16 : glBindBuffer(GL_ARRAY_BUFFER, immediateBuf.vbo);
970 16 : glBufferData(GL_ARRAY_BUFFER, SIZE_OF_ONE_QUAD, quad, GL_STREAM_DRAW);
971 16 : glBindBuffer(GL_ARRAY_BUFFER, 0);
972 16 : glBindVertexArray(immediateBuf.vao);
973 16 : set_mvp_matrix((const GLfloat *)&orthoMatrix);
974 16 : bind_tex0(texture);
975 16 : glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void *)0);
976 16 : success();
977 : }
978 :
979 : /* Textures */
980 12 : static void fill_texture_info(struct BLZ_Texture *texture)
981 : {
982 12 : glBindTexture(GL_TEXTURE_2D, texture->id);
983 12 : glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texture->width);
984 12 : glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texture->height);
985 12 : glBindTexture(GL_TEXTURE_2D, 0);
986 12 : }
987 :
988 12 : struct BLZ_Texture *BLZ_LoadTextureFromFile(
989 : const char *filename,
990 : enum BLZ_ImageChannels channels,
991 : unsigned int texture_id,
992 : enum BLZ_ImageFlags flags)
993 : {
994 : struct BLZ_Texture *texture;
995 12 : unsigned int id = SOIL_load_OGL_texture(
996 : filename,
997 : channels,
998 : texture_id,
999 : flags);
1000 12 : const char *last_result = SOIL_last_result();
1001 12 : if (!id)
1002 : {
1003 1 : printf("Error: %s\n", last_result);
1004 1 : return NULL;
1005 : }
1006 11 : texture = malloc(sizeof(struct BLZ_Texture));
1007 11 : texture->id = id;
1008 11 : fill_texture_info(texture);
1009 11 : return texture;
1010 : }
1011 :
1012 2 : struct BLZ_Texture *BLZ_LoadTextureFromMemory(
1013 : const unsigned char *const buffer,
1014 : int buffer_length,
1015 : enum BLZ_ImageChannels force_channels,
1016 : unsigned int texture_id,
1017 : enum BLZ_ImageFlags flags)
1018 : {
1019 : struct BLZ_Texture *texture;
1020 : int width, height, channels;
1021 2 : unsigned char *data = SOIL_load_image_from_memory(
1022 : buffer, buffer_length,
1023 : &width, &height, &channels,
1024 : force_channels);
1025 2 : const char *last_result = SOIL_last_result();
1026 2 : if (data == NULL)
1027 : {
1028 1 : printf("Error: %s\n", last_result);
1029 1 : return NULL;
1030 : }
1031 1 : texture = malloc(sizeof(struct BLZ_Texture));
1032 1 : texture->id = SOIL_create_OGL_texture(
1033 : data, width, height, channels, texture_id, flags);
1034 1 : fill_texture_info(texture);
1035 1 : return texture;
1036 : }
1037 :
1038 8 : int BLZ_FreeTexture(struct BLZ_Texture *texture)
1039 : {
1040 8 : if (texture == NULL)
1041 : {
1042 0 : success();
1043 : }
1044 8 : glDeleteTextures(1, &texture->id);
1045 8 : free(texture);
1046 8 : success();
1047 : }
1048 :
1049 6 : int BLZ_SaveScreenshot(
1050 : const char *filename,
1051 : enum BLZ_SaveImageFormat format,
1052 : int x, int y,
1053 : int width, int height)
1054 : {
1055 6 : return SOIL_save_screenshot(
1056 : filename,
1057 : format, x, y, width, height);
1058 : }
1059 :
1060 : /* Render targets */
1061 : static const GLenum DRAW_BUFFERS[1] = {GL_COLOR_ATTACHMENT0};
1062 1 : struct BLZ_RenderTarget *BLZ_CreateRenderTarget(int width, int height)
1063 : {
1064 : GLuint framebuffer, texture;
1065 : struct BLZ_RenderTarget *result;
1066 1 : glGenFramebuffers(1, &framebuffer);
1067 1 : glGenTextures(1, &texture);
1068 1 : null_if_false(framebuffer, "Could not create framebuffer");
1069 1 : null_if_false(texture, "Could not create texture for framebuffer");
1070 1 : result = malloc(sizeof(struct BLZ_RenderTarget));
1071 1 : result->id = framebuffer;
1072 1 : result->texture.id = texture;
1073 1 : result->texture.width = width;
1074 1 : result->texture.height = height;
1075 1 : glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
1076 1 : glBindTexture(GL_TEXTURE_2D, texture);
1077 1 : glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
1078 : GL_UNSIGNED_BYTE, NULL);
1079 1 : BLZ_SetTextureFiltering(&result->texture, NEAREST, NEAREST);
1080 1 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
1081 : texture, 0);
1082 1 : glDrawBuffers(1, DRAW_BUFFERS);
1083 1 : if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
1084 : {
1085 0 : free(result);
1086 0 : fail("The specified framebuffer is not complete");
1087 : }
1088 1 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
1089 1 : return result;
1090 : }
1091 :
1092 2 : int BLZ_BindRenderTarget(struct BLZ_RenderTarget *target)
1093 : {
1094 2 : glBindFramebuffer(GL_FRAMEBUFFER, target == NULL ? 0 : target->id);
1095 2 : success();
1096 : }
1097 :
1098 1 : int BLZ_FreeRenderTarget(struct BLZ_RenderTarget *target)
1099 : {
1100 1 : if (target == NULL) {
1101 0 : success();
1102 : }
1103 1 : glDeleteTextures(1, &target->texture.id);
1104 1 : glDeleteFramebuffers(1, &target->id);
1105 1 : free(target);
1106 1 : success();
1107 : }
1108 :
1109 : /* glUniform shims */
1110 : /* LCOV_EXCL_START */
1111 : #define PARAM1(type) type v0
1112 : #define PARAM2(type) PARAM1(type), type v1
1113 : #define PARAM3(type) PARAM2(type), type v2
1114 : #define PARAM4(type) PARAM3(type), type v3
1115 : #define PASS_PARAM1 v0
1116 : #define PASS_PARAM2 PASS_PARAM1, v1
1117 : #define PASS_PARAM3 PASS_PARAM2, v2
1118 : #define PASS_PARAM4 PASS_PARAM3, v3
1119 :
1120 : #define UNIFORM_VEC(postfix, type, n) \
1121 : void BLZ_Uniform##n##postfix(GLint location, PARAM##n(type)) \
1122 : { \
1123 : glUniform##n##postfix(location, PASS_PARAM##n); \
1124 : }
1125 :
1126 : #define UNIFORM_MAT(size) \
1127 : void BLZ_UniformMatrix##size##fv( \
1128 : GLint location, \
1129 : GLsizei count, \
1130 : GLboolean transpose, \
1131 : const GLfloat *value) \
1132 : { \
1133 : glUniformMatrix##size##fv(location, count, transpose, value); \
1134 : }
1135 :
1136 : UNIFORM_VEC(f, GLfloat, 1)
1137 : UNIFORM_VEC(f, GLfloat, 2)
1138 : UNIFORM_VEC(f, GLfloat, 3)
1139 : UNIFORM_VEC(f, GLfloat, 4)
1140 : UNIFORM_VEC(i, GLint, 1)
1141 : UNIFORM_VEC(i, GLint, 2)
1142 : UNIFORM_VEC(i, GLint, 3)
1143 : UNIFORM_VEC(i, GLint, 4)
1144 : UNIFORM_VEC(ui, GLuint, 1)
1145 : UNIFORM_VEC(ui, GLuint, 2)
1146 : UNIFORM_VEC(ui, GLuint, 3)
1147 : UNIFORM_VEC(ui, GLuint, 4)
1148 : UNIFORM_MAT(2)
1149 : UNIFORM_MAT(3)
1150 : UNIFORM_MAT(4)
1151 : UNIFORM_MAT(2x3)
1152 : UNIFORM_MAT(3x2)
1153 : UNIFORM_MAT(2x4)
1154 : UNIFORM_MAT(4x2)
1155 : UNIFORM_MAT(3x4)
1156 : UNIFORM_MAT(4x3)
1157 : /* LCOV_EXCL_STOP */
|