├── LICENSE ├── README.md ├── gfw.c └── gfw.h /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2018 Felipe Ferreira da Silva 2 | 3 | This software is provided 'as-is', without any express or implied warranty. In 4 | no event will the authors be held liable for any damages arising from the use of 5 | this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, including 8 | commercial applications, and to alter it and redistribute it freely, subject to 9 | the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not claim 12 | that you wrote the original software. If you use this software in a 13 | product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GFW 2 | 3 | GFW (Graphics Framework) is a small library wrapper for development with modern OpenGL. 4 | 5 | # License 6 | 7 | The source code of this project is licensed under the terms of the ZLIB license: 8 | 9 | Copyright © 2018 Felipe Ferreira da Silva 10 | 11 | This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. 12 | 13 | Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 14 | 15 | 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | -------------------------------------------------------------------------------- /gfw.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2018 Felipe Ferreira da Silva 3 | 4 | This software is provided 'as-is', without any express or implied warranty. In 5 | no event will the authors be held liable for any damages arising from the use of 6 | this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, including 9 | commercial applications, and to alter it and redistribute it freely, subject to 10 | the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not claim 13 | that you wrote the original software. If you use this software in a 14 | product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | */ 20 | 21 | #include "gfw.h" 22 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 23 | #include 24 | #endif 25 | #ifdef GFW_PRINT_BACKEND_ERROR 26 | #include 27 | #endif 28 | 29 | #ifndef GFW_SHADER_LOG_MAX_LENGTH 30 | #define GFW_SHADER_LOG_MAX_LENGTH 1024 31 | #endif 32 | 33 | /* Texture */ 34 | void gfw_texture_unbind(void) 35 | { 36 | glBindTexture(GL_TEXTURE_2D, 0); 37 | #ifdef GFW_CHECK_BACKEND_ERROR 38 | if (glGetError() != GL_NO_ERROR) { 39 | #ifdef GFW_PRINT_BACKEND_ERROR 40 | printf("Error: failed to unbind texture.\n"); 41 | #endif 42 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 43 | abort(); 44 | #endif 45 | } 46 | #endif 47 | } 48 | 49 | void gfw_texture_bind(struct gfw_texture *texture) 50 | { 51 | glBindTexture(GL_TEXTURE_2D, texture->texture_gl_id); 52 | #ifdef GFW_CHECK_BACKEND_ERROR 53 | if (glGetError() != GL_NO_ERROR) { 54 | #ifdef GFW_PRINT_BACKEND_ERROR 55 | printf("Error: failed to bind texture.\n"); 56 | #endif 57 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 58 | abort(); 59 | #endif 60 | } 61 | #endif 62 | } 63 | 64 | void gfw_texture_activate(uint32_t index) 65 | { 66 | GLenum texture = GL_TEXTURE0; 67 | if (index > GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS || index > 31) { 68 | #ifdef GFW_PRINT_BACKEND_ERROR 69 | printf("Error: failed to activate texture of index out of range.\n"); 70 | #endif 71 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 72 | abort(); 73 | #endif 74 | } 75 | texture = texture + index; 76 | glActiveTexture(texture); 77 | #ifdef GFW_CHECK_BACKEND_ERROR 78 | if (glGetError() != GL_NO_ERROR) { 79 | #ifdef GFW_PRINT_BACKEND_ERROR 80 | printf("Error: failed to activate image.\n"); 81 | #endif 82 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 83 | abort(); 84 | #endif 85 | } 86 | #endif 87 | } 88 | 89 | void gfw_texture_put_subimage(struct gfw_texture *texture, int32_t x, int32_t y, uint8_t *data, uint32_t width, uint32_t height) 90 | { 91 | glBindTexture(GL_TEXTURE_2D, texture->texture_gl_id); 92 | #ifdef GFW_CHECK_BACKEND_ERROR 93 | if (glGetError() != GL_NO_ERROR) { 94 | #ifdef GFW_PRINT_BACKEND_ERROR 95 | printf("Error: failed to bind texture.\n"); 96 | #endif 97 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 98 | abort(); 99 | #endif 100 | } 101 | #endif 102 | glTexSubImage2D(GL_TEXTURE_2D, 103 | 0, 104 | x, 105 | y, 106 | width, 107 | height, 108 | texture->pixel_format, 109 | GL_UNSIGNED_BYTE, 110 | data); 111 | #ifdef GFW_CHECK_BACKEND_ERROR 112 | if (glGetError() != GL_NO_ERROR) { 113 | #ifdef GFW_PRINT_BACKEND_ERROR 114 | printf("Error: failed to set texture sub image.\n"); 115 | #endif 116 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 117 | abort(); 118 | #endif 119 | } 120 | #endif 121 | glBindTexture(GL_TEXTURE_2D, 0); 122 | #ifdef GFW_CHECK_BACKEND_ERROR 123 | if (glGetError() != GL_NO_ERROR) { 124 | #ifdef GFW_PRINT_BACKEND_ERROR 125 | printf("Error: failed to unbind texture.\n"); 126 | #endif 127 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 128 | abort(); 129 | #endif 130 | } 131 | #endif 132 | } 133 | 134 | void gfw_free_texture(struct gfw_texture *texture) 135 | { 136 | if (glIsTexture(texture->texture_gl_id)) { 137 | glDeleteTextures(1, &texture->texture_gl_id); 138 | #ifdef GFW_CHECK_BACKEND_ERROR 139 | if (glGetError() != GL_NO_ERROR) { 140 | #ifdef GFW_PRINT_BACKEND_ERROR 141 | printf("Error: failed to delete texture.\n"); 142 | #endif 143 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 144 | abort(); 145 | #endif 146 | } 147 | #endif 148 | } else { 149 | #ifdef GFW_PRINT_BACKEND_ERROR 150 | printf("Error: failed to delete invalid texture.\n"); 151 | #endif 152 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 153 | abort(); 154 | #endif 155 | } 156 | texture->texture_gl_id = 0; 157 | texture->pixel_format = 0; 158 | texture->width = 0; 159 | texture->height = 0; 160 | } 161 | 162 | bool gfw_init_texture(struct gfw_texture *texture, struct gfw_texture_descriptor descriptor) 163 | { 164 | bool success = true; 165 | texture->width = descriptor.width; 166 | texture->height = descriptor.height; 167 | texture->pixel_format = descriptor.pixel_format; 168 | glGenTextures(1, &texture->texture_gl_id); 169 | #ifdef GFW_CHECK_BACKEND_ERROR 170 | if (glGetError() != GL_NO_ERROR) { 171 | success = false; 172 | #ifdef GFW_PRINT_BACKEND_ERROR 173 | printf("Error: failed to generate texture.\n"); 174 | #endif 175 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 176 | abort(); 177 | #else 178 | goto done; 179 | #endif 180 | } 181 | #endif 182 | glBindTexture(GL_TEXTURE_2D, texture->texture_gl_id); 183 | #ifdef GFW_CHECK_BACKEND_ERROR 184 | if (glGetError() != GL_NO_ERROR) { 185 | success = false; 186 | #ifdef GFW_PRINT_BACKEND_ERROR 187 | printf("Error: failed to bind texture.\n"); 188 | #endif 189 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 190 | abort(); 191 | #else 192 | goto done; 193 | #endif 194 | } 195 | #endif 196 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, descriptor.horizontal_wrap); 197 | #ifdef GFW_CHECK_BACKEND_ERROR 198 | if (glGetError() != GL_NO_ERROR) { 199 | success = false; 200 | #ifdef GFW_PRINT_BACKEND_ERROR 201 | printf("Error: failed to set texture wrap-s parameter.\n"); 202 | #endif 203 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 204 | abort(); 205 | #else 206 | goto done; 207 | #endif 208 | } 209 | #endif 210 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, descriptor.vertical_wrap); 211 | #ifdef GFW_CHECK_BACKEND_ERROR 212 | if (glGetError() != GL_NO_ERROR) { 213 | success = false; 214 | #ifdef GFW_PRINT_BACKEND_ERROR 215 | printf("Error: failed to set texture wrap-t parameter.\n"); 216 | #endif 217 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 218 | abort(); 219 | #else 220 | goto done; 221 | #endif 222 | } 223 | #endif 224 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, descriptor.mag_filter); 225 | #ifdef GFW_CHECK_BACKEND_ERROR 226 | if (glGetError() != GL_NO_ERROR) { 227 | success = false; 228 | #ifdef GFW_PRINT_BACKEND_ERROR 229 | printf("Error: failed to set texture mag-filter parameter.\n"); 230 | #endif 231 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 232 | abort(); 233 | #else 234 | goto done; 235 | #endif 236 | } 237 | #endif 238 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, descriptor.min_filter); 239 | #ifdef GFW_CHECK_BACKEND_ERROR 240 | if (glGetError() != GL_NO_ERROR) { 241 | success = false; 242 | #ifdef GFW_PRINT_BACKEND_ERROR 243 | printf("Error: failed to set texture min-filter parameter.\n"); 244 | #endif 245 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 246 | abort(); 247 | #else 248 | goto done; 249 | #endif 250 | } 251 | #endif 252 | glTexImage2D(GL_TEXTURE_2D, 253 | 0, 254 | descriptor.pixel_format, 255 | descriptor.width, 256 | descriptor.height, 257 | 0, 258 | descriptor.pixel_format, 259 | GL_UNSIGNED_BYTE, 260 | descriptor.data); 261 | #ifdef GFW_CHECK_BACKEND_ERROR 262 | if (glGetError() != GL_NO_ERROR) { 263 | success = false; 264 | #ifdef GFW_PRINT_BACKEND_ERROR 265 | printf("Error: failed to set texture image.\n"); 266 | #endif 267 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 268 | abort(); 269 | #else 270 | goto done; 271 | #endif 272 | } 273 | #endif 274 | #ifdef GFW_CHECK_BACKEND_ERROR 275 | if (!glIsTexture(texture->texture_gl_id)) { 276 | success = false; 277 | #ifdef GFW_PRINT_BACKEND_ERROR 278 | printf("Error: failed to generate valid texture.\n"); 279 | #endif 280 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 281 | abort(); 282 | #else 283 | goto done; 284 | #endif 285 | } 286 | #endif 287 | glBindTexture(GL_TEXTURE_2D, 0); 288 | #ifdef GFW_CHECK_BACKEND_ERROR 289 | if (glGetError() != GL_NO_ERROR) { 290 | success = false; 291 | #ifdef GFW_PRINT_BACKEND_ERROR 292 | printf("Warning: failed to unbind texture.\n"); 293 | #endif 294 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 295 | abort(); 296 | #endif 297 | } 298 | #endif 299 | #if defined(GFW_CHECK_BACKEND_ERROR) && !defined(GFW_ABORT_ON_BACKEND_ERROR) 300 | done: 301 | #endif 302 | return success; 303 | } 304 | 305 | /* Framebuffer */ 306 | void gfw_framebuffer_clear_color(gfw_float_t r, gfw_float_t g, gfw_float_t b, gfw_float_t a) 307 | { 308 | glClearColor(r, g, b, a); 309 | #ifdef GFW_CHECK_BACKEND_ERROR 310 | if (glGetError() != GL_NO_ERROR) { 311 | #ifdef GFW_PRINT_BACKEND_ERROR 312 | printf("Error: failed to set clear color value.\n"); 313 | #endif 314 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 315 | abort(); 316 | #endif 317 | } 318 | #endif 319 | } 320 | 321 | void gfw_framebuffer_clear_depth(gfw_float_t depth) 322 | { 323 | glClearDepth(depth); 324 | #ifdef GFW_CHECK_BACKEND_ERROR 325 | if (glGetError() != GL_NO_ERROR) { 326 | #ifdef GFW_PRINT_BACKEND_ERROR 327 | printf("Error: failed to set clear depth value.\n"); 328 | #endif 329 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 330 | abort(); 331 | #endif 332 | } 333 | #endif 334 | } 335 | 336 | void gfw_framebuffer_clear(bool color, bool depth) 337 | { 338 | GLbitfield mask = 0; 339 | if (color) { 340 | mask = mask | GL_COLOR_BUFFER_BIT; 341 | } 342 | if (depth) { 343 | mask = mask | GL_DEPTH_BUFFER_BIT; 344 | } 345 | glClear(mask); 346 | #ifdef GFW_CHECK_BACKEND_ERROR 347 | if (glGetError() != GL_NO_ERROR) { 348 | #ifdef GFW_PRINT_BACKEND_ERROR 349 | printf("Error: failed to clear framebuffer.\n"); 350 | #endif 351 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 352 | abort(); 353 | #endif 354 | } 355 | #endif 356 | } 357 | 358 | void gfw_framebuffer_unbind(void) 359 | { 360 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 361 | #ifdef GFW_CHECK_BACKEND_ERROR 362 | if (glGetError() != GL_NO_ERROR) { 363 | #ifdef GFW_PRINT_BACKEND_ERROR 364 | printf("Error: failed to unbind framebuffer.\n"); 365 | #endif 366 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 367 | abort(); 368 | #endif 369 | } 370 | #endif 371 | } 372 | 373 | void gfw_framebuffer_bind(struct gfw_framebuffer *framebuffer) 374 | { 375 | glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->framebuffer_gl_id); 376 | #ifdef GFW_CHECK_BACKEND_ERROR 377 | if (glGetError() != GL_NO_ERROR) { 378 | #ifdef GFW_PRINT_BACKEND_ERROR 379 | printf("Error: failed to bind framebuffer.\n"); 380 | #endif 381 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 382 | abort(); 383 | #endif 384 | } 385 | #endif 386 | } 387 | 388 | void gfw_free_framebuffer(struct gfw_framebuffer *framebuffer) 389 | { 390 | if (glIsFramebuffer(framebuffer->framebuffer_gl_id)) { 391 | glDeleteFramebuffers(1, &framebuffer->framebuffer_gl_id); 392 | #ifdef GFW_CHECK_BACKEND_ERROR 393 | if (glGetError() != GL_NO_ERROR) { 394 | #ifdef GFW_PRINT_BACKEND_ERROR 395 | printf("Error: failed to delete framebuffer.\n"); 396 | #endif 397 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 398 | abort(); 399 | #endif 400 | } 401 | #endif 402 | } else { 403 | #ifdef GFW_PRINT_BACKEND_ERROR 404 | printf("Error: failed to delete invalid framebuffer.\n"); 405 | #endif 406 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 407 | abort(); 408 | #endif 409 | } 410 | framebuffer->framebuffer_gl_id = 0; 411 | framebuffer->texture = NULL; 412 | } 413 | 414 | bool gfw_init_framebuffer(struct gfw_framebuffer *framebuffer, struct gfw_texture *texture) 415 | { 416 | bool success = true; 417 | framebuffer->texture = texture; 418 | glGenFramebuffers(1, &framebuffer->framebuffer_gl_id); 419 | #ifdef GFW_CHECK_BACKEND_ERROR 420 | if (glGetError() != GL_NO_ERROR) { 421 | success = false; 422 | #ifdef GFW_PRINT_BACKEND_ERROR 423 | printf("Error: failed to generate framebuffer.\n"); 424 | #endif 425 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 426 | abort(); 427 | #else 428 | goto done; 429 | #endif 430 | } 431 | #endif 432 | glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->framebuffer_gl_id); 433 | #ifdef GFW_CHECK_BACKEND_ERROR 434 | if (glGetError() != GL_NO_ERROR) { 435 | success = false; 436 | #ifdef GFW_PRINT_BACKEND_ERROR 437 | printf("Error: failed to bind framebuffer.\n"); 438 | #endif 439 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 440 | abort(); 441 | #else 442 | goto done; 443 | #endif 444 | } 445 | #endif 446 | if (texture) { 447 | glBindTexture(GL_TEXTURE_2D, texture->texture_gl_id); 448 | #ifdef GFW_CHECK_BACKEND_ERROR 449 | if (glGetError() != GL_NO_ERROR) { 450 | success = false; 451 | #ifdef GFW_PRINT_BACKEND_ERROR 452 | printf("Error: failed to bind texture for framebuffer.\n"); 453 | #endif 454 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 455 | abort(); 456 | #else 457 | goto done; 458 | #endif 459 | } 460 | #endif 461 | glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture->texture_gl_id, 0); 462 | #ifdef GFW_CHECK_BACKEND_ERROR 463 | if (glGetError() != GL_NO_ERROR) { 464 | success = false; 465 | #ifdef GFW_PRINT_BACKEND_ERROR 466 | printf("Warning: failed to set framebuffer texture.\n"); 467 | #endif 468 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 469 | abort(); 470 | #else 471 | goto done; 472 | #endif 473 | } 474 | #endif 475 | } 476 | #ifdef GFW_CHECK_BACKEND_ERROR 477 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 478 | success = false; 479 | #ifdef GFW_PRINT_BACKEND_ERROR 480 | printf("Error: failed to create complete framebuffer.\n"); 481 | #endif 482 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 483 | abort(); 484 | #else 485 | goto done; 486 | #endif 487 | } 488 | #endif 489 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 490 | #ifdef GFW_CHECK_BACKEND_ERROR 491 | if (glGetError() != GL_NO_ERROR) { 492 | success = false; 493 | #ifdef GFW_PRINT_BACKEND_ERROR 494 | printf("Error: failed to unbind framebuffer.\n"); 495 | #endif 496 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 497 | abort(); 498 | #endif 499 | } 500 | #endif 501 | #if defined(GFW_CHECK_BACKEND_ERROR) && !defined(GFW_ABORT_ON_BACKEND_ERROR) 502 | done: 503 | #endif 504 | return success; 505 | } 506 | 507 | /* Vertex Data */ 508 | void gfw_vertex_data_clear(struct gfw_vertex_data *vertex_data) 509 | { 510 | uint32_t i = 0; 511 | while (i < vertex_data->range) { 512 | vertex_data->buffer[i] = 0; 513 | i++; 514 | } 515 | } 516 | 517 | bool gfw_vertex_data_push(struct gfw_vertex_data *vertex_data, uint8_t *data, size_t size) 518 | { 519 | bool success = true; 520 | uint32_t i = 0; 521 | if (vertex_data->count + size > vertex_data->range) { 522 | success = false; 523 | #ifdef GFW_PRINT_BACKEND_ERROR 524 | printf("Warning: not enough space in vertex data for data.\n"); 525 | #endif 526 | goto done; 527 | } 528 | while (i < size) { 529 | vertex_data->buffer[vertex_data->count + i] = data[i]; 530 | i++; 531 | } 532 | vertex_data->count = vertex_data->count + size; 533 | done: 534 | return success; 535 | } 536 | 537 | void gfw_vertex_data_unmap(void) 538 | { 539 | if (!glUnmapBuffer(GL_ARRAY_BUFFER)) { 540 | #ifdef GFW_PRINT_BACKEND_ERROR 541 | printf("Warning: failed to unmap vertex data.\n"); 542 | #endif 543 | #ifdef GFW_CHECK_BACKEND_ERROR 544 | if (glGetError() != GL_NO_ERROR) { 545 | #ifdef GFW_PRINT_BACKEND_ERROR 546 | printf("Error: failed to unmap vertex data.\n"); 547 | #endif 548 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 549 | abort(); 550 | #endif 551 | } 552 | #endif 553 | } 554 | } 555 | 556 | void gfw_vertex_data_map_range(struct gfw_vertex_data *vertex_data, bool read, bool write, size_t offset, size_t range) 557 | { 558 | GLint vbo_gl_id = 0; 559 | glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vbo_gl_id); 560 | #ifdef GFW_CHECK_BACKEND_ERROR 561 | if (vbo_gl_id == 0 || vbo_gl_id != (GLint)vertex_data->vbo_gl_id) { 562 | #ifdef GFW_PRINT_BACKEND_ERROR 563 | printf("Error: failed to map not bound vertex data.\n"); 564 | #endif 565 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 566 | abort(); 567 | #endif 568 | } 569 | #endif 570 | #ifdef GFW_CHECK_BACKEND_ERROR 571 | if (offset + range >= vertex_data->size) { 572 | #ifdef GFW_PRINT_BACKEND_ERROR 573 | printf("Error: failed to map vertex data range larger than vertex data size.\n"); 574 | #endif 575 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 576 | abort(); 577 | #endif 578 | } 579 | #endif 580 | if (!read && write) { 581 | vertex_data->buffer = glMapBufferRange(GL_ARRAY_BUFFER, offset, range, GL_MAP_WRITE_BIT); 582 | } else if (read && !write) { 583 | vertex_data->buffer = glMapBufferRange(GL_ARRAY_BUFFER, offset, range, GL_MAP_READ_BIT); 584 | } else if (read && write) { 585 | vertex_data->buffer = glMapBufferRange(GL_ARRAY_BUFFER, offset, range, GL_MAP_WRITE_BIT | GL_MAP_READ_BIT); 586 | } 587 | #ifdef GFW_CHECK_BACKEND_ERROR 588 | if (glGetError() != GL_NO_ERROR) { 589 | #ifdef GFW_PRINT_BACKEND_ERROR 590 | printf("Error: failed to map vertex data with range.\n"); 591 | #endif 592 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 593 | abort(); 594 | #endif 595 | } 596 | #endif 597 | vertex_data->range = range; 598 | vertex_data->count = 0; 599 | } 600 | 601 | void gfw_vertex_data_map(struct gfw_vertex_data *vertex_data, bool read, bool write) 602 | { 603 | GLint vbo_gl_id = 0; 604 | glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vbo_gl_id); 605 | #ifdef GFW_CHECK_BACKEND_ERROR 606 | if (vbo_gl_id == 0 || vbo_gl_id != (GLint)vertex_data->vbo_gl_id) { 607 | #ifdef GFW_PRINT_BACKEND_ERROR 608 | printf("Error: failed to map not bound vertex data.\n"); 609 | #endif 610 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 611 | abort(); 612 | #endif 613 | } 614 | #endif 615 | if (!read && write) { 616 | vertex_data->buffer = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); 617 | } else if (read && !write) { 618 | vertex_data->buffer = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); 619 | } else if (read && write) { 620 | vertex_data->buffer = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); 621 | } 622 | #ifdef GFW_CHECK_BACKEND_ERROR 623 | if (glGetError() != GL_NO_ERROR) { 624 | #ifdef GFW_PRINT_BACKEND_ERROR 625 | printf("Error: failed to map vertex data.\n"); 626 | #endif 627 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 628 | abort(); 629 | #endif 630 | } 631 | #endif 632 | vertex_data->range = vertex_data->size; 633 | vertex_data->count = 0; 634 | } 635 | 636 | void gfw_vertex_data_unbind(void) 637 | { 638 | glBindBuffer(GL_ARRAY_BUFFER, 0); 639 | #ifdef GFW_CHECK_BACKEND_ERROR 640 | if (glGetError() != GL_NO_ERROR) { 641 | #ifdef GFW_PRINT_BACKEND_ERROR 642 | printf("Error: failed to unbind vertex data.\n"); 643 | #endif 644 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 645 | abort(); 646 | #endif 647 | } 648 | #endif 649 | } 650 | 651 | void gfw_vertex_data_bind(struct gfw_vertex_data *vertex_data) 652 | { 653 | glBindBuffer(GL_ARRAY_BUFFER, vertex_data->vbo_gl_id); 654 | #ifdef GFW_CHECK_BACKEND_ERROR 655 | if (glGetError() != GL_NO_ERROR) { 656 | #ifdef GFW_PRINT_BACKEND_ERROR 657 | printf("Error: failed to bind vertex data.\n"); 658 | #endif 659 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 660 | abort(); 661 | #endif 662 | } 663 | #endif 664 | } 665 | 666 | void gfw_free_vertex_data(struct gfw_vertex_data *vertex_data) 667 | { 668 | glDeleteBuffers(1, &vertex_data->vbo_gl_id); 669 | #ifdef GFW_CHECK_BACKEND_ERROR 670 | if (glGetError() != GL_NO_ERROR) { 671 | #ifdef GFW_PRINT_BACKEND_ERROR 672 | printf("Error: failed to delete buffer from vertex data.\n"); 673 | #endif 674 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 675 | abort(); 676 | #endif 677 | } 678 | #endif 679 | vertex_data->vbo_gl_id = 0; 680 | vertex_data->count = 0; 681 | vertex_data->range = 0; 682 | vertex_data->size = 0; 683 | vertex_data->buffer = NULL; 684 | } 685 | 686 | bool gfw_init_vertex_data(struct gfw_vertex_data *vertex_data, size_t size, enum gfw_vertex_data_usage usage) 687 | { 688 | bool success = false; 689 | vertex_data->count = 0; 690 | vertex_data->range = 0; 691 | vertex_data->size = size; 692 | glGenBuffers(1, &vertex_data->vbo_gl_id); 693 | #ifdef GFW_CHECK_BACKEND_ERROR 694 | if (glGetError() != GL_NO_ERROR) { 695 | success = false; 696 | #ifdef GFW_PRINT_BACKEND_ERROR 697 | printf("Error: failed generate vertex buffer object for vertex data.\n"); 698 | #endif 699 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 700 | abort(); 701 | #else 702 | goto done; 703 | #endif 704 | } 705 | #endif 706 | glBindBuffer(GL_ARRAY_BUFFER, vertex_data->vbo_gl_id); 707 | #ifdef GFW_CHECK_BACKEND_ERROR 708 | if (glGetError() != GL_NO_ERROR) { 709 | success = false; 710 | #ifdef GFW_PRINT_BACKEND_ERROR 711 | printf("Error: failed to bind vertex data.\n"); 712 | #endif 713 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 714 | abort(); 715 | #else 716 | goto done; 717 | #endif 718 | } 719 | #endif 720 | /* Buffer allocation */ 721 | glBufferData(GL_ARRAY_BUFFER, 722 | vertex_data->size, 723 | NULL, 724 | usage); 725 | #ifdef GFW_CHECK_BACKEND_ERROR 726 | if (glGetError() != GL_NO_ERROR) { 727 | success = false; 728 | #ifdef GFW_PRINT_BACKEND_ERROR 729 | printf("Error: failed to create buffer for vertex data.\n"); 730 | #endif 731 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 732 | abort(); 733 | #else 734 | goto done; 735 | #endif 736 | } 737 | #endif 738 | #ifdef GFW_CHECK_BACKEND_ERROR 739 | if (!glIsBuffer(vertex_data->vbo_gl_id)) { 740 | success = false; 741 | #ifdef GFW_PRINT_BACKEND_ERROR 742 | printf("Error: failed to initialize vertex data.\n"); 743 | #endif 744 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 745 | abort(); 746 | #else 747 | goto done; 748 | #endif 749 | } 750 | #endif 751 | glBindBuffer(GL_ARRAY_BUFFER, 0); 752 | #ifdef GFW_CHECK_BACKEND_ERROR 753 | if (glGetError() != GL_NO_ERROR) { 754 | success = false; 755 | #ifdef GFW_PRINT_BACKEND_ERROR 756 | printf("Error: failed to unbind vertex data buffer.\n"); 757 | #endif 758 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 759 | abort(); 760 | #else 761 | goto done; 762 | #endif 763 | } 764 | #endif 765 | #if defined(GFW_CHECK_BACKEND_ERROR) && !defined(GFW_ABORT_ON_BACKEND_ERROR) 766 | done: 767 | #endif 768 | return success; 769 | } 770 | 771 | /* Vertex State */ 772 | void gfw_vertex_state_unbind(void) 773 | { 774 | glBindVertexArray(0); 775 | #ifdef GFW_CHECK_BACKEND_ERROR 776 | if (glGetError() != GL_NO_ERROR) { 777 | #ifdef GFW_PRINT_BACKEND_ERROR 778 | printf("Error: failed to unbind vertex state.\n"); 779 | #endif 780 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 781 | abort(); 782 | #endif 783 | } 784 | #endif 785 | } 786 | 787 | void gfw_vertex_state_bind(struct gfw_vertex_state *vertex_state) 788 | { 789 | glBindVertexArray(vertex_state->vao_gl_id); 790 | #ifdef GFW_CHECK_BACKEND_ERROR 791 | if (glGetError() != GL_NO_ERROR) { 792 | #ifdef GFW_PRINT_BACKEND_ERROR 793 | printf("Error: failed to bind vertex state.\n"); 794 | #endif 795 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 796 | abort(); 797 | #endif 798 | } 799 | #endif 800 | } 801 | 802 | void gfw_free_vertex_state(struct gfw_vertex_state *vertex_state) 803 | { 804 | glDeleteVertexArrays(1, &vertex_state->vao_gl_id); 805 | #ifdef GFW_CHECK_BACKEND_ERROR 806 | if (glGetError() != GL_NO_ERROR) { 807 | #ifdef GFW_PRINT_BACKEND_ERROR 808 | printf("Error: failed to delete vertex state.\n"); 809 | #endif 810 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 811 | abort(); 812 | #endif 813 | } 814 | #endif 815 | } 816 | 817 | bool gfw_init_vertex_state(struct gfw_vertex_state *vertex_state) 818 | { 819 | bool success = false; 820 | glGenVertexArrays(1, &vertex_state->vao_gl_id); 821 | #ifdef GFW_CHECK_BACKEND_ERROR 822 | if (glGetError() != GL_NO_ERROR) { 823 | success = false; 824 | #ifdef GFW_PRINT_BACKEND_ERROR 825 | printf("Error: failed to generate vertex array object for vertex state.\n"); 826 | #endif 827 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 828 | abort(); 829 | #else 830 | goto done; 831 | #endif 832 | } 833 | #endif 834 | glBindVertexArray(vertex_state->vao_gl_id); 835 | #ifdef GFW_CHECK_BACKEND_ERROR 836 | if (glGetError() != GL_NO_ERROR) { 837 | #ifdef GFW_PRINT_BACKEND_ERROR 838 | printf("Error: failed to bind vertex state.\n"); 839 | #endif 840 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 841 | abort(); 842 | #else 843 | goto done; 844 | #endif 845 | } 846 | #endif 847 | #ifdef GFW_CHECK_BACKEND_ERROR 848 | if (!glIsVertexArray(vertex_state->vao_gl_id)) { 849 | success = false; 850 | #ifdef GFW_PRINT_BACKEND_ERROR 851 | printf("Error: failed to initialize vertex state.\n"); 852 | #endif 853 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 854 | abort(); 855 | #else 856 | goto done; 857 | #endif 858 | } 859 | #endif 860 | glBindVertexArray(0); 861 | #ifdef GFW_CHECK_BACKEND_ERROR 862 | if (glGetError() != GL_NO_ERROR) { 863 | #ifdef GFW_PRINT_BACKEND_ERROR 864 | printf("Error: failed to unbind vertex state.\n"); 865 | #endif 866 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 867 | abort(); 868 | #endif 869 | } 870 | #endif 871 | #if defined(GFW_CHECK_BACKEND_ERROR) && !defined(GFW_ABORT_ON_BACKEND_ERROR) 872 | done: 873 | #endif 874 | return success; 875 | } 876 | 877 | /* Shader */ 878 | void gfw_shader_set_uniform_mat4(gfw_int_t location, bool normalize, gfw_float_t *matrix) 879 | { 880 | glUniformMatrix4fv(location, 1, normalize, matrix); 881 | #ifdef GFW_CHECK_BACKEND_ERROR 882 | if (glGetError() != GL_NO_ERROR) { 883 | #ifdef GFW_PRINT_BACKEND_ERROR 884 | printf("Error: failed to set 4x4 matrix uniform variable.\n"); 885 | #endif 886 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 887 | abort(); 888 | #endif 889 | } 890 | #endif 891 | } 892 | 893 | void gfw_shader_set_uniform_mat3(gfw_int_t location, bool normalize, gfw_float_t *matrix) 894 | { 895 | glUniformMatrix3fv(location, 1, normalize, matrix); 896 | #ifdef GFW_CHECK_BACKEND_ERROR 897 | if (glGetError() != GL_NO_ERROR) { 898 | #ifdef GFW_PRINT_BACKEND_ERROR 899 | printf("Error: failed to set 3x3 matrix uniform variable.\n"); 900 | #endif 901 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 902 | abort(); 903 | #endif 904 | } 905 | #endif 906 | } 907 | 908 | void gfw_shader_set_uniform_float(gfw_int_t location, gfw_float_t f) 909 | { 910 | glUniform1f(location, f); 911 | #ifdef GFW_CHECK_BACKEND_ERROR 912 | if (glGetError() != GL_NO_ERROR) { 913 | #ifdef GFW_PRINT_BACKEND_ERROR 914 | printf("Error: failed to set floating-point uniform variable.\n"); 915 | #endif 916 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 917 | abort(); 918 | #endif 919 | } 920 | #endif 921 | } 922 | 923 | void gfw_shader_set_uniform_floatv(gfw_int_t location, gfw_float_t *f, uint32_t count) 924 | { 925 | glUniform1fv(location, count, f); 926 | #ifdef GFW_CHECK_BACKEND_ERROR 927 | if (glGetError() != GL_NO_ERROR) { 928 | #ifdef GFW_PRINT_BACKEND_ERROR 929 | printf("Error: failed to set floating-point uniform array.\n"); 930 | #endif 931 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 932 | abort(); 933 | #endif 934 | } 935 | #endif 936 | } 937 | 938 | void gfw_shader_set_uniform_int(gfw_int_t location, gfw_int_t i) 939 | { 940 | glUniform1i(location, i); 941 | #ifdef GFW_CHECK_BACKEND_ERROR 942 | if (glGetError() != GL_NO_ERROR) { 943 | #ifdef GFW_PRINT_BACKEND_ERROR 944 | printf("Error: failed to set integer uniform variable.\n"); 945 | #endif 946 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 947 | abort(); 948 | #endif 949 | } 950 | #endif 951 | } 952 | 953 | void gfw_shader_set_uniform_intv(gfw_int_t location, gfw_int_t *i, uint32_t count) 954 | { 955 | glUniform1iv(location, count, i); 956 | #ifdef GFW_CHECK_BACKEND_ERROR 957 | if (glGetError() != GL_NO_ERROR) { 958 | #ifdef GFW_PRINT_BACKEND_ERROR 959 | printf("Error: failed to set integer uniform array.\n"); 960 | #endif 961 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 962 | abort(); 963 | #endif 964 | } 965 | #endif 966 | } 967 | 968 | void gfw_shader_set_uniform_uint(gfw_int_t location, gfw_uint_t i) 969 | { 970 | glUniform1ui(location, i); 971 | #ifdef GFW_CHECK_BACKEND_ERROR 972 | if (glGetError() != GL_NO_ERROR) { 973 | #ifdef GFW_PRINT_BACKEND_ERROR 974 | printf("Error: failed to set unsigned integer uniform variable.\n"); 975 | #endif 976 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 977 | abort(); 978 | #endif 979 | } 980 | #endif 981 | } 982 | 983 | void gfw_shader_set_uniform_uintv(gfw_int_t location, gfw_uint_t *i, uint32_t count) 984 | { 985 | glUniform1uiv(location, count, i); 986 | #ifdef GFW_CHECK_BACKEND_ERROR 987 | if (glGetError() != GL_NO_ERROR) { 988 | #ifdef GFW_PRINT_BACKEND_ERROR 989 | printf("Error: failed to set unsigned integer uniform array.\n"); 990 | #endif 991 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 992 | abort(); 993 | #endif 994 | } 995 | #endif 996 | } 997 | 998 | gfw_int_t gfw_shader_get_uniform_location(struct gfw_shader *shader, char *name) 999 | { 1000 | gfw_int_t location = glGetUniformLocation(shader->program_gl_id, name); 1001 | #ifdef GFW_CHECK_BACKEND_ERROR 1002 | if (glGetError() != GL_NO_ERROR) { 1003 | #ifdef GFW_PRINT_BACKEND_ERROR 1004 | printf("Error: failed to get uniform location.\n"); 1005 | #endif 1006 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1007 | abort(); 1008 | #endif 1009 | } 1010 | #endif 1011 | return location; 1012 | } 1013 | 1014 | gfw_int_t gfw_shader_get_attribute_location(struct gfw_shader *shader, char *name) 1015 | { 1016 | gfw_int_t location = glGetAttribLocation(shader->program_gl_id, name); 1017 | #ifdef GFW_CHECK_BACKEND_ERROR 1018 | if (glGetError() != GL_NO_ERROR) { 1019 | #ifdef GFW_PRINT_BACKEND_ERROR 1020 | printf("Error: failed to get shader attribute location.\n"); 1021 | #endif 1022 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1023 | abort(); 1024 | #endif 1025 | } 1026 | #endif 1027 | return location; 1028 | } 1029 | 1030 | void gfw_shader_draw_range(struct gfw_attribute *attributes, 1031 | size_t attributes_count, 1032 | enum gfw_primitive primitive, 1033 | size_t first, 1034 | size_t count) 1035 | { 1036 | uint32_t i = 0; 1037 | while (i < attributes_count) { 1038 | glEnableVertexAttribArray(attributes[i].location); 1039 | glVertexAttribPointer(attributes[i].location, 1040 | attributes[i].count, 1041 | attributes[i].type, 1042 | attributes[i].normalize, 1043 | attributes[i].stride, 1044 | (GLvoid *)attributes[i].offset); 1045 | i++; 1046 | } 1047 | glDrawArrays(primitive, first, count); 1048 | i = 0; 1049 | while (i < attributes_count) { 1050 | glDisableVertexAttribArray(attributes[i].location); 1051 | i++; 1052 | } 1053 | } 1054 | 1055 | void gfw_shader_use(struct gfw_shader *shader) 1056 | { 1057 | glUseProgram(shader->program_gl_id); 1058 | #ifdef GFW_CHECK_BACKEND_ERROR 1059 | if (glGetError() != GL_NO_ERROR) { 1060 | #ifdef GFW_PRINT_BACKEND_ERROR 1061 | printf("Error: failed to use shader.\n"); 1062 | #endif 1063 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1064 | abort(); 1065 | #endif 1066 | } 1067 | #endif 1068 | } 1069 | 1070 | void gfw_free_shader(struct gfw_shader *shader) 1071 | { 1072 | glDeleteProgram(shader->program_gl_id); 1073 | #ifdef GFW_CHECK_BACKEND_ERROR 1074 | if (glGetError() != GL_NO_ERROR) { 1075 | #ifdef GFW_PRINT_BACKEND_ERROR 1076 | printf("Error: failed to delete shader program.\n"); 1077 | #endif 1078 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1079 | abort(); 1080 | #endif 1081 | } 1082 | #endif 1083 | shader->program_gl_id = 0; 1084 | } 1085 | 1086 | static void gfw_detach_shader(GLuint program_gl_id, GLuint shader_gl_id) 1087 | { 1088 | glDetachShader(program_gl_id, shader_gl_id); 1089 | #ifdef GFW_CHECK_BACKEND_ERROR 1090 | if (glGetError() != GL_NO_ERROR) { 1091 | #ifdef GFW_PRINT_BACKEND_ERROR 1092 | printf("Error: failed to detach shader.\n"); 1093 | #endif 1094 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1095 | abort(); 1096 | #endif 1097 | } 1098 | #endif 1099 | } 1100 | 1101 | static void gfw_delete_shader(GLuint shader_gl_id) 1102 | { 1103 | glDeleteShader(shader_gl_id); 1104 | #ifdef GFW_CHECK_BACKEND_ERROR 1105 | if (glGetError() != GL_NO_ERROR) { 1106 | #ifdef GFW_PRINT_BACKEND_ERROR 1107 | printf("Error: failed to delete shader.\n"); 1108 | #endif 1109 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1110 | abort(); 1111 | #endif 1112 | } 1113 | #endif 1114 | } 1115 | 1116 | static bool gfw_compile_shader(GLuint *shader_gl_id, GLenum shader_type, char *source) 1117 | { 1118 | bool success = true; 1119 | GLint param = 0; 1120 | char log_string[GFW_SHADER_LOG_MAX_LENGTH] = {0}; 1121 | *shader_gl_id = glCreateShader(shader_type); 1122 | #ifdef GFW_CHECK_BACKEND_ERROR 1123 | if (glGetError() != GL_NO_ERROR) { 1124 | success = false; 1125 | #ifdef GFW_PRINT_BACKEND_ERROR 1126 | if (shader_type == GL_VERTEX_SHADER) { 1127 | printf("Error: failed to create vertex shader.\n"); 1128 | } else if (shader_type == GL_FRAGMENT_SHADER) { 1129 | printf("Error: failed to create fragment shader.\n"); 1130 | } else if (shader_type == GL_GEOMETRY_SHADER) { 1131 | printf("Error: failed to create geometry shader.\n"); 1132 | } 1133 | #endif 1134 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1135 | abort(); 1136 | #else 1137 | goto done; 1138 | #endif 1139 | } 1140 | #endif 1141 | glShaderSource(*shader_gl_id, 1, (const char **)&source, NULL); 1142 | #ifdef GFW_CHECK_BACKEND_ERROR 1143 | if (glGetError() != GL_NO_ERROR) { 1144 | success = false; 1145 | #ifdef GFW_PRINT_BACKEND_ERROR 1146 | if (shader_type == GL_VERTEX_SHADER) { 1147 | printf("Error: failed to set vertex shader source.\n"); 1148 | } else if (shader_type == GL_FRAGMENT_SHADER) { 1149 | printf("Error: failed to set fragment shader source.\n"); 1150 | } else if (shader_type == GL_GEOMETRY_SHADER) { 1151 | printf("Error: failed to set geometry shader source.\n"); 1152 | } 1153 | #endif 1154 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1155 | abort(); 1156 | #else 1157 | goto done; 1158 | #endif 1159 | } 1160 | #endif 1161 | glCompileShader(*shader_gl_id); 1162 | #ifdef GFW_CHECK_BACKEND_ERROR 1163 | if (glGetError() != GL_NO_ERROR) { 1164 | success = false; 1165 | #ifdef GFW_PRINT_BACKEND_ERROR 1166 | if (shader_type == GL_VERTEX_SHADER) { 1167 | printf("Error: failed to compile vertex shader.\n"); 1168 | } else if (shader_type == GL_FRAGMENT_SHADER) { 1169 | printf("Error: failed to compile fragment shader.\n"); 1170 | } else if (shader_type == GL_GEOMETRY_SHADER) { 1171 | printf("Error: failed to compile geometry shader.\n"); 1172 | } 1173 | #endif 1174 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1175 | abort(); 1176 | #else 1177 | goto done; 1178 | #endif 1179 | } 1180 | #endif 1181 | glGetShaderiv(*shader_gl_id, GL_COMPILE_STATUS, ¶m); 1182 | #ifdef GFW_CHECK_BACKEND_ERROR 1183 | if (glGetError() != GL_NO_ERROR) { 1184 | success = false; 1185 | #ifdef GFW_PRINT_BACKEND_ERROR 1186 | if (shader_type == GL_VERTEX_SHADER) { 1187 | printf("Error: failed to get vertex shader status.\n"); 1188 | } else if (shader_type == GL_FRAGMENT_SHADER) { 1189 | printf("Error: failed to get fragment shader status.\n"); 1190 | } else if (shader_type == GL_GEOMETRY_SHADER) { 1191 | printf("Error: failed to get geometry shader status.\n"); 1192 | } 1193 | #endif 1194 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1195 | abort(); 1196 | #else 1197 | goto done; 1198 | #endif 1199 | } 1200 | #endif 1201 | if (!param) { 1202 | GLsizei length; 1203 | glGetShaderInfoLog(*shader_gl_id, 1204 | GFW_SHADER_LOG_MAX_LENGTH, 1205 | &length, 1206 | log_string); 1207 | #ifdef GFW_CHECK_BACKEND_ERROR 1208 | if (glGetError() != GL_NO_ERROR) { 1209 | success = false; 1210 | #ifdef GFW_PRINT_BACKEND_ERROR 1211 | if (shader_type == GL_VERTEX_SHADER) { 1212 | printf("Error: failed to get vertex shader info log.\n"); 1213 | } else if (shader_type == GL_FRAGMENT_SHADER) { 1214 | printf("Error: failed to get fragment shader info log.\n"); 1215 | } else if (shader_type == GL_GEOMETRY_SHADER) { 1216 | printf("Error: failed to get geometry shader info log.\n"); 1217 | } 1218 | #endif 1219 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1220 | abort(); 1221 | #else 1222 | goto done; 1223 | #endif 1224 | } 1225 | #endif 1226 | #ifdef GFW_PRINT_BACKEND_ERROR 1227 | if (shader_type == GL_VERTEX_SHADER) { 1228 | printf("Vertex shader error:\n %s", log_string); 1229 | } else if (shader_type == GL_FRAGMENT_SHADER) { 1230 | printf("Fragment shader error:\n %s", log_string); 1231 | } else if (shader_type == GL_GEOMETRY_SHADER) { 1232 | printf("Geometry shader error:\n %s", log_string); 1233 | } 1234 | #endif 1235 | success = false; 1236 | goto done; 1237 | } 1238 | done: 1239 | return success; 1240 | } 1241 | 1242 | bool gfw_init_shader(struct gfw_shader *shader, char *vertex_source, char *geometry_source, char *fragment_source) 1243 | { 1244 | bool success = true; 1245 | GLuint vertex_shader_gl_id = 0; 1246 | GLuint geometry_shader_gl_id = 0; 1247 | GLuint fragment_shader_gl_id = 0; 1248 | GLint param = 0; 1249 | char log_string[GFW_SHADER_LOG_MAX_LENGTH] = {0}; 1250 | /* Vertex shader */ 1251 | if (!gfw_compile_shader(&vertex_shader_gl_id, GL_VERTEX_SHADER, vertex_source)) { 1252 | success = false; 1253 | goto done; 1254 | } 1255 | if (geometry_source) { 1256 | if (!gfw_compile_shader(&geometry_shader_gl_id, GL_GEOMETRY_SHADER, geometry_source)) { 1257 | success = false; 1258 | goto done; 1259 | } 1260 | } 1261 | if (!gfw_compile_shader(&fragment_shader_gl_id, GL_FRAGMENT_SHADER, fragment_source)) { 1262 | success = false; 1263 | goto done; 1264 | } 1265 | /* Create program and attach shaders */ 1266 | shader->program_gl_id = glCreateProgram(); 1267 | #ifdef GFW_CHECK_BACKEND_ERROR 1268 | if (glGetError() != GL_NO_ERROR) { 1269 | success = false; 1270 | #ifdef GFW_PRINT_BACKEND_ERROR 1271 | printf("Error: failed to create shader program.\n"); 1272 | #endif 1273 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1274 | abort(); 1275 | #else 1276 | goto done; 1277 | #endif 1278 | } 1279 | #endif 1280 | glAttachShader(shader->program_gl_id, vertex_shader_gl_id); 1281 | #ifdef GFW_CHECK_BACKEND_ERROR 1282 | if (glGetError() != GL_NO_ERROR) { 1283 | success = false; 1284 | #ifdef GFW_PRINT_BACKEND_ERROR 1285 | printf("Error: failed to attach vertex shader.\n"); 1286 | #endif 1287 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1288 | abort(); 1289 | #else 1290 | goto done; 1291 | #endif 1292 | } 1293 | #endif 1294 | if (geometry_source) { 1295 | glAttachShader(shader->program_gl_id, geometry_shader_gl_id); 1296 | #ifdef GFW_CHECK_BACKEND_ERROR 1297 | if (glGetError() != GL_NO_ERROR) { 1298 | success = false; 1299 | #ifdef GFW_PRINT_BACKEND_ERROR 1300 | printf("Error: failed to attach geometry shader.\n"); 1301 | #endif 1302 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1303 | abort(); 1304 | #else 1305 | goto done; 1306 | #endif 1307 | } 1308 | #endif 1309 | } 1310 | glAttachShader(shader->program_gl_id, fragment_shader_gl_id); 1311 | #ifdef GFW_CHECK_BACKEND_ERROR 1312 | if (glGetError() != GL_NO_ERROR) { 1313 | success = false; 1314 | #ifdef GFW_PRINT_BACKEND_ERROR 1315 | printf("Error: failed to attach fragment shader.\n"); 1316 | #endif 1317 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1318 | abort(); 1319 | #else 1320 | goto done; 1321 | #endif 1322 | } 1323 | #endif 1324 | glLinkProgram(shader->program_gl_id); 1325 | #ifdef GFW_CHECK_BACKEND_ERROR 1326 | if (glGetError() != GL_NO_ERROR) { 1327 | success = false; 1328 | #ifdef GFW_PRINT_BACKEND_ERROR 1329 | printf("Error: failed to link shader program.\n"); 1330 | #endif 1331 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1332 | abort(); 1333 | #else 1334 | goto done; 1335 | #endif 1336 | } 1337 | #endif 1338 | /* Check status */ 1339 | glGetProgramiv(shader->program_gl_id, GL_LINK_STATUS, ¶m); 1340 | #ifdef GFW_CHECK_BACKEND_ERROR 1341 | if (glGetError() != GL_NO_ERROR) { 1342 | success = false; 1343 | #ifdef GFW_PRINT_BACKEND_ERROR 1344 | printf("Error: failed to get shader program status.\n"); 1345 | #endif 1346 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1347 | abort(); 1348 | #else 1349 | goto done; 1350 | #endif 1351 | } 1352 | #endif 1353 | if (!param) { 1354 | GLsizei length; 1355 | glGetProgramInfoLog(shader->program_gl_id, 1356 | GFW_SHADER_LOG_MAX_LENGTH, 1357 | &length, 1358 | log_string); 1359 | #ifdef GFW_CHECK_BACKEND_ERROR 1360 | if (glGetError() != GL_NO_ERROR) { 1361 | success = false; 1362 | #ifdef GFW_PRINT_BACKEND_ERROR 1363 | printf("Error: failed to get program info log.\n"); 1364 | #endif 1365 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1366 | abort(); 1367 | #else 1368 | goto done; 1369 | #endif 1370 | } 1371 | #endif 1372 | #ifdef GFW_PRINT_BACKEND_ERROR 1373 | printf("Program shader error:\n %s", log_string); 1374 | #endif 1375 | gfw_delete_shader(vertex_shader_gl_id); 1376 | if (geometry_source) { 1377 | gfw_delete_shader(geometry_shader_gl_id); 1378 | } 1379 | gfw_delete_shader(fragment_shader_gl_id); 1380 | success = false; 1381 | goto done; 1382 | } 1383 | /* Detach and delete unneeded shaders */ 1384 | gfw_detach_shader(shader->program_gl_id, vertex_shader_gl_id); 1385 | gfw_delete_shader(vertex_shader_gl_id); 1386 | if (geometry_source) { 1387 | gfw_detach_shader(shader->program_gl_id, geometry_shader_gl_id); 1388 | gfw_delete_shader(geometry_shader_gl_id); 1389 | } 1390 | gfw_detach_shader(shader->program_gl_id, fragment_shader_gl_id); 1391 | gfw_delete_shader(fragment_shader_gl_id); 1392 | done: 1393 | return success; 1394 | } 1395 | 1396 | /* Graphic state */ 1397 | void gfw_set_viewport(int32_t x, int32_t y, uint32_t width, uint32_t height) 1398 | { 1399 | glViewport(x, y, width, height); 1400 | #ifdef GFW_CHECK_BACKEND_ERROR 1401 | if (glGetError() != GL_NO_ERROR) { 1402 | #ifdef GFW_PRINT_BACKEND_ERROR 1403 | printf("Error: failed to set viewport.\n"); 1404 | #endif 1405 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1406 | abort(); 1407 | #endif 1408 | } 1409 | #endif 1410 | } 1411 | 1412 | void gfw_enable_blend(void) 1413 | { 1414 | glEnable(GL_BLEND); 1415 | #ifdef GFW_CHECK_BACKEND_ERROR 1416 | if (glGetError() != GL_NO_ERROR) { 1417 | #ifdef GFW_PRINT_BACKEND_ERROR 1418 | printf("Error: failed to enable blending.\n"); 1419 | #endif 1420 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1421 | abort(); 1422 | #endif 1423 | } 1424 | #endif 1425 | } 1426 | 1427 | void gfw_disable_blend(void) 1428 | { 1429 | glDisable(GL_BLEND); 1430 | #ifdef GFW_CHECK_BACKEND_ERROR 1431 | if (glGetError() != GL_NO_ERROR) { 1432 | #ifdef GFW_PRINT_BACKEND_ERROR 1433 | printf("Error: failed to disable blending.\n"); 1434 | #endif 1435 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1436 | abort(); 1437 | #endif 1438 | } 1439 | #endif 1440 | } 1441 | 1442 | void gfw_enable_clip_distance(uint32_t i) 1443 | { 1444 | glEnable(GL_CLIP_DISTANCE0 + i); 1445 | #ifdef GFW_CHECK_BACKEND_ERROR 1446 | if (glGetError() != GL_NO_ERROR) { 1447 | #ifdef GFW_PRINT_BACKEND_ERROR 1448 | printf("Error: failed to enable clip distance in space %u.\n", i); 1449 | #endif 1450 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1451 | abort(); 1452 | #endif 1453 | } 1454 | #endif 1455 | } 1456 | 1457 | void gfw_disable_clip_distance(uint32_t i) 1458 | { 1459 | glDisable(GL_CLIP_DISTANCE0 + i); 1460 | #ifdef GFW_CHECK_BACKEND_ERROR 1461 | if (glGetError() != GL_NO_ERROR) { 1462 | #ifdef GFW_PRINT_BACKEND_ERROR 1463 | printf("Error: failed to disable clip distance in space %u.\n", i); 1464 | #endif 1465 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1466 | abort(); 1467 | #endif 1468 | } 1469 | #endif 1470 | } 1471 | 1472 | void gfw_enable_color_logic_operation(void) 1473 | { 1474 | glEnable(GL_COLOR_LOGIC_OP); 1475 | #ifdef GFW_CHECK_BACKEND_ERROR 1476 | if (glGetError() != GL_NO_ERROR) { 1477 | #ifdef GFW_PRINT_BACKEND_ERROR 1478 | printf("Error: failed to enable color logic operation.\n"); 1479 | #endif 1480 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1481 | abort(); 1482 | #endif 1483 | } 1484 | #endif 1485 | } 1486 | 1487 | void gfw_disable_color_logic_operation(void) 1488 | { 1489 | glDisable(GL_COLOR_LOGIC_OP); 1490 | #ifdef GFW_CHECK_BACKEND_ERROR 1491 | if (glGetError() != GL_NO_ERROR) { 1492 | #ifdef GFW_PRINT_BACKEND_ERROR 1493 | printf("Error: failed to disable color logic operation.\n"); 1494 | #endif 1495 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1496 | abort(); 1497 | #endif 1498 | } 1499 | #endif 1500 | } 1501 | 1502 | void gfw_enable_cull_face(void) 1503 | { 1504 | glEnable(GL_CULL_FACE); 1505 | #ifdef GFW_CHECK_BACKEND_ERROR 1506 | if (glGetError() != GL_NO_ERROR) { 1507 | #ifdef GFW_PRINT_BACKEND_ERROR 1508 | printf("Error: failed to enable cull face.\n"); 1509 | #endif 1510 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1511 | abort(); 1512 | #endif 1513 | } 1514 | #endif 1515 | } 1516 | 1517 | void gfw_disable_cull_face(void) 1518 | { 1519 | glDisable(GL_CULL_FACE); 1520 | #ifdef GFW_CHECK_BACKEND_ERROR 1521 | if (glGetError() != GL_NO_ERROR) { 1522 | #ifdef GFW_PRINT_BACKEND_ERROR 1523 | printf("Error: failed to disable cull face.\n"); 1524 | #endif 1525 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1526 | abort(); 1527 | #endif 1528 | } 1529 | #endif 1530 | } 1531 | 1532 | void gfw_enable_depth_clamp(void) 1533 | { 1534 | glEnable(GL_DEPTH_CLAMP); 1535 | #ifdef GFW_CHECK_BACKEND_ERROR 1536 | if (glGetError() != GL_NO_ERROR) { 1537 | #ifdef GFW_PRINT_BACKEND_ERROR 1538 | printf("Error: failed to enable depth clamp.\n"); 1539 | #endif 1540 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1541 | abort(); 1542 | #endif 1543 | } 1544 | #endif 1545 | } 1546 | 1547 | void gfw_disable_depth_clamp(void) 1548 | { 1549 | glDisable(GL_DEPTH_CLAMP); 1550 | #ifdef GFW_CHECK_BACKEND_ERROR 1551 | if (glGetError() != GL_NO_ERROR) { 1552 | #ifdef GFW_PRINT_BACKEND_ERROR 1553 | printf("Error: failed to disable depth clamp.\n"); 1554 | #endif 1555 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1556 | abort(); 1557 | #endif 1558 | } 1559 | #endif 1560 | } 1561 | 1562 | void gfw_enable_depth_test(void) 1563 | { 1564 | glEnable(GL_DEPTH_TEST); 1565 | #ifdef GFW_CHECK_BACKEND_ERROR 1566 | if (glGetError() != GL_NO_ERROR) { 1567 | #ifdef GFW_PRINT_BACKEND_ERROR 1568 | printf("Error: failed to enable depth test.\n"); 1569 | #endif 1570 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1571 | abort(); 1572 | #endif 1573 | } 1574 | #endif 1575 | } 1576 | 1577 | void gfw_disable_depth_test(void) 1578 | { 1579 | glDisable(GL_DEPTH_TEST); 1580 | #ifdef GFW_CHECK_BACKEND_ERROR 1581 | if (glGetError() != GL_NO_ERROR) { 1582 | #ifdef GFW_PRINT_BACKEND_ERROR 1583 | printf("Error: failed to disable depth test.\n"); 1584 | #endif 1585 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1586 | abort(); 1587 | #endif 1588 | } 1589 | #endif 1590 | } 1591 | 1592 | void gfw_enable_dither(void) 1593 | { 1594 | glEnable(GL_DITHER); 1595 | #ifdef GFW_CHECK_BACKEND_ERROR 1596 | if (glGetError() != GL_NO_ERROR) { 1597 | #ifdef GFW_PRINT_BACKEND_ERROR 1598 | printf("Error: failed to enable dither.\n"); 1599 | #endif 1600 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1601 | abort(); 1602 | #endif 1603 | } 1604 | #endif 1605 | } 1606 | 1607 | void gfw_disable_dither(void) 1608 | { 1609 | glDisable(GL_DITHER); 1610 | #ifdef GFW_CHECK_BACKEND_ERROR 1611 | if (glGetError() != GL_NO_ERROR) { 1612 | #ifdef GFW_PRINT_BACKEND_ERROR 1613 | printf("Error: failed to enable dither.\n"); 1614 | #endif 1615 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1616 | abort(); 1617 | #endif 1618 | } 1619 | #endif 1620 | } 1621 | 1622 | void gfw_enable_line_smooth(void) 1623 | { 1624 | glEnable(GL_LINE_SMOOTH); 1625 | #ifdef GFW_CHECK_BACKEND_ERROR 1626 | if (glGetError() != GL_NO_ERROR) { 1627 | #ifdef GFW_PRINT_BACKEND_ERROR 1628 | printf("Error: failed to enable line smooth.\n"); 1629 | #endif 1630 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1631 | abort(); 1632 | #endif 1633 | } 1634 | #endif 1635 | } 1636 | 1637 | void gfw_disable_line_smooth(void) 1638 | { 1639 | glDisable(GL_LINE_SMOOTH); 1640 | #ifdef GFW_CHECK_BACKEND_ERROR 1641 | if (glGetError() != GL_NO_ERROR) { 1642 | #ifdef GFW_PRINT_BACKEND_ERROR 1643 | printf("Error: failed to disable line smooth.\n"); 1644 | #endif 1645 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1646 | abort(); 1647 | #endif 1648 | } 1649 | #endif 1650 | } 1651 | 1652 | void gfw_set_blend_equation(enum gfw_blend_equation blend_equation_rgb, enum gfw_blend_equation blend_equation_alpha) 1653 | { 1654 | glBlendEquationSeparate(blend_equation_rgb, blend_equation_alpha); 1655 | #ifdef GFW_CHECK_BACKEND_ERROR 1656 | if (glGetError() != GL_NO_ERROR) { 1657 | #ifdef GFW_PRINT_BACKEND_ERROR 1658 | printf("Error: failed to set blend equation.\n"); 1659 | #endif 1660 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1661 | abort(); 1662 | #endif 1663 | } 1664 | #endif 1665 | } 1666 | 1667 | void gfw_set_blend_function(enum gfw_blend_factor blend_factor_source, enum gfw_blend_factor blend_factor_destination) 1668 | { 1669 | glBlendFunc(blend_factor_source, blend_factor_destination); 1670 | #ifdef GFW_CHECK_BACKEND_ERROR 1671 | if (glGetError() != GL_NO_ERROR) { 1672 | #ifdef GFW_PRINT_BACKEND_ERROR 1673 | printf("Error: failed to set blend function.\n"); 1674 | #endif 1675 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1676 | abort(); 1677 | #endif 1678 | } 1679 | #endif 1680 | } 1681 | 1682 | void gfw_set_blend_function_separate(enum gfw_blend_factor blend_factor_source_rgb, enum gfw_blend_factor blend_factor_destination_rgb, enum gfw_blend_factor blend_factor_source_alpha, enum gfw_blend_factor blend_factor_destination_alpha) 1683 | { 1684 | glBlendFuncSeparate(blend_factor_source_rgb, blend_factor_destination_rgb, blend_factor_source_alpha, blend_factor_destination_alpha); 1685 | #ifdef GFW_CHECK_BACKEND_ERROR 1686 | if (glGetError() != GL_NO_ERROR) { 1687 | #ifdef GFW_PRINT_BACKEND_ERROR 1688 | printf("Error: failed to set blend functions.\n"); 1689 | #endif 1690 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1691 | abort(); 1692 | #endif 1693 | } 1694 | #endif 1695 | } 1696 | 1697 | void gfw_set_blend_color(gfw_float_t r, gfw_float_t g, gfw_float_t b, gfw_float_t a) 1698 | { 1699 | glBlendColor(r, g, b, a); 1700 | #ifdef GFW_CHECK_BACKEND_ERROR 1701 | if (glGetError() != GL_NO_ERROR) { 1702 | #ifdef GFW_PRINT_BACKEND_ERROR 1703 | printf("Error: failed to set blending color.\n"); 1704 | #endif 1705 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1706 | abort(); 1707 | #endif 1708 | } 1709 | #endif 1710 | } 1711 | 1712 | void gfw_set_color_logic_operation(enum gfw_color_logic_operation color_logic_operation) 1713 | { 1714 | glLogicOp(color_logic_operation); 1715 | #ifdef GFW_CHECK_BACKEND_ERROR 1716 | if (glGetError() != GL_NO_ERROR) { 1717 | #ifdef GFW_PRINT_BACKEND_ERROR 1718 | printf("Error: failed to set color logic operation.\n"); 1719 | #endif 1720 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1721 | abort(); 1722 | #endif 1723 | } 1724 | #endif 1725 | } 1726 | 1727 | void gfw_set_cull_face_mode(enum gfw_cull_face_mode cull_face_mode) 1728 | { 1729 | glCullFace(cull_face_mode); 1730 | #ifdef GFW_CHECK_BACKEND_ERROR 1731 | if (glGetError() != GL_NO_ERROR) { 1732 | #ifdef GFW_PRINT_BACKEND_ERROR 1733 | printf("Error: failed to set cull face mode.\n"); 1734 | #endif 1735 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1736 | abort(); 1737 | #endif 1738 | } 1739 | #endif 1740 | } 1741 | 1742 | void gfw_set_front_face(enum gfw_cull_face_front front_face) 1743 | { 1744 | glFrontFace(front_face); 1745 | #ifdef GFW_CHECK_BACKEND_ERROR 1746 | if (glGetError() != GL_NO_ERROR) { 1747 | #ifdef GFW_PRINT_BACKEND_ERROR 1748 | printf("Error: failed to set face culling front face.\n"); 1749 | #endif 1750 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1751 | abort(); 1752 | #endif 1753 | } 1754 | #endif 1755 | } 1756 | 1757 | void gfw_set_depth_test_function(enum gfw_depth_test_function depth_test_function) 1758 | { 1759 | glDepthFunc(depth_test_function); 1760 | #ifdef GFW_CHECK_BACKEND_ERROR 1761 | if (glGetError() != GL_NO_ERROR) { 1762 | #ifdef GFW_PRINT_BACKEND_ERROR 1763 | printf("Error: failed to set depth function.\n"); 1764 | #endif 1765 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1766 | abort(); 1767 | #endif 1768 | } 1769 | #endif 1770 | } 1771 | 1772 | void gfw_set_depth_range(gfw_float_t near, gfw_float_t far) 1773 | { 1774 | glDepthRange(near, far); 1775 | #ifdef GFW_CHECK_BACKEND_ERROR 1776 | if (glGetError() != GL_NO_ERROR) { 1777 | #ifdef GFW_PRINT_BACKEND_ERROR 1778 | printf("Error: failed to set depth range.\n"); 1779 | #endif 1780 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1781 | abort(); 1782 | #endif 1783 | } 1784 | #endif 1785 | } 1786 | 1787 | void gfw_set_point_size(gfw_float_t size) 1788 | { 1789 | glPointSize(size); 1790 | #ifdef GFW_CHECK_BACKEND_ERROR 1791 | if (glGetError() != GL_NO_ERROR) { 1792 | #ifdef GFW_PRINT_BACKEND_ERROR 1793 | printf("Error: failed to set point size.\n"); 1794 | #endif 1795 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1796 | abort(); 1797 | #endif 1798 | } 1799 | #endif 1800 | } 1801 | 1802 | void gfw_set_line_width(gfw_float_t width) 1803 | { 1804 | glLineWidth(width); 1805 | #ifdef GFW_CHECK_BACKEND_ERROR 1806 | if (glGetError() != GL_NO_ERROR) { 1807 | #ifdef GFW_PRINT_BACKEND_ERROR 1808 | printf("Error: failed to set line width.\n"); 1809 | #endif 1810 | #ifdef GFW_ABORT_ON_BACKEND_ERROR 1811 | abort(); 1812 | #endif 1813 | } 1814 | #endif 1815 | } 1816 | -------------------------------------------------------------------------------- /gfw.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2018 Felipe Ferreira da Silva 3 | 4 | This software is provided 'as-is', without any express or implied warranty. In 5 | no event will the authors be held liable for any damages arising from the use of 6 | this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, including 9 | commercial applications, and to alter it and redistribute it freely, subject to 10 | the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not claim 13 | that you wrote the original software. If you use this software in a 14 | product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | */ 20 | 21 | #ifndef GFW_H 22 | #define GFW_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | /* Types */ 29 | typedef GLbyte gfw_byte_t; 30 | typedef GLubyte gfw_ubyte_t; 31 | typedef GLshort gfw_short_t; 32 | typedef GLushort gfw_ushort_t; 33 | typedef GLint gfw_int_t; 34 | typedef GLuint gfw_uint_t; 35 | typedef GLhalf gfw_half_float_t; 36 | typedef GLfloat gfw_float_t; 37 | typedef GLdouble gfw_double_t; 38 | 39 | /* Texture */ 40 | enum gfw_texture_wrap { 41 | GFW_TEXTURE_WRAP_REPEAT = GL_REPEAT, 42 | GFW_TEXTURE_WRAP_CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE, 43 | GFW_TEXTURE_WRAP_CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER, 44 | GFW_TEXTURE_WRAP_MIRRORED_REPEAT = GL_MIRRORED_REPEAT 45 | }; 46 | 47 | enum gfw_texture_filter { 48 | GFW_TEXTURE_FILTER_NEAREST = GL_NEAREST, 49 | GFW_TEXTURE_FILTER_LINEAR = GL_LINEAR 50 | }; 51 | 52 | enum gfw_texture_pixel_format { 53 | GFW_TEXTURE_PIXEL_FORMAT_RGB = GL_RGB, 54 | GFW_TEXTURE_PIXEL_FORMAT_RGBA = GL_RGBA, 55 | GFW_TEXTURE_PIXEL_FORMAT_PALETTE = GL_RED 56 | }; 57 | 58 | struct gfw_texture_descriptor { 59 | enum gfw_texture_pixel_format pixel_format; 60 | enum gfw_texture_wrap horizontal_wrap; 61 | enum gfw_texture_wrap vertical_wrap; 62 | enum gfw_texture_filter mag_filter; 63 | enum gfw_texture_filter min_filter; 64 | uint32_t width; 65 | uint32_t height; 66 | void *data; 67 | }; 68 | 69 | struct gfw_texture { 70 | gfw_uint_t texture_gl_id; 71 | enum gfw_texture_pixel_format pixel_format; 72 | uint32_t width; 73 | uint32_t height; 74 | }; 75 | 76 | /* Framebuffer */ 77 | struct gfw_framebuffer { 78 | gfw_uint_t framebuffer_gl_id; 79 | struct gfw_texture *texture; 80 | }; 81 | 82 | /* Vertex Data */ 83 | enum gfw_primitive { 84 | GFW_PRIMITIVE_TRIANGLES = GL_TRIANGLES, 85 | GFW_PRIMITIVE_LINES = GL_LINES, 86 | GFW_PRIMITIVE_LINE_STRIPS = GL_LINE_STRIP, 87 | GFW_PRIMITIVE_POINTS = GL_POINTS 88 | }; 89 | 90 | enum gfw_vertex_data_usage { 91 | GFW_VERTEX_DATA_USAGE_STATIC = GL_STATIC_DRAW, 92 | GFW_VERTEX_DATA_USAGE_DYNAMIC = GL_DYNAMIC_DRAW 93 | }; 94 | 95 | enum gfw_attribute_type { 96 | GFW_ATTRIBUTE_BYTE = GL_BYTE, 97 | GFW_ATTRIBUTE_UBYTE = GL_UNSIGNED_BYTE, 98 | GFW_ATTRIBUTE_SHORT = GL_SHORT, 99 | GFW_ATTRIBUTE_USHORT = GL_UNSIGNED_SHORT, 100 | GFW_ATTRIBUTE_INT = GL_INT, 101 | GFW_ATTRIBUTE_UINT = GL_UNSIGNED_INT, 102 | GFW_ATTRIBUTE_HALF_FLOAT = GL_HALF_FLOAT, 103 | GFW_ATTRIBUTE_FLOAT = GL_FLOAT, 104 | GFW_ATTRIBUTE_DOUBLE = GL_DOUBLE 105 | }; 106 | 107 | struct gfw_attribute { 108 | gfw_int_t location; 109 | enum gfw_attribute_type type; 110 | size_t count; 111 | bool normalize; 112 | size_t stride; 113 | size_t offset; 114 | }; 115 | 116 | struct gfw_vertex_data { 117 | gfw_uint_t vbo_gl_id; 118 | size_t range; 119 | size_t count; 120 | size_t size; 121 | uint8_t *buffer; 122 | }; 123 | 124 | /* Vertex State */ 125 | struct gfw_vertex_state { 126 | gfw_uint_t vao_gl_id; 127 | }; 128 | 129 | /* Shader */ 130 | struct gfw_shader { 131 | gfw_uint_t program_gl_id; 132 | }; 133 | 134 | /* Graphic states */ 135 | enum gfw_blend_factor { 136 | GFW_BLEND_FACTOR_ZERO = GL_ZERO, 137 | GFW_BLEND_FACTOR_ONE = GL_ONE, 138 | GFW_BLEND_FACTOR_SOURCE_COLOR = GL_SRC_COLOR, 139 | GFW_BLEND_FACTOR_ONE_MINUS_SOURCE_COLOR = GL_ONE_MINUS_SRC_ALPHA, 140 | GFW_BLEND_FACTOR_DESTINATION_COLOR = GL_DST_COLOR, 141 | GFW_BLEND_FACTOR_ONE_MINUS_DESTINATION_COLOR = GL_ONE_MINUS_DST_COLOR, 142 | GFW_BLEND_FACTOR_SOURCE_ALPHA = GL_SRC_ALPHA, 143 | GFW_BLEND_FACTOR_ONE_MINUS_SOURCE_ALPHA = GL_ONE_MINUS_SRC_ALPHA, 144 | GFW_BLEND_FACTOR_DESTINATION_ALPHA = GL_DST_ALPHA, 145 | GFW_BLEND_FACTOR_ONE_MINUS_DESTINATION_ALPHA = GL_ONE_MINUS_DST_ALPHA, 146 | GFW_BLEND_FACTOR_CONSTANT_COLOR = GL_CONSTANT_COLOR, 147 | GFW_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = GL_ONE_MINUS_CONSTANT_COLOR, 148 | GFW_BLEND_FACTOR_CONSTANT_ALPHA = GL_CONSTANT_ALPHA, 149 | GFW_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = GL_ONE_MINUS_CONSTANT_ALPHA, 150 | GFW_BLEND_FACTOR_SOURCE_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE, 151 | GFW_BLEND_FACTOR_SOURCE1_COLOR = GL_SRC1_COLOR, 152 | GFW_BLEND_FACTOR_ONE_MINUS_SOURCE1_COLOR = GL_ONE_MINUS_SRC1_COLOR, 153 | GFW_BLEND_FACTOR_SOURCE1_ALPHA = GL_SRC1_ALPHA, 154 | GFW_BLEND_FACTOR_ONE_MINUS_SOURCE1_ALPHA = GL_ONE_MINUS_SRC1_ALPHA 155 | }; 156 | 157 | enum gfw_blend_equation { 158 | GFW_BLEND_EQUATION_ADD = GL_FUNC_ADD, 159 | GFW_BLEND_EQUATION_SUBTRACT = GL_FUNC_SUBTRACT, 160 | GFW_BLEND_EQUATION_REVERSE_SUBTRACT = GL_FUNC_REVERSE_SUBTRACT, 161 | GFW_BLEND_EQUATION_MIN = GL_MIN, 162 | GFW_BLEND_EQUATION_MAX = GL_MAX 163 | }; 164 | 165 | enum gfw_color_logic_operation { 166 | GFW_COLOR_LOGIC_OPERATION_CLEAR = GL_CLEAR, 167 | GFW_COLOR_LOGIC_OPERATION_SET = GL_SET, 168 | GFW_COLOR_LOGIC_OPERATION_COPY = GL_COPY, 169 | GFW_COLOR_LOGIC_OPERATION_COPY_INVERTED = GL_COPY_INVERTED, 170 | GFW_COLOR_LOGIC_OPERATION_NO_OPERATION = GL_NOOP, 171 | GFW_COLOR_LOGIC_OPERATION_INVERT = GL_INVERT, 172 | GFW_COLOR_LOGIC_OPERATION_AND = GL_AND, 173 | GFW_COLOR_LOGIC_OPERATION_NOT_AND = GL_NAND, 174 | GFW_COLOR_LOGIC_OPERATION_OR = GL_OR, 175 | GFW_COLOR_LOGIC_OPERATION_NOT_OR = GL_NOR, 176 | GFW_COLOR_LOGIC_OPERATION_EXCLUSIVE_OR = GL_XOR, 177 | GFW_COLOR_LOGIC_OPERATION_EQUIVALENT = GL_EQUIV, 178 | GFW_COLOR_LOGIC_OPERATION_AND_REVERSE = GL_AND_REVERSE, 179 | GFW_COLOR_LOGIC_OPERATION_AND_INVERTED = GL_AND_INVERTED, 180 | GFW_COLOR_LOGIC_OPERATION_OR_REVERSE = GL_OR_REVERSE, 181 | GFW_COLOR_LOGIC_OPERATION_OR_INVERTED = GL_OR_INVERTED 182 | }; 183 | 184 | enum gfw_cull_face_mode { 185 | GFW_CULL_FACE_FRONT = GL_FRONT, 186 | GFW_CULL_FACE_BACK = GL_BACK, 187 | GFW_CULL_FACE_FRONT_AND_BACK = GL_FRONT_AND_BACK 188 | }; 189 | 190 | enum gfw_cull_face_front { 191 | GFW_CULL_FACE_FRONT_CW = GL_CW, 192 | GFW_CULL_FACE_FRONT_CCW = GL_CCW 193 | }; 194 | 195 | enum gfw_depth_test_function { 196 | GFW_DEPTH_TEST_FUNCTION_NEVER = GL_NEVER, 197 | GFW_DEPTH_TEST_FUNCTION_LESS = GL_LESS, 198 | GFW_DEPTH_TEST_FUNCTION_EQUAL = GL_EQUAL, 199 | GFW_DEPTH_TEST_FUNCTION_LESS_OR_EQUAL = GL_LEQUAL, 200 | GFW_DEPTH_TEST_FUNCTION_GREATER = GL_GREATER, 201 | GFW_DEPTH_TEST_FUNCTION_NOT_EQUAL = GL_NOTEQUAL, 202 | GFW_DEPTH_TEST_FUNCTION_GREATER_OR_EQUAL = GL_GEQUAL, 203 | GFW_DEPTH_TEST_FUNCTION_ALWAYS = GL_ALWAYS 204 | }; 205 | 206 | /* Texture */ 207 | void gfw_texture_unbind(void); 208 | void gfw_texture_bind(struct gfw_texture *texture); 209 | void gfw_texture_activate(uint32_t index); 210 | void gfw_texture_put_subimage(struct gfw_texture *texture, int32_t x, int32_t y, uint8_t *data, uint32_t width, uint32_t height); 211 | void gfw_free_texture(struct gfw_texture *texture); 212 | bool gfw_init_texture(struct gfw_texture *texture, struct gfw_texture_descriptor descriptor); 213 | 214 | /* Framebuffer */ 215 | void gfw_framebuffer_clear_color(float r, float g, float b, float a); 216 | void gfw_framebuffer_clear_depth(float depth); 217 | void gfw_framebuffer_clear(bool color, bool depth); 218 | void gfw_framebuffer_unbind(void); 219 | void gfw_framebuffer_bind(struct gfw_framebuffer *framebuffer); 220 | void gfw_free_framebuffer(struct gfw_framebuffer *framebuffer); 221 | bool gfw_init_framebuffer(struct gfw_framebuffer *framebuffer, struct gfw_texture *texture); 222 | 223 | /* Vertex data */ 224 | void gfw_vertex_data_clear(struct gfw_vertex_data *vertex_data); 225 | bool gfw_vertex_data_push(struct gfw_vertex_data *vertex_data, uint8_t *data, size_t size); 226 | void gfw_vertex_data_unmap(void); 227 | void gfw_vertex_data_map_range(struct gfw_vertex_data *vertex_data, bool read, bool write, size_t offset, size_t range); 228 | void gfw_vertex_data_map(struct gfw_vertex_data *vertex_data, bool read, bool write); 229 | void gfw_vertex_data_unbind(void); 230 | void gfw_vertex_data_bind(struct gfw_vertex_data *vertex_data); 231 | void gfw_free_vertex_data(struct gfw_vertex_data *vertex_data); 232 | bool gfw_init_vertex_data(struct gfw_vertex_data *vertex_data, size_t size, enum gfw_vertex_data_usage usage); 233 | 234 | /* Vertex state */ 235 | void gfw_vertex_state_unbind(void); 236 | void gfw_vertex_state_bind(struct gfw_vertex_state *vertex_state); 237 | void gfw_free_vertex_state(struct gfw_vertex_state *vertex_state); 238 | bool gfw_init_vertex_state(struct gfw_vertex_state *vertex_state); 239 | 240 | /* Shader */ 241 | void gfw_shader_set_uniform_mat4(gfw_int_t location, bool normalize, gfw_float_t *matrix); 242 | void gfw_shader_set_uniform_mat3(gfw_int_t location, bool normalize, gfw_float_t *matrix); 243 | void gfw_shader_set_uniform_float(gfw_int_t location, gfw_float_t f); 244 | void gfw_shader_set_uniform_floatv(gfw_int_t location, gfw_float_t *f, uint32_t count); 245 | void gfw_shader_set_uniform_int(gfw_int_t location, gfw_int_t i); 246 | void gfw_shader_set_uniform_intv(gfw_int_t location, gfw_int_t *i, uint32_t count); 247 | void gfw_shader_set_uniform_uint(gfw_int_t location, gfw_uint_t i); 248 | void gfw_shader_set_uniform_uintv(gfw_int_t location, gfw_uint_t *i, uint32_t count); 249 | gfw_int_t gfw_shader_get_uniform_location(struct gfw_shader *shader, char *name); 250 | gfw_int_t gfw_shader_get_attribute_location(struct gfw_shader *shader, char *name); 251 | void gfw_shader_draw_range(struct gfw_attribute *attributes, 252 | size_t attributes_count, 253 | enum gfw_primitive primitive, 254 | size_t first, 255 | size_t count); 256 | void gfw_shader_use(struct gfw_shader *shader); 257 | void gfw_free_shader(struct gfw_shader *shader); 258 | bool gfw_init_shader(struct gfw_shader *shader, char *vertex_source, char *geometry_source, char *fragment_source); 259 | 260 | /* Graphic state */ 261 | void gfw_set_viewport(int32_t x, int32_t y, uint32_t width, uint32_t height); 262 | void gfw_enable_blend(void); 263 | void gfw_disable_blend(void); 264 | void gfw_enable_clip_distance(uint32_t i); 265 | void gfw_disable_clip_distance(uint32_t i); 266 | void gfw_enable_color_logic_operation(void); 267 | void gfw_disable_color_logic_operation(void); 268 | void gfw_enable_cull_face(void); 269 | void gfw_disable_cull_face(void); 270 | void gfw_enable_depth_clamp(void); 271 | void gfw_disable_depth_clamp(void); 272 | void gfw_enable_depth_test(void); 273 | void gfw_disable_depth_test(void); 274 | void gfw_enable_dither(void); 275 | void gfw_disable_dither(void); 276 | void gfw_enable_line_smooth(void); 277 | void gfw_disable_line_smooth(void); 278 | void gfw_set_blend_equation(enum gfw_blend_equation blend_equation_rgb, enum gfw_blend_equation blend_equation_alpha); 279 | void gfw_set_blend_function(enum gfw_blend_factor blend_factor_source, enum gfw_blend_factor blend_factor_destination); 280 | void gfw_set_blend_function_separate(enum gfw_blend_factor blend_factor_source_rgb, enum gfw_blend_factor blend_factor_destination_rgb, enum gfw_blend_factor blend_factor_source_alpha, enum gfw_blend_factor blend_factor_destination_alpha); 281 | void gfw_set_blend_color(float r, float g, float b, float a); 282 | void gfw_set_color_logic_operation(enum gfw_color_logic_operation color_logic_operation); 283 | void gfw_set_cull_face_mode(enum gfw_cull_face_mode cull_face_mode); 284 | void gfw_set_front_face(enum gfw_cull_face_front cull_front_face); 285 | void gfw_set_depth_test_function(enum gfw_depth_test_function depth_test_function); 286 | void gfw_set_depth_range(float near, float far); 287 | void gfw_set_point_size(float size); 288 | void gfw_set_line_width(float width); 289 | 290 | #endif 291 | --------------------------------------------------------------------------------