Fix rotation on render, change rendering code
Premultiply transformation matrix onto vertices before sending onto GPU to preserve transformation properties of entities before being batched into a general group. This removes the model matrix from the shader pipeline- instead in rendering code we deal in world space (which works out to be more intuitive). Only in the last step in GLSL we convert back to normalised coordinates.
This commit is contained in:
parent
88ce511f2b
commit
3894d33485
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
in vec2 texCoord;
|
|
||||||
|
|
||||||
|
in vec2 texCoord;
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
layout (location = 0) in vec4 data; // (vec2)pos, (vec2)texCoord
|
layout(location = 0) in vec4 data; // (vec2)pos, (vec2)texCoord
|
||||||
|
|
||||||
out vec2 texCoord;
|
|
||||||
|
|
||||||
uniform mat4 model;
|
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
|
out vec2 texCoord;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = projection * model * vec4(data.xy, 0.0f, 1.0f);
|
gl_Position = projection * vec4(data.xy, 0.0f, 1.0f);
|
||||||
texCoord = data.zw;
|
texCoord = data.zw;
|
||||||
}
|
}
|
||||||
|
245
src/Renderer.c
245
src/Renderer.c
@ -8,9 +8,9 @@
|
|||||||
#include "Dengine/Shader.h"
|
#include "Dengine/Shader.h"
|
||||||
#include "Dengine/Texture.h"
|
#include "Dengine/Texture.h"
|
||||||
|
|
||||||
#define RENDER_BOUNDING_BOX FALSE
|
#define RENDER_BOUNDING_BOX TRUE
|
||||||
|
|
||||||
INTERNAL void addToRenderGroup(Renderer *renderer, Texture *texture,
|
INTERNAL void addVertexToRenderGroup(Renderer *renderer, Texture *texture,
|
||||||
Vertex *vertexList, i32 numVertexes)
|
Vertex *vertexList, i32 numVertexes)
|
||||||
{
|
{
|
||||||
/* Find vacant/matching render group */
|
/* Find vacant/matching render group */
|
||||||
@ -57,6 +57,37 @@ INTERNAL void addToRenderGroup(Renderer *renderer, Texture *texture,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INTERNAL inline void addRenderQuadToRenderGroup(Renderer *renderer,
|
||||||
|
RenderQuad_ quad,
|
||||||
|
RenderTex renderTex)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
NOTE(doyle): Entity rendering is always done in two pairs of
|
||||||
|
triangles, i.e. quad. To batch render quads as a triangle strip, we
|
||||||
|
need to create zero-area triangles which OGL will omit from
|
||||||
|
rendering. Render groups are initialised with 1 degenerate vertex and
|
||||||
|
then the first two vertexes sent to the render group are the same to
|
||||||
|
form 1 zero-area triangle strip.
|
||||||
|
|
||||||
|
A degenerate vertex has to be copied from the last vertex in the
|
||||||
|
rendering quad, to repeat this process as more entities are
|
||||||
|
renderered.
|
||||||
|
|
||||||
|
Alternative implementation is recognising if the rendered
|
||||||
|
entity is the first in its render group, then we don't need to init
|
||||||
|
a degenerate vertex, and only at the end of its vertex list. But on
|
||||||
|
subsequent renders, we need a degenerate vertex at the front to
|
||||||
|
create the zero-area triangle strip.
|
||||||
|
|
||||||
|
The first has been chosen for simplicity of code, at the cost of
|
||||||
|
1 degenerate vertex at the start of each render group.
|
||||||
|
*/
|
||||||
|
Vertex vertexList[6] = {quad.vertex[0], quad.vertex[0], quad.vertex[1],
|
||||||
|
quad.vertex[2], quad.vertex[3], quad.vertex[3]};
|
||||||
|
addVertexToRenderGroup(renderer, renderTex.tex, vertexList,
|
||||||
|
ARRAY_COUNT(vertexList));
|
||||||
|
};
|
||||||
|
|
||||||
INTERNAL inline void flipTexCoord(v4 *texCoords, b32 flipX, b32 flipY)
|
INTERNAL inline void flipTexCoord(v4 *texCoords, b32 flipX, b32 flipY)
|
||||||
{
|
{
|
||||||
if (flipX)
|
if (flipX)
|
||||||
@ -92,7 +123,8 @@ INTERNAL void bufferRenderGroupToGL(Renderer *renderer, RenderGroup *group)
|
|||||||
updateBufferObject(renderer, group->vertexList, group->vertexIndex);
|
updateBufferObject(renderer, group->vertexList, group->vertexIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL RenderQuad_ createTexQuad(Renderer *renderer, v4 quadRect,
|
INTERNAL RenderQuad_ createRenderQuad(Renderer *renderer, v2 pos, v2 size,
|
||||||
|
v2 pivotPoint, f32 rotate,
|
||||||
RenderTex renderTex)
|
RenderTex renderTex)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -108,16 +140,9 @@ INTERNAL RenderQuad_ createTexQuad(Renderer *renderer, v4 quadRect,
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// NOTE(doyle): Draws a series of triangles using vertices v0, v1, v2, then
|
v4 vertexPair = {0};
|
||||||
// v2, v1, v3 (note the order)
|
vertexPair.vec2[0] = pos;
|
||||||
RenderQuad_ result = {0};
|
vertexPair.vec2[1] = v2_add(pos, size);
|
||||||
|
|
||||||
/* Convert screen coordinates to normalised device coordinates */
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* Convert texture coordinates to normalised texture coordinates */
|
/* Convert texture coordinates to normalised texture coordinates */
|
||||||
v4 texRectNdc = renderTex.texRect;
|
v4 texRectNdc = renderTex.texRect;
|
||||||
@ -131,15 +156,51 @@ INTERNAL RenderQuad_ createTexQuad(Renderer *renderer, v4 quadRect,
|
|||||||
texRectNdc.e[3] *= texNdcFactor.h;
|
texRectNdc.e[3] *= texNdcFactor.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Form the quad */
|
// NOTE(doyle): Create a quad composed of 4 vertexes to be rendered as
|
||||||
result.vertex[0].e = V4(quadRectNdc.x, quadRectNdc.w, texRectNdc.x,
|
// a triangle strip using vertices v0, v1, v2, then v2, v1, v3 (note the
|
||||||
texRectNdc.w); // Top left
|
// order)
|
||||||
result.vertex[1].e = V4(quadRectNdc.x, quadRectNdc.y, texRectNdc.x,
|
RenderQuad_ result = {0};
|
||||||
texRectNdc.y); // Bottom left
|
result.vertex[0].pos = V2(vertexPair.x, vertexPair.w); // Top left
|
||||||
result.vertex[2].e = V4(quadRectNdc.z, quadRectNdc.w, texRectNdc.z,
|
result.vertex[0].texCoord = V2(texRectNdc.x, texRectNdc.w);
|
||||||
texRectNdc.w); // Top right
|
|
||||||
result.vertex[3].e = V4(quadRectNdc.z, quadRectNdc.y, texRectNdc.z,
|
result.vertex[1].pos = V2(vertexPair.x, vertexPair.y); // Bottom left
|
||||||
texRectNdc.y); // Bottom right
|
result.vertex[1].texCoord = V2(texRectNdc.x, texRectNdc.y);
|
||||||
|
|
||||||
|
result.vertex[2].pos = V2(vertexPair.z, vertexPair.w); // Top right
|
||||||
|
result.vertex[2].texCoord = V2(texRectNdc.z, texRectNdc.w);
|
||||||
|
|
||||||
|
result.vertex[3].pos = V2(vertexPair.z, vertexPair.y); // Bottom right
|
||||||
|
result.vertex[3].texCoord = V2(texRectNdc.z, texRectNdc.y);
|
||||||
|
if (rotate == 0) return result;
|
||||||
|
|
||||||
|
// NOTE(doyle): Precalculate rotation on vertex positions
|
||||||
|
// NOTE(doyle): No translation/scale matrix as we pre-calculate it from
|
||||||
|
// entity data and work in world space until GLSL uses the projection matrix
|
||||||
|
|
||||||
|
// NOTE(doyle): Move the world origin to the base position of the object.
|
||||||
|
// Then move the origin to the pivot point (e.g. center of object) and
|
||||||
|
// rotate from that point.
|
||||||
|
v2 pointOfRotation = v2_add(pivotPoint, pos);
|
||||||
|
|
||||||
|
mat4 rotateMat = mat4_translate(pointOfRotation.x, pointOfRotation.y, 0.0f);
|
||||||
|
rotateMat = mat4_mul(rotateMat, mat4_rotate(rotate, 0.0f, 0.0f, 1.0f));
|
||||||
|
rotateMat = mat4_mul(rotateMat, mat4_translate(-pointOfRotation.x,
|
||||||
|
-pointOfRotation.y, 0.0f));
|
||||||
|
for (i32 i = 0; i < ARRAY_COUNT(result.vertex); i++)
|
||||||
|
{
|
||||||
|
// NOTE(doyle): Manual matrix multiplication since vertex pos is 2D and
|
||||||
|
// matrix is 4D
|
||||||
|
v2 oldP = result.vertex[i].pos;
|
||||||
|
v2 newP = {0};
|
||||||
|
|
||||||
|
newP.x = (oldP.x * rotateMat.e[0][0]) + (oldP.y * rotateMat.e[1][0]) +
|
||||||
|
(rotateMat.e[3][0]);
|
||||||
|
newP.y = (oldP.x * rotateMat.e[0][1]) + (oldP.y * rotateMat.e[1][1]) +
|
||||||
|
(rotateMat.e[3][1]);
|
||||||
|
|
||||||
|
result.vertex[i].pos = newP;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,28 +208,16 @@ INTERNAL inline RenderQuad_
|
|||||||
createDefaultTexQuad(Renderer *renderer, RenderTex renderTex)
|
createDefaultTexQuad(Renderer *renderer, RenderTex renderTex)
|
||||||
{
|
{
|
||||||
RenderQuad_ result = {0};
|
RenderQuad_ result = {0};
|
||||||
v4 defaultQuad = V4(0.0f, 0.0f, renderer->size.w, renderer->size.h);
|
result = createRenderQuad(renderer, V2(0, 0), V2(0, 0), V2(0, 0),
|
||||||
result = createTexQuad(renderer, defaultQuad, renderTex);
|
0.0f, renderTex);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void renderObject(Renderer *renderer, v2 pos, v2 size, v2 pivotPoint,
|
INTERNAL void renderObject(Renderer *renderer, v2 pos, v2 size, v2 pivotPoint,
|
||||||
f32 rotate, v4 color, Texture *tex)
|
f32 rotate, v4 color, Texture *tex)
|
||||||
{
|
{
|
||||||
mat4 transMatrix = mat4_translate(pos.x, pos.y, 0.0f);
|
|
||||||
// NOTE(doyle): Rotate from pivot point of the object, (0, 0) is bottom left
|
|
||||||
mat4 rotateMatrix = mat4_translate(pivotPoint.x, pivotPoint.y, 0.0f);
|
|
||||||
rotateMatrix = mat4_mul(rotateMatrix, mat4_rotate(rotate, 0.0f, 0.0f, 1.0f));
|
|
||||||
rotateMatrix = mat4_mul(rotateMatrix,
|
|
||||||
mat4_translate(-pivotPoint.x, -pivotPoint.y, 0.0f));
|
|
||||||
|
|
||||||
// NOTE(doyle): We draw everything as a unit square in OGL. Scale it to size
|
|
||||||
mat4 scaleMatrix = mat4_scale(size.x, size.y, 1.0f);
|
|
||||||
mat4 model = mat4_mul(transMatrix, mat4_mul(rotateMatrix, scaleMatrix));
|
|
||||||
|
|
||||||
/* Load transformation matrix */
|
/* Load transformation matrix */
|
||||||
shader_use(renderer->shader);
|
shader_use(renderer->shader);
|
||||||
shader_uniformSetMat4fv(renderer->shader, "model", model);
|
|
||||||
GL_CHECK_ERROR();
|
GL_CHECK_ERROR();
|
||||||
|
|
||||||
/* Set color modulation value */
|
/* Set color modulation value */
|
||||||
@ -201,14 +250,6 @@ INTERNAL void renderObject(Renderer *renderer, v2 pos, v2 size, v2 pivotPoint,
|
|||||||
GL_CHECK_ERROR();
|
GL_CHECK_ERROR();
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL v2 mapWorldToCameraSpace(v2 worldPos, v4 cameraBounds)
|
|
||||||
{
|
|
||||||
// Convert the world position to the camera coordinate system
|
|
||||||
v2 cameraBottomLeftBound = V2(cameraBounds.x, cameraBounds.w);
|
|
||||||
v2 posInCameraSpace = v2_sub(worldPos, cameraBottomLeftBound);
|
|
||||||
return posInCameraSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderTex renderer_createNullRenderTex(AssetManager *const assetManager)
|
RenderTex renderer_createNullRenderTex(AssetManager *const assetManager)
|
||||||
{
|
{
|
||||||
Texture *emptyTex = asset_getTex(assetManager, "nullTex");
|
Texture *emptyTex = asset_getTex(assetManager, "nullTex");
|
||||||
@ -219,50 +260,11 @@ RenderTex renderer_createNullRenderTex(AssetManager *const assetManager)
|
|||||||
void renderer_rect(Renderer *const renderer, Rect camera, v2 pos, v2 size,
|
void renderer_rect(Renderer *const renderer, Rect camera, v2 pos, v2 size,
|
||||||
v2 pivotPoint, f32 rotate, RenderTex renderTex, v4 color)
|
v2 pivotPoint, f32 rotate, RenderTex renderTex, v4 color)
|
||||||
{
|
{
|
||||||
|
// NOTE(doyle): Bottom left and top right position of quad in world space
|
||||||
v2 posInCameraSpace = v2_sub(pos, camera.pos);
|
v2 posInCameraSpace = v2_sub(pos, camera.pos);
|
||||||
|
RenderQuad_ quad = createRenderQuad(renderer, posInCameraSpace, size,
|
||||||
#if RENDERER_USE_RENDER_GROUPS
|
pivotPoint, rotate, renderTex);
|
||||||
// TODO(doyle): getRect needs a better name
|
addRenderQuadToRenderGroup(renderer, quad, renderTex);
|
||||||
v4 entityVertexOnScreen = math_getRect(posInCameraSpace, size);
|
|
||||||
RenderQuad_ entityQuad =
|
|
||||||
createTexQuad(renderer, entityVertexOnScreen, renderTex);
|
|
||||||
|
|
||||||
/*
|
|
||||||
NOTE(doyle): Entity rendering is always done in two pairs of
|
|
||||||
triangles, i.e. quad. To batch render quads as a triangle strip, we
|
|
||||||
need to create zero-area triangles which OGL will omit from
|
|
||||||
rendering. Render groups are initialised with 1 degenerate vertex and
|
|
||||||
then the first two vertexes sent to the render group are the same to
|
|
||||||
form 1 zero-area triangle strip.
|
|
||||||
|
|
||||||
A degenerate vertex has to be copied from the last vertex in the
|
|
||||||
rendering quad, to repeat this process as more entities are
|
|
||||||
renderered.
|
|
||||||
|
|
||||||
Alternative implementation is recognising if the rendered
|
|
||||||
entity is the first in its render group, then we don't need to init
|
|
||||||
a degenerate vertex, and only at the end of its vertex list. But on
|
|
||||||
subsequent renders, we need a degenerate vertex at the front to
|
|
||||||
create the zero-area triangle strip.
|
|
||||||
|
|
||||||
The first has been chosen for simplicity of code, at the cost of
|
|
||||||
1 degenerate vertex at the start of each render group.
|
|
||||||
*/
|
|
||||||
Vertex degenerateVertexes[2] = {entityQuad.vertex[0], entityQuad.vertex[3]};
|
|
||||||
|
|
||||||
Vertex vertexList[6] = {degenerateVertexes[0], entityQuad.vertex[0],
|
|
||||||
entityQuad.vertex[1], entityQuad.vertex[2],
|
|
||||||
entityQuad.vertex[3], degenerateVertexes[1]};
|
|
||||||
|
|
||||||
addToRenderGroup(renderer, renderTex.tex, vertexList,
|
|
||||||
ARRAY_COUNT(vertexList));
|
|
||||||
#else
|
|
||||||
RenderQuad_ quad = createDefaultTexQuad(renderer, renderTex);
|
|
||||||
updateBufferObject(renderer, quad.vertex, ARRAY_COUNT(quad.vertex));
|
|
||||||
|
|
||||||
renderObject(renderer, posInCameraSpace, size, pivotPoint, rotate,
|
|
||||||
color, renderTex.tex);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera,
|
void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera,
|
||||||
@ -281,20 +283,13 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera,
|
|||||||
if (math_pointInRect(camera, leftAlignedP) ||
|
if (math_pointInRect(camera, leftAlignedP) ||
|
||||||
math_pointInRect(camera, rightAlignedP))
|
math_pointInRect(camera, rightAlignedP))
|
||||||
{
|
{
|
||||||
|
|
||||||
i32 vertexIndex = 0;
|
i32 vertexIndex = 0;
|
||||||
const i32 numVertexPerQuad = 4;
|
i32 numVertexPerQuad = 4;
|
||||||
|
i32 numVertexesToAlloc = (strLen * (numVertexPerQuad + 2));
|
||||||
#if RENDERER_USE_RENDER_GROUPS
|
|
||||||
const i32 numVertexesToAlloc = (strLen * (numVertexPerQuad + 2));
|
|
||||||
#else
|
|
||||||
const i32 numVertexesToAlloc = (strLen * numVertexPerQuad);
|
|
||||||
#endif
|
|
||||||
Vertex *vertexList =
|
Vertex *vertexList =
|
||||||
PLATFORM_MEM_ALLOC(arena, numVertexesToAlloc, Vertex);
|
PLATFORM_MEM_ALLOC(arena, numVertexesToAlloc, Vertex);
|
||||||
|
|
||||||
v2 posInCameraSpace = v2_sub(pos, camera.pos);
|
v2 posInCameraSpace = v2_sub(pos, camera.pos);
|
||||||
|
|
||||||
pos = posInCameraSpace;
|
pos = posInCameraSpace;
|
||||||
|
|
||||||
// TODO(doyle): Find why font is 1px off, might be arial font semantics
|
// TODO(doyle): Find why font is 1px off, might be arial font semantics
|
||||||
@ -304,51 +299,33 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera,
|
|||||||
{
|
{
|
||||||
i32 codepoint = string[i];
|
i32 codepoint = string[i];
|
||||||
i32 relativeIndex = CAST(i32)(codepoint - font->codepointRange.x);
|
i32 relativeIndex = CAST(i32)(codepoint - font->codepointRange.x);
|
||||||
CharMetrics charMetric = font->charMetrics[relativeIndex];
|
CharMetrics metric = font->charMetrics[relativeIndex];
|
||||||
pos.y = baseline - (charMetric.offset.y);
|
pos.y = baseline - (metric.offset.y);
|
||||||
|
|
||||||
const v4 charRectOnScreen =
|
|
||||||
math_getRect(pos, font->maxSize);
|
|
||||||
pos.x += charMetric.advance;
|
|
||||||
|
|
||||||
/* Get texture out */
|
/* Get texture out */
|
||||||
SubTexture charSubTexture =
|
SubTexture subTexture =
|
||||||
asset_getAtlasSubTex(font->atlas, &CAST(char)codepoint);
|
asset_getAtlasSubTex(font->atlas, &CAST(char)codepoint);
|
||||||
|
|
||||||
v4 charTexRect = {0};
|
v4 charTexRect = {0};
|
||||||
charTexRect.vec2[0] = charSubTexture.rect.pos;
|
charTexRect.vec2[0] = subTexture.rect.pos;
|
||||||
charTexRect.vec2[1] =
|
charTexRect.vec2[1] =
|
||||||
v2_add(charSubTexture.rect.pos, charSubTexture.rect.size);
|
v2_add(subTexture.rect.pos, subTexture.rect.size);
|
||||||
|
|
||||||
flipTexCoord(&charTexRect, FALSE, TRUE);
|
flipTexCoord(&charTexRect, FALSE, TRUE);
|
||||||
|
|
||||||
RenderTex renderTex = {tex, charTexRect};
|
RenderTex renderTex = {tex, charTexRect};
|
||||||
RenderQuad_ charQuad =
|
RenderQuad_ quad = createRenderQuad(renderer, pos, font->maxSize,
|
||||||
createTexQuad(renderer, charRectOnScreen, renderTex);
|
pivotPoint, rotate, renderTex);
|
||||||
|
|
||||||
Vertex degenerateVertexes[2] = {charQuad.vertex[0],
|
vertexList[vertexIndex++] = quad.vertex[0];
|
||||||
charQuad.vertex[3]};
|
for (i32 i = 0; i < ARRAY_COUNT(quad.vertex); i++)
|
||||||
|
{
|
||||||
vertexList[vertexIndex++] = degenerateVertexes[0];
|
vertexList[vertexIndex++] = quad.vertex[i];
|
||||||
for (i32 i = 0; i < ARRAY_COUNT(charQuad.vertex); i++)
|
}
|
||||||
vertexList[vertexIndex++] = charQuad.vertex[i];
|
vertexList[vertexIndex++] = quad.vertex[3];
|
||||||
|
pos.x += metric.advance;
|
||||||
vertexList[vertexIndex++] = degenerateVertexes[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(doyle): We render at the renderer's size because we create quads
|
addVertexToRenderGroup(renderer, tex, vertexList, numVertexesToAlloc);
|
||||||
// relative to the window size, hence we also render at the origin since
|
|
||||||
// we're rendering a window sized buffer
|
|
||||||
|
|
||||||
// TODO(doyle): Render group differentiate between null tex and colors
|
|
||||||
#if RENDERER_USE_RENDER_GROUPS && !DISABLE_TEXT_RENDER_GROUPS
|
|
||||||
addToRenderGroup(renderer, tex, vertexList, numVertexesToAlloc);
|
|
||||||
#else
|
|
||||||
updateBufferObject(renderer, vertexList, vertexIndex);
|
|
||||||
renderObject(renderer, V2(0.0f, 0.0f), renderer->size, pivotPoint,
|
|
||||||
rotate, color, tex);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PLATFORM_MEM_FREE(arena, vertexList,
|
PLATFORM_MEM_FREE(arena, vertexList,
|
||||||
sizeof(Vertex) * numVertexesToAlloc);
|
sizeof(Vertex) * numVertexesToAlloc);
|
||||||
}
|
}
|
||||||
@ -384,8 +361,6 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
|
|||||||
}
|
}
|
||||||
|
|
||||||
RenderTex renderTex = {entity->tex, animTexRect};
|
RenderTex renderTex = {entity->tex, animTexRect};
|
||||||
|
|
||||||
// TODO(doyle): Rotation is lost since rotation transformations aren't stored into vertex data when put into render group
|
|
||||||
renderer_rect(renderer, camera, entity->pos, entity->size, pivotPoint,
|
renderer_rect(renderer, camera, entity->pos, entity->size, pivotPoint,
|
||||||
entity->rotation + rotate, renderTex, color);
|
entity->rotation + rotate, renderTex, color);
|
||||||
}
|
}
|
||||||
@ -399,12 +374,8 @@ void renderer_renderGroups(Renderer *renderer)
|
|||||||
if (currGroup->tex)
|
if (currGroup->tex)
|
||||||
{
|
{
|
||||||
bufferRenderGroupToGL(renderer, currGroup);
|
bufferRenderGroupToGL(renderer, currGroup);
|
||||||
|
renderObject(renderer, V2(0.0f, 0.0f), renderer->size, V2(0, 0),
|
||||||
v2 pivotPoint = V2(0, 0);
|
0, V4(1, 1, 1, 1), currGroup->tex);
|
||||||
f32 rotate = 0;
|
|
||||||
v4 color = V4(1, 1, 1, 1);
|
|
||||||
renderObject(renderer, V2(0.0f, 0.0f), renderer->size, pivotPoint,
|
|
||||||
rotate, color, currGroup->tex);
|
|
||||||
|
|
||||||
RenderGroup cleanGroup = {0};
|
RenderGroup cleanGroup = {0};
|
||||||
cleanGroup.vertexList = currGroup->vertexList;
|
cleanGroup.vertexList = currGroup->vertexList;
|
||||||
|
@ -87,11 +87,12 @@ INTERNAL void rendererInit(GameState *state, v2 windowSize)
|
|||||||
glBindVertexArray(renderer->vao);
|
glBindVertexArray(renderer->vao);
|
||||||
|
|
||||||
/* Configure VAO */
|
/* Configure VAO */
|
||||||
const GLuint numVertexElements = 4;
|
u32 numVertexElements = 4;
|
||||||
const GLuint vertexSize = sizeof(Vertex);
|
u32 stride = sizeof(Vertex);
|
||||||
|
glVertexAttribPointer(0, numVertexElements, GL_FLOAT, GL_FALSE,
|
||||||
|
stride, (GLvoid *)0);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glVertexAttribPointer(0, numVertexElements, GL_FLOAT, GL_FALSE, vertexSize,
|
|
||||||
(GLvoid *)0);
|
|
||||||
GL_CHECK_ERROR();
|
GL_CHECK_ERROR();
|
||||||
|
|
||||||
/* Unbind */
|
/* Unbind */
|
||||||
@ -589,7 +590,7 @@ INTERNAL void entityInit(GameState *state, v2 windowSize)
|
|||||||
Renderer *renderer = &state->renderer;
|
Renderer *renderer = &state->renderer;
|
||||||
v2 size = V2(10.0f, 10.0f);
|
v2 size = V2(10.0f, 10.0f);
|
||||||
v2 pos = V2(0, 0);
|
v2 pos = V2(0, 0);
|
||||||
f32 scale = 0.0f;
|
f32 scale = 1.0f;
|
||||||
enum EntityType type = entitytype_soundscape;
|
enum EntityType type = entitytype_soundscape;
|
||||||
enum Direction dir = direction_null;
|
enum Direction dir = direction_null;
|
||||||
Texture *tex = NULL;
|
Texture *tex = NULL;
|
||||||
@ -2022,12 +2023,14 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
{
|
{
|
||||||
weapon->pos.x += entitySubTexture.offset.x;
|
weapon->pos.x += entitySubTexture.offset.x;
|
||||||
// TODO(doyle): Typedef rotation to degrees for type safety
|
// TODO(doyle): Typedef rotation to degrees for type safety
|
||||||
weapon->rotation = DEGREES_TO_RADIANS(60.0f);
|
weapon->rotation = DEGREES_TO_RADIANS(30.0f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
LOCAL_PERSIST f32 rotation = -30.0f;
|
||||||
|
rotation -= 1.5f;
|
||||||
weapon->pos.x -= entitySubTexture.offset.x;
|
weapon->pos.x -= entitySubTexture.offset.x;
|
||||||
weapon->rotation = DEGREES_TO_RADIANS(-60.0f);
|
weapon->rotation = DEGREES_TO_RADIANS(rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2426,8 +2429,9 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
v2 heroCenter = v2_add(hero->pos, v2_scale(hero->hitbox, 0.5f));
|
v2 heroCenter = v2_add(hero->pos, v2_scale(hero->hitbox, 0.5f));
|
||||||
RenderTex renderTex = renderer_createNullRenderTex(assetManager);
|
RenderTex renderTex = renderer_createNullRenderTex(assetManager);
|
||||||
f32 distance = v2_magnitude(hero->pos, entity->pos);
|
f32 distance = v2_magnitude(hero->pos, entity->pos);
|
||||||
|
v2 size = V2(distance, 2.0f);
|
||||||
renderer_rect(&state->renderer, camera, heroCenter,
|
renderer_rect(&state->renderer, camera, heroCenter,
|
||||||
V2(distance, 2.0f), V2(0, 0), angle, renderTex,
|
size, V2(0, 0), angle, renderTex,
|
||||||
V4(1, 0, 0, 1.0f));
|
V4(1, 0, 0, 1.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2458,8 +2462,5 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if RENDERER_USE_RENDER_GROUPS
|
|
||||||
renderer_renderGroups(renderer);
|
renderer_renderGroups(renderer);
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -188,6 +188,8 @@ INTERNAL inline v3 v3_cross(const v3 a, const v3 b)
|
|||||||
typedef union mat4
|
typedef union mat4
|
||||||
{
|
{
|
||||||
v4 col[4];
|
v4 col[4];
|
||||||
|
|
||||||
|
// Column/row
|
||||||
f32 e[4][4];
|
f32 e[4][4];
|
||||||
} mat4;
|
} mat4;
|
||||||
|
|
||||||
@ -279,14 +281,15 @@ INTERNAL inline mat4 mat4_mul(const mat4 a, const mat4 b)
|
|||||||
INTERNAL inline v4 mat4_mul_v4(const mat4 a, const v4 b)
|
INTERNAL inline v4 mat4_mul_v4(const mat4 a, const v4 b)
|
||||||
{
|
{
|
||||||
v4 result = {0};
|
v4 result = {0};
|
||||||
result.x =
|
|
||||||
a.e[0][0] * b.x + a.e[0][1] * b.y + a.e[0][2] * b.z + a.e[0][3] * b.w;
|
result.x = (a.e[0][0] * b.x) + (a.e[1][0] * b.y) + (a.e[2][0] * b.z) +
|
||||||
result.y =
|
(a.e[3][0] * b.w);
|
||||||
a.e[1][0] * b.x + a.e[1][1] * b.y + a.e[1][2] * b.z + a.e[1][3] * b.w;
|
result.y = (a.e[0][1] * b.x) + (a.e[1][1] * b.y) + (a.e[2][1] * b.z) +
|
||||||
result.z =
|
(a.e[3][1] * b.w);
|
||||||
a.e[2][0] * b.x + a.e[2][1] * b.y + a.e[2][2] * b.z + a.e[2][3] * b.w;
|
result.z = (a.e[0][2] * b.x) + (a.e[1][2] * b.y) + (a.e[2][2] * b.z) +
|
||||||
result.w =
|
(a.e[3][2] * b.w);
|
||||||
a.e[3][0] * b.x + a.e[3][1] * b.y + a.e[3][2] * b.z + a.e[3][3] * b.w;
|
result.w = (a.e[0][3] * b.x) + (a.e[1][3] * b.y) + (a.e[2][3] * b.z) +
|
||||||
|
(a.e[3][3] * b.w);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -12,16 +12,10 @@ typedef struct MemoryArena MemoryArena;
|
|||||||
typedef struct Shader Shader;
|
typedef struct Shader Shader;
|
||||||
typedef struct Texture Texture;
|
typedef struct Texture Texture;
|
||||||
|
|
||||||
typedef union Vertex
|
typedef struct Vertex
|
||||||
{
|
{
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
v2 pos;
|
v2 pos;
|
||||||
v2 texCoords;
|
v2 texCoord;
|
||||||
};
|
|
||||||
|
|
||||||
v4 e;
|
|
||||||
} Vertex;
|
} Vertex;
|
||||||
|
|
||||||
typedef struct RenderQuad
|
typedef struct RenderQuad
|
||||||
@ -57,8 +51,6 @@ typedef struct Renderer
|
|||||||
i32 groupCapacity;
|
i32 groupCapacity;
|
||||||
} Renderer;
|
} Renderer;
|
||||||
|
|
||||||
#define RENDERER_USE_RENDER_GROUPS TRUE
|
|
||||||
|
|
||||||
// TODO(doyle): Use z-index occluding for rendering
|
// TODO(doyle): Use z-index occluding for rendering
|
||||||
RenderTex renderer_createNullRenderTex(AssetManager *const assetManager);
|
RenderTex renderer_createNullRenderTex(AssetManager *const assetManager);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user