Atlas - testgles2.c

Home / ext / SDL / test Lines: 1 | Size: 26191 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 3 4 This software is provided 'as-is', without any express or implied 5 warranty. In no event will the authors be held liable for any damages 6 arising from the use of this software. 7 8 Permission is granted to anyone to use this software for any purpose, 9 including commercial applications, and to alter it and redistribute it 10 freely. 11*/ 12 13#include <SDL3/SDL_test_common.h> 14#include <SDL3/SDL_main.h> 15 16#ifdef SDL_PLATFORM_EMSCRIPTEN 17#include <emscripten/emscripten.h> 18#endif 19 20#include <stdlib.h> 21 22#if defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_EMSCRIPTEN) || defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_HURD) 23#define HAVE_OPENGLES2 24#endif 25 26#ifdef HAVE_OPENGLES2 27 28#include <SDL3/SDL_opengles2.h> 29 30typedef struct GLES2_Context 31{ 32#define SDL_PROC(ret, func, params) ret (APIENTRY *func) params; 33#include "../src/render/opengles2/SDL_gles2funcs.h" 34#undef SDL_PROC 35} GLES2_Context; 36 37typedef struct shader_data 38{ 39 GLuint shader_program, shader_frag, shader_vert; 40 41 GLint attr_position; 42 GLint attr_color, attr_mvp; 43 44 int angle_x, angle_y, angle_z; 45 46 GLuint position_buffer; 47 GLuint color_buffer; 48} shader_data; 49 50typedef enum wait_state 51{ 52 WAIT_STATE_GO = 0, 53 WAIT_STATE_ENTER_SEM, 54 WAIT_STATE_WAITING_ON_SEM, 55} wait_state; 56 57typedef struct thread_data 58{ 59 SDL_Thread *thread; 60 SDL_Semaphore *suspend_sem; 61 SDL_AtomicInt suspended; 62 int done; 63 int index; 64} thread_data; 65 66static SDLTest_CommonState *state; 67static SDL_GLContext *context = NULL; 68static int depth = 16; 69static bool suspend_when_occluded; 70static GLES2_Context ctx; 71static shader_data *datas; 72 73static bool LoadContext(GLES2_Context *data) 74{ 75#ifdef SDL_VIDEO_DRIVER_UIKIT 76#define __SDL_NOGETPROCADDR__ 77#elif defined(SDL_VIDEO_DRIVER_ANDROID) 78#define __SDL_NOGETPROCADDR__ 79#endif 80 81#if defined __SDL_NOGETPROCADDR__ 82#define SDL_PROC(ret, func, params) data->func = func; 83#else 84#define SDL_PROC(ret, func, params) \ 85 do { \ 86 data->func = (ret (APIENTRY *) params)SDL_GL_GetProcAddress(#func); \ 87 if (!data->func) { \ 88 return SDL_SetError("Couldn't load GLES2 function %s: %s", #func, SDL_GetError()); \ 89 } \ 90 } while (0); 91#endif /* __SDL_NOGETPROCADDR__ */ 92 93#include "../src/render/opengles2/SDL_gles2funcs.h" 94#undef SDL_PROC 95 return true; 96} 97 98/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ 99static void 100quit(int rc) 101{ 102 int i; 103 104 SDL_free(datas); 105 if (context) { 106 for (i = 0; i < state->num_windows; i++) { 107 if (context[i]) { 108 SDL_GL_DestroyContext(context[i]); 109 } 110 } 111 112 SDL_free(context); 113 } 114 115 SDLTest_CommonQuit(state); 116 /* Let 'main()' return normally */ 117 if (rc != 0) { 118 exit(rc); 119 } 120} 121 122#define GL_CHECK(x) \ 123 x; \ 124 { \ 125 GLenum glError = ctx.glGetError(); \ 126 if (glError != GL_NO_ERROR) { \ 127 SDL_Log("glGetError() = %i (0x%.8x) at line %i", glError, glError, __LINE__); \ 128 quit(1); \ 129 } \ 130 } 131 132/** 133 * Simulates desktop's glRotatef. The matrix is returned in column-major 134 * order. 135 */ 136static void 137rotate_matrix(float angle, float x, float y, float z, float *r) 138{ 139 float radians, c, s, c1, u[3], length; 140 int i, j; 141 142 radians = (angle * SDL_PI_F) / 180.0f; 143 144 c = SDL_cosf(radians); 145 s = SDL_sinf(radians); 146 147 c1 = 1.0f - SDL_cosf(radians); 148 149 length = (float)SDL_sqrt(x * x + y * y + z * z); 150 151 u[0] = x / length; 152 u[1] = y / length; 153 u[2] = z / length; 154 155 for (i = 0; i < 16; i++) { 156 r[i] = 0.0; 157 } 158 159 r[15] = 1.0; 160 161 for (i = 0; i < 3; i++) { 162 r[i * 4 + (i + 1) % 3] = u[(i + 2) % 3] * s; 163 r[i * 4 + (i + 2) % 3] = -u[(i + 1) % 3] * s; 164 } 165 166 for (i = 0; i < 3; i++) { 167 for (j = 0; j < 3; j++) { 168 r[i * 4 + j] += c1 * u[i] * u[j] + (i == j ? c : 0.0f); 169 } 170 } 171} 172 173/** 174 * Simulates gluPerspectiveMatrix 175 */ 176static void 177perspective_matrix(float fovy, float aspect, float znear, float zfar, float *r) 178{ 179 int i; 180 float f; 181 182 f = 1.0f / SDL_tanf((fovy / 180.0f) * SDL_PI_F * 0.5f); 183 184 for (i = 0; i < 16; i++) { 185 r[i] = 0.0; 186 } 187 188 r[0] = f / aspect; 189 r[5] = f; 190 r[10] = (znear + zfar) / (znear - zfar); 191 r[11] = -1.0f; 192 r[14] = (2.0f * znear * zfar) / (znear - zfar); 193 r[15] = 0.0f; 194} 195 196/** 197 * Multiplies lhs by rhs and writes out to r. All matrices are 4x4 and column 198 * major. In-place multiplication is supported. 199 */ 200static void 201multiply_matrix(const float *lhs, const float *rhs, float *r) 202{ 203 int i, j, k; 204 float tmp[16]; 205 206 for (i = 0; i < 4; i++) { 207 for (j = 0; j < 4; j++) { 208 tmp[j * 4 + i] = 0.0; 209 210 for (k = 0; k < 4; k++) { 211 tmp[j * 4 + i] += lhs[k * 4 + i] * rhs[j * 4 + k]; 212 } 213 } 214 } 215 216 for (i = 0; i < 16; i++) { 217 r[i] = tmp[i]; 218 } 219} 220 221/** 222 * Create shader, load in source, compile, dump debug as necessary. 223 * 224 * shader: Pointer to return created shader ID. 225 * source: Passed-in shader source code. 226 * shader_type: Passed to GL, e.g. GL_VERTEX_SHADER. 227 */ 228static void 229process_shader(GLuint *shader, const char *source, GLint shader_type) 230{ 231 GLint status = GL_FALSE; 232 const char *shaders[1] = { NULL }; 233 char buffer[1024]; 234 GLsizei length = 0; 235 236 /* Create shader and load into GL. */ 237 *shader = GL_CHECK(ctx.glCreateShader(shader_type)); 238 239 shaders[0] = source; 240 241 GL_CHECK(ctx.glShaderSource(*shader, 1, shaders, NULL)); 242 243 /* Clean up shader source. */ 244 shaders[0] = NULL; 245 246 /* Try compiling the shader. */ 247 GL_CHECK(ctx.glCompileShader(*shader)); 248 GL_CHECK(ctx.glGetShaderiv(*shader, GL_COMPILE_STATUS, &status)); 249 250 /* Dump debug info (source and log) if compilation failed. */ 251 if (status != GL_TRUE) { 252 ctx.glGetShaderInfoLog(*shader, sizeof(buffer), &length, &buffer[0]); 253 buffer[length] = '\0'; 254 SDL_Log("Shader compilation failed: %s", buffer); 255 quit(-1); 256 } 257} 258 259static void 260link_program(struct shader_data *data) 261{ 262 GLint status = GL_FALSE; 263 char buffer[1024]; 264 GLsizei length = 0; 265 266 GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_vert)); 267 GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_frag)); 268 GL_CHECK(ctx.glLinkProgram(data->shader_program)); 269 GL_CHECK(ctx.glGetProgramiv(data->shader_program, GL_LINK_STATUS, &status)); 270 271 if (status != GL_TRUE) { 272 ctx.glGetProgramInfoLog(data->shader_program, sizeof(buffer), &length, &buffer[0]); 273 buffer[length] = '\0'; 274 SDL_Log("Program linking failed: %s", buffer); 275 quit(-1); 276 } 277} 278 279/* 3D data. Vertex range -0.5..0.5 in all axes. 280 * Z -0.5 is near, 0.5 is far. */ 281static const float g_vertices[] = { 282 /* Front face. */ 283 /* Bottom left */ 284 -0.5, 285 0.5, 286 -0.5, 287 0.5, 288 -0.5, 289 -0.5, 290 -0.5, 291 -0.5, 292 -0.5, 293 /* Top right */ 294 -0.5, 295 0.5, 296 -0.5, 297 0.5, 298 0.5, 299 -0.5, 300 0.5, 301 -0.5, 302 -0.5, 303 /* Left face */ 304 /* Bottom left */ 305 -0.5, 306 0.5, 307 0.5, 308 -0.5, 309 -0.5, 310 -0.5, 311 -0.5, 312 -0.5, 313 0.5, 314 /* Top right */ 315 -0.5, 316 0.5, 317 0.5, 318 -0.5, 319 0.5, 320 -0.5, 321 -0.5, 322 -0.5, 323 -0.5, 324 /* Top face */ 325 /* Bottom left */ 326 -0.5, 327 0.5, 328 0.5, 329 0.5, 330 0.5, 331 -0.5, 332 -0.5, 333 0.5, 334 -0.5, 335 /* Top right */ 336 -0.5, 337 0.5, 338 0.5, 339 0.5, 340 0.5, 341 0.5, 342 0.5, 343 0.5, 344 -0.5, 345 /* Right face */ 346 /* Bottom left */ 347 0.5, 348 0.5, 349 -0.5, 350 0.5, 351 -0.5, 352 0.5, 353 0.5, 354 -0.5, 355 -0.5, 356 /* Top right */ 357 0.5, 358 0.5, 359 -0.5, 360 0.5, 361 0.5, 362 0.5, 363 0.5, 364 -0.5, 365 0.5, 366 /* Back face */ 367 /* Bottom left */ 368 0.5, 369 0.5, 370 0.5, 371 -0.5, 372 -0.5, 373 0.5, 374 0.5, 375 -0.5, 376 0.5, 377 /* Top right */ 378 0.5, 379 0.5, 380 0.5, 381 -0.5, 382 0.5, 383 0.5, 384 -0.5, 385 -0.5, 386 0.5, 387 /* Bottom face */ 388 /* Bottom left */ 389 -0.5, 390 -0.5, 391 -0.5, 392 0.5, 393 -0.5, 394 0.5, 395 -0.5, 396 -0.5, 397 0.5, 398 /* Top right */ 399 -0.5, 400 -0.5, 401 -0.5, 402 0.5, 403 -0.5, 404 -0.5, 405 0.5, 406 -0.5, 407 0.5, 408}; 409 410static const float g_colors[] = { 411 /* Front face */ 412 /* Bottom left */ 413 1.0, 0.0, 0.0, /* red */ 414 0.0, 0.0, 1.0, /* blue */ 415 0.0, 1.0, 0.0, /* green */ 416 /* Top right */ 417 1.0, 0.0, 0.0, /* red */ 418 1.0, 1.0, 0.0, /* yellow */ 419 0.0, 0.0, 1.0, /* blue */ 420 /* Left face */ 421 /* Bottom left */ 422 1.0, 1.0, 1.0, /* white */ 423 0.0, 1.0, 0.0, /* green */ 424 0.0, 1.0, 1.0, /* cyan */ 425 /* Top right */ 426 1.0, 1.0, 1.0, /* white */ 427 1.0, 0.0, 0.0, /* red */ 428 0.0, 1.0, 0.0, /* green */ 429 /* Top face */ 430 /* Bottom left */ 431 1.0, 1.0, 1.0, /* white */ 432 1.0, 1.0, 0.0, /* yellow */ 433 1.0, 0.0, 0.0, /* red */ 434 /* Top right */ 435 1.0, 1.0, 1.0, /* white */ 436 0.0, 0.0, 0.0, /* black */ 437 1.0, 1.0, 0.0, /* yellow */ 438 /* Right face */ 439 /* Bottom left */ 440 1.0, 1.0, 0.0, /* yellow */ 441 1.0, 0.0, 1.0, /* magenta */ 442 0.0, 0.0, 1.0, /* blue */ 443 /* Top right */ 444 1.0, 1.0, 0.0, /* yellow */ 445 0.0, 0.0, 0.0, /* black */ 446 1.0, 0.0, 1.0, /* magenta */ 447 /* Back face */ 448 /* Bottom left */ 449 0.0, 0.0, 0.0, /* black */ 450 0.0, 1.0, 1.0, /* cyan */ 451 1.0, 0.0, 1.0, /* magenta */ 452 /* Top right */ 453 0.0, 0.0, 0.0, /* black */ 454 1.0, 1.0, 1.0, /* white */ 455 0.0, 1.0, 1.0, /* cyan */ 456 /* Bottom face */ 457 /* Bottom left */ 458 0.0, 1.0, 0.0, /* green */ 459 1.0, 0.0, 1.0, /* magenta */ 460 0.0, 1.0, 1.0, /* cyan */ 461 /* Top right */ 462 0.0, 1.0, 0.0, /* green */ 463 0.0, 0.0, 1.0, /* blue */ 464 1.0, 0.0, 1.0, /* magenta */ 465}; 466 467static const char *g_shader_vert_src = 468 " attribute vec4 av4position; " 469 " attribute vec3 av3color; " 470 " uniform mat4 mvp; " 471 " varying vec3 vv3color; " 472 " void main() { " 473 " vv3color = av3color; " 474 " gl_Position = mvp * av4position; " 475 " } "; 476 477static const char *g_shader_frag_src = 478 " precision lowp float; " 479 " varying vec3 vv3color; " 480 " void main() { " 481 " gl_FragColor = vec4(vv3color, 1.0); " 482 " } "; 483 484static void 485Render(unsigned int width, unsigned int height, shader_data *data) 486{ 487 float matrix_rotate[16], matrix_modelview[16], matrix_perspective[16], matrix_mvp[16]; 488 489 /* 490 * Do some rotation with Euler angles. It is not a fixed axis as 491 * quaterions would be, but the effect is cool. 492 */ 493 rotate_matrix((float)data->angle_x, 1.0f, 0.0f, 0.0f, matrix_modelview); 494 rotate_matrix((float)data->angle_y, 0.0f, 1.0f, 0.0f, matrix_rotate); 495 496 multiply_matrix(matrix_rotate, matrix_modelview, matrix_modelview); 497 498 rotate_matrix((float)data->angle_z, 0.0f, 1.0f, 0.0f, matrix_rotate); 499 500 multiply_matrix(matrix_rotate, matrix_modelview, matrix_modelview); 501 502 /* Pull the camera back from the cube */ 503 matrix_modelview[14] -= 2.5f; 504 505 perspective_matrix(45.0f, (float)width / height, 0.01f, 100.0f, matrix_perspective); 506 multiply_matrix(matrix_perspective, matrix_modelview, matrix_mvp); 507 508 GL_CHECK(ctx.glUniformMatrix4fv(data->attr_mvp, 1, GL_FALSE, matrix_mvp)); 509 510 data->angle_x += 3; 511 data->angle_y += 2; 512 data->angle_z += 1; 513 514 if (data->angle_x >= 360) { 515 data->angle_x -= 360; 516 } 517 if (data->angle_x < 0) { 518 data->angle_x += 360; 519 } 520 if (data->angle_y >= 360) { 521 data->angle_y -= 360; 522 } 523 if (data->angle_y < 0) { 524 data->angle_y += 360; 525 } 526 if (data->angle_z >= 360) { 527 data->angle_z -= 360; 528 } 529 if (data->angle_z < 0) { 530 data->angle_z += 360; 531 } 532 533 GL_CHECK(ctx.glViewport(0, 0, width, height)); 534 GL_CHECK(ctx.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)); 535 GL_CHECK(ctx.glDrawArrays(GL_TRIANGLES, 0, 36)); 536} 537 538static int done; 539static Uint32 frames; 540#ifndef SDL_PLATFORM_EMSCRIPTEN 541static thread_data *threads; 542#endif 543 544static void 545render_window(int index) 546{ 547 int w, h; 548 549 if (!state->windows[index]) { 550 return; 551 } 552 553 if (!SDL_GL_MakeCurrent(state->windows[index], context[index])) { 554 SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError()); 555 return; 556 } 557 558 SDL_GetWindowSizeInPixels(state->windows[index], &w, &h); 559 Render(w, h, &datas[index]); 560 SDL_GL_SwapWindow(state->windows[index]); 561 ++frames; 562} 563 564#ifndef SDL_PLATFORM_EMSCRIPTEN 565static int SDLCALL 566render_thread_fn(void *render_ctx) 567{ 568 thread_data *thread = render_ctx; 569 570 while (!done && !thread->done && state->windows[thread->index]) { 571 if (SDL_CompareAndSwapAtomicInt(&thread->suspended, WAIT_STATE_ENTER_SEM, WAIT_STATE_WAITING_ON_SEM)) { 572 SDL_WaitSemaphore(thread->suspend_sem); 573 } 574 render_window(thread->index); 575 } 576 577 SDL_GL_MakeCurrent(state->windows[thread->index], NULL); 578 return 0; 579} 580 581static thread_data *GetThreadDataForWindow(SDL_WindowID id) 582{ 583 int i; 584 SDL_Window *window = SDL_GetWindowFromID(id); 585 if (window) { 586 for (i = 0; i < state->num_windows; ++i) { 587 if (window == state->windows[i]) { 588 return &threads[i]; 589 } 590 } 591 } 592 return NULL; 593} 594 595static void 596loop_threaded(void) 597{ 598 SDL_Event event; 599 thread_data *tdata; 600 601 /* Wait for events */ 602 while (SDL_WaitEvent(&event) && !done) { 603 if (suspend_when_occluded && event.type == SDL_EVENT_WINDOW_OCCLUDED) { 604 tdata = GetThreadDataForWindow(event.window.windowID); 605 if (tdata) { 606 SDL_CompareAndSwapAtomicInt(&tdata->suspended, WAIT_STATE_GO, WAIT_STATE_ENTER_SEM); 607 } 608 } else if (suspend_when_occluded && event.type == SDL_EVENT_WINDOW_EXPOSED) { 609 tdata = GetThreadDataForWindow(event.window.windowID); 610 if (tdata) { 611 if (SDL_SetAtomicInt(&tdata->suspended, WAIT_STATE_GO) == WAIT_STATE_WAITING_ON_SEM) { 612 SDL_SignalSemaphore(tdata->suspend_sem); 613 } 614 } 615 } else if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) { 616 tdata = GetThreadDataForWindow(event.window.windowID); 617 if (tdata) { 618 /* Stop the render thread when the window is closed */ 619 tdata->done = 1; 620 if (tdata->thread) { 621 SDL_SetAtomicInt(&tdata->suspended, WAIT_STATE_GO); 622 SDL_SignalSemaphore(tdata->suspend_sem); 623 SDL_WaitThread(tdata->thread, NULL); 624 tdata->thread = NULL; 625 SDL_DestroySemaphore(tdata->suspend_sem); 626 } 627 break; 628 } 629 } 630 SDLTest_CommonEvent(state, &event, &done); 631 } 632} 633#endif 634 635static void 636loop(void) 637{ 638 SDL_Event event; 639 int i; 640 int active_windows = 0; 641 642 /* Check for events */ 643 while (SDL_PollEvent(&event) && !done) { 644 SDLTest_CommonEvent(state, &event, &done); 645 } 646 if (!done) { 647 for (i = 0; i < state->num_windows; ++i) { 648 if (state->windows[i] == NULL || 649 (suspend_when_occluded && (SDL_GetWindowFlags(state->windows[i]) & SDL_WINDOW_OCCLUDED))) { 650 continue; 651 } 652 ++active_windows; 653 render_window(i); 654 } 655 } 656#ifdef SDL_PLATFORM_EMSCRIPTEN 657 else { 658 emscripten_cancel_main_loop(); 659 } 660#endif 661 662 /* If all windows are occluded, throttle event polling to 15hz. */ 663 if (!done && !active_windows) { 664 SDL_DelayNS(SDL_NS_PER_SECOND / 15); 665 } 666} 667 668int main(int argc, char *argv[]) 669{ 670 int fsaa, accel, threaded; 671 int value; 672 int i; 673 const SDL_DisplayMode *mode; 674 Uint64 then, now; 675 shader_data *data; 676 677 /* Initialize parameters */ 678 fsaa = 0; 679 accel = 0; 680 threaded = 0; 681 682 /* Initialize test framework */ 683 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); 684 if (!state) { 685 return 1; 686 } 687 for (i = 1; i < argc;) { 688 int consumed; 689 690 consumed = SDLTest_CommonArg(state, i); 691 if (consumed == 0) { 692 if (SDL_strcasecmp(argv[i], "--fsaa") == 0) { 693 ++fsaa; 694 consumed = 1; 695 } else if (SDL_strcasecmp(argv[i], "--accel") == 0) { 696 ++accel; 697 consumed = 1; 698 } else if (SDL_strcasecmp(argv[i], "--threaded") == 0) { 699 ++threaded; 700 consumed = 1; 701 } else if(SDL_strcasecmp(argv[i], "--suspend-when-occluded") == 0) { 702 suspend_when_occluded = true; 703 consumed = 1; 704 } else if (SDL_strcasecmp(argv[i], "--zdepth") == 0) { 705 i++; 706 if (!argv[i]) { 707 consumed = -1; 708 } else { 709 char *endptr = NULL; 710 depth = (int)SDL_strtol(argv[i], &endptr, 0); 711 if (endptr != argv[i] && *endptr == '\0') { 712 consumed = 1; 713 } else { 714 consumed = -1; 715 } 716 } 717 } else { 718 consumed = -1; 719 } 720 } 721 if (consumed < 0) { 722 static const char *options[] = { "[--fsaa]", "[--accel]", "[--zdepth %d]", "[--threaded]", "[--suspend-when-occluded]",NULL }; 723 SDLTest_CommonLogUsage(state, argv[0], options); 724 quit(1); 725 } 726 i += consumed; 727 } 728 729 /* Set OpenGL parameters */ 730 state->window_flags |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; 731 state->gl_red_size = 5; 732 state->gl_green_size = 5; 733 state->gl_blue_size = 5; 734 state->gl_depth_size = depth; 735 state->gl_major_version = 2; 736 state->gl_minor_version = 0; 737 state->gl_profile_mask = SDL_GL_CONTEXT_PROFILE_ES; 738 739 if (fsaa) { 740 state->gl_multisamplebuffers = 1; 741 state->gl_multisamplesamples = fsaa; 742 } 743 if (accel) { 744 state->gl_accelerated = 1; 745 } 746 if (!SDLTest_CommonInit(state)) { 747 quit(2); 748 return 0; 749 } 750 751 context = (SDL_GLContext *)SDL_calloc(state->num_windows, sizeof(*context)); 752 if (!context) { 753 SDL_Log("Out of memory!"); 754 quit(2); 755 } 756 757 /* Create OpenGL ES contexts */ 758 for (i = 0; i < state->num_windows; i++) { 759 context[i] = SDL_GL_CreateContext(state->windows[i]); 760 if (!context[i]) { 761 SDL_Log("SDL_GL_CreateContext(): %s", SDL_GetError()); 762 quit(2); 763 } 764 } 765 766 /* Important: call this *after* creating the context */ 767 if (!LoadContext(&ctx)) { 768 SDL_Log("Could not load GLES2 functions"); 769 quit(2); 770 return 0; 771 } 772 773 SDL_GL_SetSwapInterval(state->render_vsync); 774 775 mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); 776 SDL_Log("Threaded : %s", threaded ? "yes" : "no"); 777 if (mode) { 778 SDL_Log("Screen bpp: %d", SDL_BITSPERPIXEL(mode->format)); 779 SDL_Log("%s", ""); 780 } 781 SDL_Log("Vendor : %s", ctx.glGetString(GL_VENDOR)); 782 SDL_Log("Renderer : %s", ctx.glGetString(GL_RENDERER)); 783 SDL_Log("Version : %s", ctx.glGetString(GL_VERSION)); 784 SDL_Log("Extensions : %s", ctx.glGetString(GL_EXTENSIONS)); 785 SDL_Log("%s", ""); 786 787 if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value)) { 788 SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d", 5, value); 789 } else { 790 SDL_Log("Failed to get SDL_GL_RED_SIZE: %s", 791 SDL_GetError()); 792 } 793 if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &value)) { 794 SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d", 5, value); 795 } else { 796 SDL_Log("Failed to get SDL_GL_GREEN_SIZE: %s", 797 SDL_GetError()); 798 } 799 if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &value)) { 800 SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d", 5, value); 801 } else { 802 SDL_Log("Failed to get SDL_GL_BLUE_SIZE: %s", 803 SDL_GetError()); 804 } 805 if (SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &value)) { 806 SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d", depth, value); 807 } else { 808 SDL_Log("Failed to get SDL_GL_DEPTH_SIZE: %s", 809 SDL_GetError()); 810 } 811 if (fsaa) { 812 if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &value)) { 813 SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d", value); 814 } else { 815 SDL_Log("Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s", 816 SDL_GetError()); 817 } 818 if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &value)) { 819 SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d", fsaa, 820 value); 821 } else { 822 SDL_Log("Failed to get SDL_GL_MULTISAMPLESAMPLES: %s", 823 SDL_GetError()); 824 } 825 } 826 if (accel) { 827 if (SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &value)) { 828 SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested 1, got %d", value); 829 } else { 830 SDL_Log("Failed to get SDL_GL_ACCELERATED_VISUAL: %s", 831 SDL_GetError()); 832 } 833 } 834 835 datas = (shader_data *)SDL_calloc(state->num_windows, sizeof(shader_data)); 836 837 /* Set rendering settings for each context */ 838 for (i = 0; i < state->num_windows; ++i) { 839 840 int w, h; 841 if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) { 842 SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError()); 843 844 /* Continue for next window */ 845 continue; 846 } 847 SDL_GetWindowSizeInPixels(state->windows[i], &w, &h); 848 ctx.glViewport(0, 0, w, h); 849 850 data = &datas[i]; 851 data->angle_x = 0; 852 data->angle_y = 0; 853 data->angle_z = 0; 854 855 /* Shader Initialization */ 856 process_shader(&data->shader_vert, g_shader_vert_src, GL_VERTEX_SHADER); 857 process_shader(&data->shader_frag, g_shader_frag_src, GL_FRAGMENT_SHADER); 858 859 /* Create shader_program (ready to attach shaders) */ 860 data->shader_program = GL_CHECK(ctx.glCreateProgram()); 861 862 /* Attach shaders and link shader_program */ 863 link_program(data); 864 865 /* Get attribute locations of non-fixed attributes like color and texture coordinates. */ 866 data->attr_position = GL_CHECK(ctx.glGetAttribLocation(data->shader_program, "av4position")); 867 data->attr_color = GL_CHECK(ctx.glGetAttribLocation(data->shader_program, "av3color")); 868 869 /* Get uniform locations */ 870 data->attr_mvp = GL_CHECK(ctx.glGetUniformLocation(data->shader_program, "mvp")); 871 872 GL_CHECK(ctx.glUseProgram(data->shader_program)); 873 874 /* Enable attributes for position, color and texture coordinates etc. */ 875 GL_CHECK(ctx.glEnableVertexAttribArray(data->attr_position)); 876 GL_CHECK(ctx.glEnableVertexAttribArray(data->attr_color)); 877 878 /* Populate attributes for position, color and texture coordinates etc. */ 879 880 GL_CHECK(ctx.glGenBuffers(1, &data->position_buffer)); 881 GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, data->position_buffer)); 882 GL_CHECK(ctx.glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices), g_vertices, GL_STATIC_DRAW)); 883 GL_CHECK(ctx.glVertexAttribPointer(data->attr_position, 3, GL_FLOAT, GL_FALSE, 0, NULL)); 884 GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, 0)); 885 886 GL_CHECK(ctx.glGenBuffers(1, &data->color_buffer)); 887 GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, data->color_buffer)); 888 GL_CHECK(ctx.glBufferData(GL_ARRAY_BUFFER, sizeof(g_colors), g_colors, GL_STATIC_DRAW)); 889 GL_CHECK(ctx.glVertexAttribPointer(data->attr_color, 3, GL_FLOAT, GL_FALSE, 0, NULL)); 890 GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, 0)); 891 892 GL_CHECK(ctx.glEnable(GL_CULL_FACE)); 893 GL_CHECK(ctx.glEnable(GL_DEPTH_TEST)); 894 895 SDL_GL_MakeCurrent(state->windows[i], NULL); 896 } 897 898 /* Main render loop */ 899 frames = 0; 900 then = SDL_GetTicks(); 901 done = 0; 902 903#ifdef SDL_PLATFORM_EMSCRIPTEN 904 emscripten_set_main_loop(loop, 0, 1); 905#else 906 if (threaded) { 907 threads = (thread_data *)SDL_calloc(state->num_windows, sizeof(thread_data)); 908 909 /* Start a render thread for each window */ 910 for (i = 0; i < state->num_windows; ++i) { 911 threads[i].index = i; 912 SDL_SetAtomicInt(&threads[i].suspended, 0); 913 threads[i].suspend_sem = SDL_CreateSemaphore(0); 914 threads[i].thread = SDL_CreateThread(render_thread_fn, "RenderThread", &threads[i]); 915 } 916 917 while (!done) { 918 loop_threaded(); 919 } 920 921 /* Join the remaining render threads (if any) */ 922 for (i = 0; i < state->num_windows; ++i) { 923 threads[i].done = 1; 924 if (threads[i].thread) { 925 SDL_WaitThread(threads[i].thread, NULL); 926 } 927 } 928 SDL_free(threads); 929 } else { 930 while (!done) { 931 loop(); 932 } 933 } 934#endif 935 936 /* Print out some timing information */ 937 now = SDL_GetTicks(); 938 if (now > then) { 939 SDL_Log("%2.2f frames per second", 940 ((double)frames * 1000) / (now - then)); 941 } 942#ifndef SDL_PLATFORM_ANDROID 943 quit(0); 944#endif 945 return 0; 946} 947 948#else /* HAVE_OPENGLES2 */ 949 950int main(int argc, char *argv[]) 951{ 952 SDL_Log("No OpenGL ES support on this system"); 953 return 1; 954} 955 956#endif /* HAVE_OPENGLES2 */ 957
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.