aboutsummaryrefslogtreecommitdiffstats
path: root/test/pugl_gl3_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/pugl_gl3_test.c')
-rw-r--r--test/pugl_gl3_test.c398
1 files changed, 0 insertions, 398 deletions
diff --git a/test/pugl_gl3_test.c b/test/pugl_gl3_test.c
deleted file mode 100644
index 86fb11c..0000000
--- a/test/pugl_gl3_test.c
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- Copyright 2012-2019 David Robillard <http://drobilla.net>
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-
-/**
- @file pugl_gl3_test.c A simple test of OpenGL 3 with Pugl.
-
- This is an example of using OpenGL for pixel-perfect 2D drawing. It uses
- pixel coordinates for positions and sizes so that things work roughly like a
- typical 2D graphics API.
-
- The program draws a bunch of rectangles with borders, using instancing.
- Each rectangle has origin, size, and fill color attributes, which are shared
- for all four vertices. On each frame, a single buffer with all the
- rectangle data is sent to the GPU, and everything is drawn with a single
- draw call.
-
- This is not particularly realistic or optimal, but serves as a decent rough
- benchmark for how much simple geometry you can draw. The number of
- rectangles can be given on the command line. For reference, it begins to
- struggle to maintain 60 FPS on my machine (1950x + Vega64) with more than
- about 100000 rectangles.
-*/
-
-#define GL_SILENCE_DEPRECATION 1
-
-#include "demo_utils.h"
-#include "shader_utils.h"
-#include "test_utils.h"
-
-#include "glad/glad.h"
-
-#include "pugl/gl.h"
-#include "pugl/pugl.h"
-#include "pugl/pugl_gl.h"
-
-#include <math.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static const int defaultWidth = 512;
-static const int defaultHeight = 512;
-
-typedef struct
-{
- float pos[2];
- float size[2];
- float fillColor[4];
-} Rect;
-
-// clang-format off
-static const GLfloat rectVertices[] = {
- 0.0f, 0.0f, // TL
- 1.0f, 0.0f, // TR
- 0.0f, 1.0f, // BL
- 1.0f, 1.0f, // BR
-};
-// clang-format on
-
-static const GLuint rectIndices[4] = {0, 1, 2, 3};
-
-typedef struct
-{
- PuglTestOptions opts;
- PuglWorld* world;
- PuglView* view;
- size_t numRects;
- Rect* rects;
- Program drawRect;
- GLuint vao;
- GLuint vbo;
- GLuint instanceVbo;
- GLuint ibo;
- GLint u_projection;
- unsigned framesDrawn;
- int quit;
-} PuglTestApp;
-
-static void
-onConfigure(PuglView* view, double width, double height)
-{
- (void)view;
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- glViewport(0, 0, (int)width, (int)height);
-}
-
-static void
-onExpose(PuglView* view)
-{
- PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
- const PuglRect frame = puglGetFrame(view);
- const double time = puglGetTime(puglGetWorld(view));
-
- // Construct projection matrix for 2D window surface (in pixels)
- mat4 proj;
- mat4Ortho(proj,
- 0.0f,
- (float)frame.width,
- 0.0f,
- (float)frame.height,
- -1.0f,
- 1.0f);
-
- // Clear and bind everything that is the same for every rect
- glClear(GL_COLOR_BUFFER_BIT);
- glUseProgram(app->drawRect.program);
- glBindVertexArray(app->vao);
-
- // Set projection matrix uniform
- glUniformMatrix4fv(app->u_projection, 1, GL_FALSE, (const GLfloat*)&proj);
-
- for (size_t i = 0; i < app->numRects; ++i) {
- Rect* rect = &app->rects[i];
- const float normal = i / (float)app->numRects;
- const float offset[2] = {normal * 128.0f, normal * 128.0f};
-
- // Move rect around in an arbitrary way that looks cool
- rect->pos[0] =
- (float)(frame.width - rect->size[0] + offset[0]) *
- (sinf((float)time * rect->size[0] / 64.0f + normal) + 1.0f) /
- 2.0f;
- rect->pos[1] =
- (float)(frame.height - rect->size[1] + offset[1]) *
- (cosf((float)time * rect->size[1] / 64.0f + normal) + 1.0f) /
- 2.0f;
- }
-
- glBufferSubData(GL_ARRAY_BUFFER,
- 0,
- (GLsizeiptr)(app->numRects * sizeof(Rect)),
- app->rects);
-
- glDrawElementsInstanced(GL_TRIANGLE_STRIP,
- 4,
- GL_UNSIGNED_INT,
- NULL,
- (GLsizei)(app->numRects * 4));
-
- ++app->framesDrawn;
-}
-
-static PuglStatus
-onEvent(PuglView* view, const PuglEvent* event)
-{
- PuglTestApp* app = (PuglTestApp*)puglGetHandle(view);
-
- printEvent(event, "Event: ", app->opts.verbose);
-
- switch (event->type) {
- case PUGL_CONFIGURE:
- onConfigure(view, event->configure.width, event->configure.height);
- break;
- case PUGL_EXPOSE: onExpose(view); break;
- case PUGL_CLOSE: app->quit = 1; break;
- case PUGL_KEY_PRESS:
- if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) {
- app->quit = 1;
- }
- break;
- default: break;
- }
-
- return PUGL_SUCCESS;
-}
-
-static Rect*
-makeRects(const size_t numRects)
-{
- const float minSize = (float)defaultWidth / 64.0f;
- const float maxSize = (float)defaultWidth / 6.0f;
- const float boxAlpha = 0.2f;
-
- Rect* rects = (Rect*)calloc(numRects, sizeof(Rect));
- for (size_t i = 0; i < numRects; ++i) {
- const float s = (sinf((float)i) / 2.0f + 0.5f);
- const float c = (cosf((float)i) / 2.0f + 0.5f);
-
- rects[i].size[0] = minSize + s * maxSize;
- rects[i].size[1] = minSize + c * maxSize;
- rects[i].fillColor[1] = s / 2.0f + 0.25f;
- rects[i].fillColor[2] = c / 2.0f + 0.25f;
- rects[i].fillColor[3] = boxAlpha;
- }
-
- return rects;
-}
-
-static char*
-loadShader(const char* const path)
-{
- FILE* const file = fopen(path, "r");
- if (!file) {
- logError("Failed to open '%s'\n", path);
- return NULL;
- }
-
- fseek(file, 0, SEEK_END);
- const size_t fileSize = (size_t)ftell(file);
-
- fseek(file, 0, SEEK_SET);
- char* source = (char*)calloc(1, fileSize + 1u);
-
- fread(source, 1, fileSize, file);
- fclose(file);
-
- return source;
-}
-
-int
-main(int argc, char** argv)
-{
- PuglTestApp app;
- memset(&app, 0, sizeof(app));
-
- const PuglRect frame = {0, 0, defaultWidth, defaultHeight};
-
- // Parse command line options
- app.numRects = 1024;
- app.opts = puglParseTestOptions(&argc, &argv);
- if (app.opts.help) {
- puglPrintTestUsage("pugl_gl3_test", "[NUM_RECTS]");
- return 1;
- }
-
- // Parse number of rectangles argument, if given
- if (argc == 1) {
- char* endptr = NULL;
- app.numRects = (size_t)strtol(argv[0], &endptr, 10);
- if (endptr != argv[0] + strlen(argv[0])) {
- puglPrintTestUsage("pugl_gl3_test", "[NUM_RECTS]");
- return 1;
- }
- }
-
- // Create world, view, and rect data
- app.world = puglNewWorld();
- app.view = puglNewView(app.world);
- app.rects = makeRects(app.numRects);
-
- // Set up world and view
- puglSetClassName(app.world, "PuglGL3Test");
- puglSetFrame(app.view, frame);
- puglSetMinSize(app.view, defaultWidth / 4, defaultHeight / 4);
- puglSetAspectRatio(app.view, 1, 1, 16, 9);
- puglSetBackend(app.view, puglGlBackend());
- puglSetViewHint(app.view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE);
- puglSetViewHint(app.view, PUGL_USE_DEBUG_CONTEXT, app.opts.errorChecking);
- puglSetViewHint(app.view, PUGL_CONTEXT_VERSION_MAJOR, 3);
- puglSetViewHint(app.view, PUGL_CONTEXT_VERSION_MINOR, 3);
- puglSetViewHint(app.view, PUGL_RESIZABLE, app.opts.resizable);
- puglSetViewHint(app.view, PUGL_SAMPLES, app.opts.samples);
- puglSetViewHint(app.view, PUGL_DOUBLE_BUFFER, app.opts.doubleBuffer);
- puglSetViewHint(app.view, PUGL_SWAP_INTERVAL, app.opts.doubleBuffer);
- puglSetViewHint(app.view, PUGL_IGNORE_KEY_REPEAT, PUGL_TRUE);
- puglSetHandle(app.view, &app);
- puglSetEventFunc(app.view, onEvent);
-
- const PuglStatus st = puglCreateWindow(app.view, "Pugl OpenGL 3");
- if (st) {
- return logError("Failed to create window (%s)\n", puglStrerror(st));
- }
-
- // Enter context to set up GL stuff
- puglEnterContext(app.view, false);
-
- // Load GL functions via GLAD
- if (!gladLoadGLLoader((GLADloadproc)&puglGetProcAddress)) {
- logError("Failed to load GL\n");
- puglFreeView(app.view);
- puglFreeWorld(app.world);
- return 1;
- }
-
- // Load shader sources
- char* const vertexSource = loadShader("shaders/rect.vert");
- char* const fragmentSource = loadShader("shaders/rect.frag");
- if (!vertexSource || !fragmentSource) {
- logError("Failed to load shader sources\n");
- puglFreeView(app.view);
- puglFreeWorld(app.world);
- return 1;
- }
-
- // Compile rectangle shaders and program
- app.drawRect = compileProgram(vertexSource, fragmentSource);
- free(fragmentSource);
- free(vertexSource);
- if (!app.drawRect.program) {
- puglFreeView(app.view);
- puglFreeWorld(app.world);
- return 1;
- }
-
- // Get location of rectangle shader uniforms
- app.u_projection =
- glGetUniformLocation(app.drawRect.program, "u_projection");
-
- // Generate/bind a VAO to track state
- glGenVertexArrays(1, &app.vao);
- glBindVertexArray(app.vao);
-
- // Generate/bind a VBO to store vertex position data
- glGenBuffers(1, &app.vbo);
- glBindBuffer(GL_ARRAY_BUFFER, app.vbo);
- glBufferData(GL_ARRAY_BUFFER,
- sizeof(rectVertices),
- rectVertices,
- GL_STATIC_DRAW);
-
- // Attribute 0 is position, 2 floats from the VBO
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL);
-
- // Generate/bind a VBO to store instance attribute data
- glGenBuffers(1, &app.instanceVbo);
- glBindBuffer(GL_ARRAY_BUFFER, app.instanceVbo);
- glBufferData(GL_ARRAY_BUFFER,
- (GLsizeiptr)(app.numRects * sizeof(Rect)),
- app.rects,
- GL_STREAM_DRAW);
-
- // Attribute 1 is Rect::position
- glEnableVertexAttribArray(1);
- glVertexAttribDivisor(1, 4);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), NULL);
-
- // Attribute 2 is Rect::size
- glEnableVertexAttribArray(2);
- glVertexAttribDivisor(2, 4);
- glVertexAttribPointer(2,
- 2,
- GL_FLOAT,
- GL_FALSE,
- sizeof(Rect),
- (const void*)offsetof(Rect, size));
-
- // Attribute 3 is Rect::fillColor
- glEnableVertexAttribArray(3);
- glVertexAttribDivisor(3, 4);
- glVertexAttribPointer(3,
- 4,
- GL_FLOAT,
- GL_FALSE,
- sizeof(Rect),
- (const void*)offsetof(Rect, fillColor));
-
- // Set up the IBO to index into the VBO
- glGenBuffers(1, &app.ibo);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, app.ibo);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER,
- sizeof(rectIndices),
- rectIndices,
- GL_STATIC_DRAW);
-
- // Finally ready to go, leave GL context and show the window
- puglLeaveContext(app.view, false);
- puglShowWindow(app.view);
-
- // Grind away, drawing continuously
- PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)};
- while (!app.quit) {
- puglPostRedisplay(app.view);
- puglDispatchEvents(app.world);
- puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn);
- }
-
- // Delete GL stuff
- puglEnterContext(app.view, false);
- glDeleteBuffers(1, &app.ibo);
- glDeleteBuffers(1, &app.vbo);
- glDeleteBuffers(1, &app.instanceVbo);
- glDeleteVertexArrays(1, &app.vao);
- deleteProgram(app.drawRect);
- puglLeaveContext(app.view, false);
-
- // Tear down view and world
- puglFreeView(app.view);
- puglFreeWorld(app.world);
- return 0;
-}