Doyle Thai
46629a489a
Rendering using a non-default quad specifies normalised coordinates relative to the frame buffer size. Hence each render of these frames should origin from (0,0) any other value is invalid.
216 lines
7.0 KiB
C
216 lines
7.0 KiB
C
#include "Dengine/Platform.h"
|
|
#include "Dengine/OpenGL.h"
|
|
#include "Dengine/Renderer.h"
|
|
|
|
#define RENDER_BOUNDING_BOX FALSE
|
|
|
|
DebugRenderer debugRenderer = {0};
|
|
|
|
INTERNAL void updateBufferObject(Renderer *const renderer,
|
|
RenderQuad *const quads, const i32 numQuads)
|
|
{
|
|
// TODO(doyle): We assume that vbo and vao are assigned
|
|
const i32 numVertexesInQuad = 4;
|
|
renderer->numVertexesInVbo = numQuads * numVertexesInQuad;
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, numQuads * sizeof(RenderQuad), quads,
|
|
GL_STREAM_DRAW);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
|
|
#if 0
|
|
void renderer_backgroundTiles(Renderer *const renderer, const v2 tileSize,
|
|
World *const world, TexAtlas *const atlas,
|
|
Texture *const tex)
|
|
{
|
|
RenderQuad worldQuads[ARRAY_COUNT(world->tiles)] = {0};
|
|
i32 quadIndex = 0;
|
|
|
|
for (i32 i = 0; i < ARRAY_COUNT(world->tiles); i++)
|
|
{
|
|
Tile tile = world->tiles[i];
|
|
v2 tilePosInPixel = v2_scale(tile.pos, tileSize.x);
|
|
|
|
if ((tilePosInPixel.x < renderer->size.w && tilePosInPixel.x >= 0) &&
|
|
(tilePosInPixel.y < renderer->size.h && tilePosInPixel.y >= 0))
|
|
{
|
|
const v4 texRect = atlas->texRect[terraincoords_ground];
|
|
const v4 tileRect = getRect(tilePosInPixel, tileSize);
|
|
|
|
RenderQuad tileQuad =
|
|
renderer_createQuad(renderer, tileRect, texRect, tex);
|
|
worldQuads[quadIndex++] = tileQuad;
|
|
}
|
|
}
|
|
|
|
updateBufferObject(renderer, worldQuads, quadIndex);
|
|
renderer_object(renderer, V2(0.0f, 0.0f), renderer->size, 0.0f,
|
|
V3(0, 0, 0), tex);
|
|
}
|
|
#endif
|
|
|
|
void renderer_string(Renderer *const renderer, Font *const font,
|
|
const char *const string, v2 pos, f32 rotate,
|
|
v3 color)
|
|
{
|
|
i32 quadIndex = 0;
|
|
i32 strLen = common_strlen(string);
|
|
RenderQuad *stringQuads = CAST(RenderQuad *)calloc(strLen, sizeof(RenderQuad));
|
|
|
|
f32 baseline = pos.y;
|
|
for (i32 i = 0; i < strLen; i++)
|
|
{
|
|
// NOTE(doyle): Atlas packs fonts tightly, so offset the codepoint to
|
|
// its actual atlas index, i.e. we skip the first 31 glyphs
|
|
i32 codepoint = string[i];
|
|
i32 relativeIndex = codepoint - font->codepointRange.x;
|
|
CharMetrics charMetric = font->charMetrics[relativeIndex];
|
|
pos.y = baseline - charMetric.offset.y;
|
|
|
|
const v4 charRectOnScreen = getRect(
|
|
pos, V2(CAST(f32) font->maxSize.w, CAST(f32) font->maxSize.h));
|
|
|
|
pos.x += charMetric.advance;
|
|
|
|
/* Get texture out */
|
|
v4 charTexRect = font->atlas->texRect[relativeIndex];
|
|
renderer_flipTexCoord(&charTexRect, FALSE, TRUE);
|
|
|
|
RenderQuad charQuad = renderer_createQuad(renderer, charRectOnScreen,
|
|
charTexRect, font->tex);
|
|
stringQuads[quadIndex++] = charQuad;
|
|
}
|
|
|
|
// NOTE(doyle): We render at the renderer's size because we create quads
|
|
// relative to the window size, hence we also render at the origin since
|
|
// we're rendering a window sized buffer
|
|
updateBufferObject(renderer, stringQuads, quadIndex);
|
|
renderer_object(renderer, V2(0.0f, 0.0f), renderer->size, rotate, color,
|
|
font->tex);
|
|
free(stringQuads);
|
|
|
|
}
|
|
|
|
void renderer_debugString(Renderer *const renderer, Font *const font,
|
|
const char *const string)
|
|
{
|
|
/* Intialise debug object */
|
|
if (!debugRenderer.init)
|
|
{
|
|
debugRenderer.stringPos =
|
|
V2(0.0f, renderer->size.y -
|
|
(1.8f * asset_getVFontSpacing(font->metrics)));
|
|
debugRenderer.init = TRUE;
|
|
}
|
|
|
|
f32 rotate = 0;
|
|
v3 color = V3(0, 0, 0);
|
|
renderer_string(renderer, font, string, debugRenderer.stringPos, rotate,
|
|
color);
|
|
debugRenderer.stringPos.y -= (0.9f * asset_getVFontSpacing(font->metrics));
|
|
}
|
|
|
|
void renderer_entity(Renderer *renderer, Entity *entity, f32 dt, f32 rotate,
|
|
v3 color)
|
|
{
|
|
SpriteAnim *anim = &entity->anim[entity->currAnimIndex];
|
|
v4 texRect = anim->rect[anim->currRectIndex];
|
|
|
|
anim->currDuration -= dt;
|
|
if (anim->currDuration <= 0.0f)
|
|
{
|
|
anim->currRectIndex++;
|
|
anim->currRectIndex = anim->currRectIndex % anim->numRects;
|
|
texRect = anim->rect[anim->currRectIndex];
|
|
anim->currDuration = anim->duration;
|
|
}
|
|
|
|
if (entity->direction == direction_east)
|
|
{
|
|
// NOTE(doyle): Flip the x coordinates to flip the tex
|
|
renderer_flipTexCoord(&texRect, TRUE, FALSE);
|
|
}
|
|
|
|
RenderQuad entityQuad =
|
|
renderer_createDefaultQuad(renderer, texRect, entity->tex);
|
|
updateBufferObject(renderer, &entityQuad, 1);
|
|
renderer_object(renderer, entity->pos, entity->size, rotate, color,
|
|
entity->tex);
|
|
}
|
|
|
|
void renderer_object(Renderer *renderer, v2 pos, v2 size, f32 rotate, v3 color,
|
|
Texture *tex)
|
|
{
|
|
shader_use(renderer->shader);
|
|
mat4 transMatrix = mat4_translate(pos.x, pos.y, 0.0f);
|
|
mat4 rotateMatrix = mat4_rotate(rotate, 0.0f, 0.0f, 1.0f);
|
|
|
|
// NOTE(doyle): We draw everything as a unit square in OGL. Scale it to size
|
|
// TODO(doyle): We should have a notion of hitbox size and texture size
|
|
// we're going to render so we can draw textures that may be bigger than the
|
|
// entity, (slightly) but keep a consistent bounding box
|
|
mat4 scaleMatrix = mat4_scale(size.x, size.y, 1.0f);
|
|
|
|
mat4 model = mat4_mul(transMatrix, mat4_mul(rotateMatrix, scaleMatrix));
|
|
//mat4 model = mat4_mul(transMatrix, rotateMatrix);
|
|
shader_uniformSetMat4fv(renderer->shader, "model", model);
|
|
glCheckError();
|
|
|
|
// TODO(doyle): Unimplemented
|
|
// this->shader->uniformSetVec3f("spriteColor", color);
|
|
|
|
#if RENDER_BOUNDING_BOX
|
|
glBindVertexArray(renderer->vao);
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, renderer->numVertexesInVbo);
|
|
glBindVertexArray(0);
|
|
#endif
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
if (tex)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, tex->id);
|
|
shader_uniformSet1i(renderer->shader, "tex", 0);
|
|
}
|
|
|
|
glBindVertexArray(renderer->vao);
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, renderer->numVertexesInVbo);
|
|
glBindVertexArray(0);
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
glCheckError();
|
|
}
|
|
|
|
RenderQuad renderer_createQuad(Renderer *renderer, v4 quadRect, v4 texRect,
|
|
Texture *tex)
|
|
{
|
|
// NOTE(doyle): Draws a series of triangles (three-sided polygons) using
|
|
// vertices v0, v1, v2, then v2, v1, v3 (note the order)
|
|
RenderQuad result = {0};
|
|
|
|
v4 quadRectNdc = quadRect;
|
|
quadRectNdc.e[0] *= renderer->vertexNdcFactor.w;
|
|
quadRectNdc.e[1] *= renderer->vertexNdcFactor.h;
|
|
quadRectNdc.e[2] *= renderer->vertexNdcFactor.w;
|
|
quadRectNdc.e[3] *= renderer->vertexNdcFactor.h;
|
|
|
|
v2 texNdcFactor = V2(1.0f / tex->width, 1.0f / tex->height);
|
|
v4 texRectNdc = texRect;
|
|
texRectNdc.e[0] *= texNdcFactor.w;
|
|
texRectNdc.e[1] *= texNdcFactor.h;
|
|
texRectNdc.e[2] *= texNdcFactor.w;
|
|
texRectNdc.e[3] *= texNdcFactor.h;
|
|
|
|
result.vertex[0] = V4(quadRectNdc.x, quadRectNdc.y, texRectNdc.x,
|
|
texRectNdc.y); // Top left
|
|
result.vertex[1] = V4(quadRectNdc.x, quadRectNdc.w, texRectNdc.x,
|
|
texRectNdc.w); // Bottom left
|
|
result.vertex[2] = V4(quadRectNdc.z, quadRectNdc.y, texRectNdc.z,
|
|
texRectNdc.y); // Top right
|
|
result.vertex[3] = V4(quadRectNdc.z, quadRectNdc.w, texRectNdc.z,
|
|
texRectNdc.w); // Bottom right
|
|
return result;
|
|
}
|