#include "render.h" static RenderObjects_Char createCharObjects(Arena *arena, size_t count) { RenderObjects_Char result = {0}; result.count = count; result.begin.buf = PushFullList(arena, Vec2List, count); result.glyph.buf = PushFullList(arena, IntList, count); result.fontSize.buf = PushFullList(arena, FloatList, count); result.color.buf = PushFullList(arena, Vec4List, count); glGenVertexArrays(1, &result.vao); glGenBuffers(1, &result.begin.bufId); glGenBuffers(1, &result.glyph.bufId); glGenBuffers(1, &result.fontSize.bufId); glGenBuffers(1, &result.color.bufId); glBindVertexArray(result.vao); int32 bufItemSize = sizeof(result.begin.buf.data[0]); glBindBuffer(GL_ARRAY_BUFFER, result.begin.bufId); glBufferData(GL_ARRAY_BUFFER, result.begin.buf.length * bufItemSize, 0, GL_STREAM_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, bufItemSize, NULL); glVertexAttribDivisor(0, 1); glEnableVertexAttribArray(0); bufItemSize = sizeof(result.glyph.buf.data[0]); glBindBuffer(GL_ARRAY_BUFFER, result.glyph.bufId); glBufferData(GL_ARRAY_BUFFER, result.glyph.buf.length * bufItemSize, 0, GL_STREAM_DRAW); glVertexAttribIPointer(1, 1, GL_INT, bufItemSize, NULL); glVertexAttribDivisor(1, 1); glEnableVertexAttribArray(1); bufItemSize = sizeof(result.fontSize.buf.data[0]); glBindBuffer(GL_ARRAY_BUFFER, result.fontSize.bufId); glBufferData(GL_ARRAY_BUFFER, result.fontSize.buf.length * bufItemSize, 0, GL_STREAM_DRAW); glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, bufItemSize, NULL); glVertexAttribDivisor(2, 1); glEnableVertexAttribArray(2); bufItemSize = sizeof(result.color.buf.data[0]); glBindBuffer(GL_ARRAY_BUFFER, result.color.bufId); glBufferData(GL_ARRAY_BUFFER, result.color.buf.length * bufItemSize, 0, GL_STREAM_DRAW); glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, bufItemSize, NULL); glVertexAttribDivisor(3, 1); glEnableVertexAttribArray(3); return result; } static RenderObjects_Rect createRectangleObjects(Arena *arena, size_t count) { RenderObjects_Rect result = {0}; result.count = count; result.p0.buf = PushFullList(arena, Vec2List, count); result.p1.buf = PushFullList(arena, Vec2List, count); result.color.buf = PushFullList(arena, Vec4List, count); result.borderRadius.buf = PushFullList(arena, FloatList, count); result.borderThickness.buf = PushFullList(arena, FloatList, count); result.borderColor.buf = PushFullList(arena, Vec4List, count); result.edgeSoftness.buf = PushFullList(arena, FloatList, count); glGenVertexArrays(1, &result.vao); glGenBuffers(1, &result.p0.bufId); glGenBuffers(1, &result.p1.bufId); glGenBuffers(1, &result.color.bufId); glGenBuffers(1, &result.borderRadius.bufId); glGenBuffers(1, &result.borderThickness.bufId); glGenBuffers(1, &result.borderColor.bufId); glGenBuffers(1, &result.edgeSoftness.bufId); glBindVertexArray(result.vao); int32 bufItemSize = sizeof(result.p0.buf.data[0]); glBindBuffer(GL_ARRAY_BUFFER, result.p0.bufId); glBufferData(GL_ARRAY_BUFFER, result.p0.buf.length * bufItemSize, 0, GL_STREAM_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, bufItemSize, NULL); glVertexAttribDivisor(0, 1); glEnableVertexAttribArray(0); bufItemSize = sizeof(result.p1.buf.data[0]); glBindBuffer(GL_ARRAY_BUFFER, result.p1.bufId); glBufferData(GL_ARRAY_BUFFER, result.p1.buf.length * bufItemSize, 0, GL_STREAM_DRAW); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, bufItemSize, NULL); glVertexAttribDivisor(1, 1); glEnableVertexAttribArray(1); bufItemSize = sizeof(result.color.buf.data[0]); glBindBuffer(GL_ARRAY_BUFFER, result.color.bufId); glBufferData(GL_ARRAY_BUFFER, result.color.buf.length * bufItemSize, 0, GL_STREAM_DRAW); glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, bufItemSize, NULL); glVertexAttribDivisor(2, 1); glEnableVertexAttribArray(2); bufItemSize = sizeof(result.borderRadius.buf.data[0]); glBindBuffer(GL_ARRAY_BUFFER, result.borderRadius.bufId); glBufferData(GL_ARRAY_BUFFER, result.borderRadius.buf.length * bufItemSize, 0, GL_STREAM_DRAW); glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, bufItemSize, NULL); glVertexAttribDivisor(3, 1); glEnableVertexAttribArray(3); bufItemSize = sizeof(result.borderThickness.buf.data[0]); glBindBuffer(GL_ARRAY_BUFFER, result.borderThickness.bufId); glBufferData(GL_ARRAY_BUFFER, result.borderThickness.buf.length * bufItemSize, 0, GL_STREAM_DRAW); glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, bufItemSize, NULL); glVertexAttribDivisor(4, 1); glEnableVertexAttribArray(4); bufItemSize = sizeof(result.borderColor.buf.data[0]); glBindBuffer(GL_ARRAY_BUFFER, result.borderColor.bufId); glBufferData(GL_ARRAY_BUFFER, result.borderColor.buf.length * bufItemSize, 0, GL_STREAM_DRAW); glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, bufItemSize, NULL); glVertexAttribDivisor(5, 1); glEnableVertexAttribArray(5); bufItemSize = sizeof(result.edgeSoftness.buf.data[0]); glBindBuffer(GL_ARRAY_BUFFER, result.edgeSoftness.bufId); glBufferData(GL_ARRAY_BUFFER, result.edgeSoftness.buf.length * bufItemSize, 0, GL_STREAM_DRAW); glVertexAttribPointer(6, 1, GL_FLOAT, GL_FALSE, bufItemSize, NULL); glVertexAttribDivisor(6, 1); glEnableVertexAttribArray(6); return result; } #define GL_UpdateBuffer(buffer) \ glBindBuffer(GL_ARRAY_BUFFER, (buffer).bufId);\ glBufferSubData(GL_ARRAY_BUFFER, 0, (buffer).buf.length * sizeof((buffer).underlying), (buffer).buf.data); static void updateCharObjectBuffers(Renderer *r) { glBindVertexArray(r->chars.vao); GL_UpdateBuffer(r->chars.begin); GL_UpdateBuffer(r->chars.glyph); GL_UpdateBuffer(r->chars.fontSize); GL_UpdateBuffer(r->chars.color); } static void updateRectangleObjectBuffers(Renderer *r) { glBindVertexArray(r->rects.vao); GL_UpdateBuffer(r->rects.p0); GL_UpdateBuffer(r->rects.p1); GL_UpdateBuffer(r->rects.color); GL_UpdateBuffer(r->rects.borderRadius); GL_UpdateBuffer(r->rects.borderThickness); GL_UpdateBuffer(r->rects.borderColor); GL_UpdateBuffer(r->rects.edgeSoftness); } Renderer createRenderer(Arena *arena, Scene *scene, Camera *cam, int32 light) { return (Renderer){ .scene = scene, .light = light, .camera = cam, .rects = createRectangleObjects(arena, 1024), .chars = createCharObjects(arena, 10000), }; } void renderBegin(Renderer *r) { r->rects.p0.buf.length = 0; r->rects.p1.buf.length = 0; r->rects.color.buf.length = 0; r->rects.borderRadius.buf.length = 0; r->rects.borderThickness.buf.length = 0; r->rects.borderColor.buf.length = 0; r->rects.edgeSoftness.buf.length = 0; r->chars.begin.buf.length = 0; r->chars.glyph.buf.length = 0; r->chars.fontSize.buf.length = 0; r->chars.color.buf.length = 0; r->sceneWidth = 0; r->sceneHeight = 0; r->sceneX = 0; r->sceneY = 0; } #define CHECK() do{ GLenum e=glGetError(); if(e) printf("GL err 0x%x at %s:%d\n",e,__FILE__,__LINE__); }while(0) void renderEnd(Renderer *r) { glBindFramebuffer(GL_FRAMEBUFFER, 0); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glEnable(GL_DEPTH_TEST); // --- 3D Scene --- glViewport(r->sceneX, r->height - r->sceneY - r->sceneHeight, r->sceneWidth, r->sceneHeight); cameraSetAspect(r->camera, r->sceneWidth, r->sceneHeight); glUseProgram(r->phongShader->progId); setUniformMat4fv(r->phongShader, "projection", &r->camera->proj); setUniformMat4fv(r->phongShader, "view", &r->camera->view); SceneGraphNode *lightGraphNode = getSceneGraphNode(r->scene, r->light); setUniform3fv(r->phongShader, "light_pos", &lightGraphNode->translation); setUniform3fv(r->phongShader, "camera", &r->camera->pos); //glBindVertexArray(r->cubeMesh->vao); int model_uniform = getUniformLocation(r->phongShader, "model"); int solid_color_uniform = getUniformLocation(r->phongShader, "solid_color"); for (EachIn(r->scene->entities, i)) { Entity *entity = &r->scene->entities.data[i]; if (entity->flags & EntityFlags_Render && entity->flags & EntityFlags_Visible) { setUniform4fvByLoc(solid_color_uniform, &entity->color); setUniformMat4fvByLoc(model_uniform, &getSceneGraphNode(r->scene, entity->graphNodeHandle)->world); glBindTexture(GL_TEXTURE_2D, entity->tex->tex_id); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)entity->mesh->num_indices); entity->flags &= ~EntityFlags_Render; } } // --- UI overlay --- glViewport(0, 0, r->width, r->height); glUseProgram(r->solidShader->progId); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); Matrix ortho = MatrixOrtho(0.0, r->width, r->height, 0.0, -1.0, 1.0); // - 1. Rects updateRectangleObjectBuffers(r); setUniformMat4fv(r->solidShader, "projection", &ortho); glBindVertexArray(r->rects.vao); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, r->rects.p0.buf.length); // - 2. Text updateCharObjectBuffers(r); glUseProgram(r->textShader->progId); setUniformMat4fv(r->textShader, "projection", &ortho); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, r->activeFont->texId); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_BUFFER, r->activeFont->glyphTableTexId); setUniform1i(r->textShader, "glyph_table", 1); glBindVertexArray(r->chars.vao); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, r->chars.begin.buf.length); glDisable(GL_BLEND); glActiveTexture(GL_TEXTURE0); } void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, Vec4 color, real32 borderRadius, real32 borderThickness, Vec4 borderColor) { x = roundf(x); y = roundf(y); width = roundf(width); height = roundf(height); ListAppend(r->rects.p0.buf, ((Vec2){ x, y })); ListAppend(r->rects.p1.buf, ((Vec2){ x + width, y + height })); ListAppend(r->rects.color.buf, color); ListAppend(r->rects.borderRadius.buf, borderRadius); ListAppend(r->rects.borderThickness.buf, borderThickness); ListAppend(r->rects.borderColor.buf, borderColor); ListAppend(r->rects.edgeSoftness.buf, 0.15f); } void rendererPlaceString(Renderer *r, string s, real32 x, real32 y, Vec4 color, real32 fontSize) { real32 ratio = fontSize / r->activeFont->lineHeight; real32 charWidth = ratio * r->activeFont->charWidth; for (int i = 0; i < s.length; i++) { ListAppend(r->chars.begin.buf, ((Vec2){ .x=x + i*charWidth, .y=y })); ListAppend(r->chars.glyph.buf, s.str[i] - 32); ListAppend(r->chars.fontSize.buf, ratio); ListAppend(r->chars.color.buf, (color)); } }