Move rotation step outside of inner rendering loop
We need to generate interim vertex points during the collision detection loop that includes rotation to check for collision. During collision detection, vertex points are rotated and positioned in placed for checking. We also re-create this vertex list in the renderer suggesting that we could cache the list in the entity or look at coupling rendering and collision detection.
This commit is contained in:
parent
20749dd668
commit
0c7824bf18
147
src/Asteroid.c
147
src/Asteroid.c
@ -83,7 +83,7 @@ void initRenderer(GameState *state, v2 windowSize) {
|
|||||||
|
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
u32 numVertexElements = 4;
|
u32 numVertexElements = 4;
|
||||||
u32 stride = sizeof(Vertex);
|
u32 stride = sizeof(RenderVertex);
|
||||||
|
|
||||||
glVertexAttribPointer(0, numVertexElements, GL_FLOAT,
|
glVertexAttribPointer(0, numVertexElements, GL_FLOAT,
|
||||||
GL_FALSE, stride, (GLvoid *)0);
|
GL_FALSE, stride, (GLvoid *)0);
|
||||||
@ -98,8 +98,9 @@ void initRenderer(GameState *state, v2 windowSize) {
|
|||||||
renderer->groupCapacity = 4096;
|
renderer->groupCapacity = 4096;
|
||||||
for (i32 i = 0; i < ARRAY_COUNT(renderer->groups); i++)
|
for (i32 i = 0; i < ARRAY_COUNT(renderer->groups); i++)
|
||||||
{
|
{
|
||||||
renderer->groups[i].vertexList = memory_pushBytes(
|
renderer->groups[i].vertexList =
|
||||||
&state->persistentArena, renderer->groupCapacity * sizeof(Vertex));
|
memory_pushBytes(&state->persistentArena,
|
||||||
|
renderer->groupCapacity * sizeof(RenderVertex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,38 +222,36 @@ v2 *createAsteroidVertexList(MemoryArena_ *arena, i32 iterations,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
v2 *createEntityEdgeList(MemoryArena_ *transientArena, Entity *entity)
|
v2 *createNormalEdgeList(MemoryArena_ *transientArena, v2 *vertexList,
|
||||||
|
i32 vertexListSize)
|
||||||
{
|
{
|
||||||
v2 *result = memory_pushBytes(transientArena,
|
v2 *result = memory_pushBytes(transientArena, sizeof(v2) * vertexListSize);
|
||||||
sizeof(v2) * entity->numVertexPoints);
|
for (i32 i = 0; i < vertexListSize - 1; i++)
|
||||||
|
|
||||||
i32 numVertexes = entity->numVertexPoints;
|
|
||||||
for (i32 i = 0; i < numVertexes - 1; i++)
|
|
||||||
{
|
{
|
||||||
ASSERT((i + 1) < numVertexes);
|
ASSERT((i + 1) < vertexListSize);
|
||||||
result[i] =
|
result[i] = v2_sub(vertexList[i + 1], vertexList[i]);
|
||||||
v2_sub(entity->vertexPoints[i + 1], entity->vertexPoints[i]);
|
result[i] = v2_perpendicular(result[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(doyle): Creating the last edge requires using the first
|
// NOTE(doyle): Creating the last edge requires using the first
|
||||||
// vertex point which is at index 0
|
// vertex point which is at index 0
|
||||||
result[numVertexes - 1] =
|
result[vertexListSize - 1] =
|
||||||
v2_sub(entity->vertexPoints[0], entity->vertexPoints[numVertexes - 1]);
|
v2_sub(vertexList[0], vertexList[vertexListSize - 1]);
|
||||||
|
result[vertexListSize - 1] = v2_perpendicular(result[vertexListSize - 1]);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
v2 calculateProjectionRangeForEdge(Entity *entity, v2 edgeNormal)
|
v2 calculateProjectionRangeForEdge(v2 *vertexList, i32 vertexListSize,
|
||||||
|
v2 edgeNormal)
|
||||||
{
|
{
|
||||||
v2 result = {0};
|
v2 result = {0};
|
||||||
result.max = v2_dot(entity->vertexPoints[0], edgeNormal);
|
result.min = v2_dot(vertexList[0], edgeNormal);
|
||||||
result.max = result.min;
|
result.max = result.min;
|
||||||
|
|
||||||
for (i32 vertexIndex = 0; vertexIndex < entity->numVertexPoints;
|
for (i32 vertexIndex = 0; vertexIndex < vertexListSize; vertexIndex++)
|
||||||
vertexIndex++)
|
|
||||||
{
|
{
|
||||||
f32 dist =
|
f32 dist = v2_dot(vertexList[vertexIndex], edgeNormal);
|
||||||
v2_dot(entity->vertexPoints[vertexIndex], edgeNormal);
|
|
||||||
|
|
||||||
if (dist < result.min)
|
if (dist < result.min)
|
||||||
result.min = dist;
|
result.min = dist;
|
||||||
@ -263,20 +262,20 @@ v2 calculateProjectionRangeForEdge(Entity *entity, v2 edgeNormal)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 checkEntityProjectionOverlap(Entity *entity, Entity *checkEntity,
|
b32 checkEdgeProjectionOverlap(v2 *vertexList, i32 listSize,
|
||||||
v2 *entityEdges)
|
v2 *checkVertexList, i32 checkListSize,
|
||||||
|
v2 *edgeList, i32 totalNumEdges)
|
||||||
{
|
{
|
||||||
b32 result = TRUE;
|
b32 result = TRUE;
|
||||||
for (i32 edgeIndex = 0; edgeIndex < entity->numVertexPoints && result;
|
for (i32 edgeIndex = 0; edgeIndex < totalNumEdges && result; edgeIndex++)
|
||||||
edgeIndex++)
|
|
||||||
{
|
{
|
||||||
v2 entityProjectionRange =
|
v2 projectionRange = calculateProjectionRangeForEdge(
|
||||||
calculateProjectionRangeForEdge(entity, entityEdges[edgeIndex]);
|
vertexList, listSize, edgeList[edgeIndex]);
|
||||||
v2 checkEntityProjectionRange = calculateProjectionRangeForEdge(
|
|
||||||
checkEntity, entityEdges[edgeIndex]);
|
|
||||||
|
|
||||||
if (!v2_intervalsOverlap(entityProjectionRange,
|
v2 checkProjectionRange = calculateProjectionRangeForEdge(
|
||||||
checkEntityProjectionRange))
|
checkVertexList, checkListSize, edgeList[edgeIndex]);
|
||||||
|
|
||||||
|
if (!v2_intervalsOverlap(projectionRange, checkProjectionRange))
|
||||||
{
|
{
|
||||||
result = FALSE;
|
result = FALSE;
|
||||||
return result;
|
return result;
|
||||||
@ -286,7 +285,7 @@ b32 checkEntityProjectionOverlap(Entity *entity, Entity *checkEntity,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed)
|
b32 moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed)
|
||||||
{
|
{
|
||||||
ASSERT(ABS(ddP.x) <= 1.0f && ABS(ddP.y) <= 1.0f);
|
ASSERT(ABS(ddP.x) <= 1.0f && ABS(ddP.y) <= 1.0f);
|
||||||
/*
|
/*
|
||||||
@ -311,7 +310,8 @@ void moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed)
|
|||||||
v2 newPos = v2_add(v2_add(ddPHalfDtSquared, oldDpDt), oldPos);
|
v2 newPos = v2_add(v2_add(ddPHalfDtSquared, oldDpDt), oldPos);
|
||||||
|
|
||||||
b32 willCollide = FALSE;
|
b32 willCollide = FALSE;
|
||||||
#if 0
|
|
||||||
|
#if 1
|
||||||
if (entity->renderMode == rendermode_polygon && entity->collides)
|
if (entity->renderMode == rendermode_polygon && entity->collides)
|
||||||
{
|
{
|
||||||
for (i32 i = 0; i < state->entityIndex; i++)
|
for (i32 i = 0; i < state->entityIndex; i++)
|
||||||
@ -322,31 +322,40 @@ void moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed)
|
|||||||
if (checkEntity->renderMode == rendermode_polygon &&
|
if (checkEntity->renderMode == rendermode_polygon &&
|
||||||
checkEntity->collides)
|
checkEntity->collides)
|
||||||
{
|
{
|
||||||
i32 numEntityEdges = entity->numVertexPoints;
|
/* Create entity edge lists */
|
||||||
i32 numCheckEntityEdges = checkEntity->numVertexPoints;
|
v2 *entityVertexListOffsetToP =
|
||||||
v2 *entityEdges =
|
entity_createVertexList(&state->transientArena, entity);
|
||||||
createEntityEdgeList(&state->transientArena, entity);
|
v2 *checkEntityVertexListOffsetToP = entity_createVertexList(
|
||||||
v2 *checkEntityEdges =
|
&state->transientArena, checkEntity);
|
||||||
createEntityEdgeList(&state->transientArena, entity);
|
|
||||||
|
|
||||||
// Convert inplace the vector normal of the edges
|
v2 *entityEdgeList = createNormalEdgeList(
|
||||||
for (i32 i = 0; i < numEntityEdges; i++)
|
&state->transientArena, entityVertexListOffsetToP,
|
||||||
|
entity->numVertexPoints);
|
||||||
|
|
||||||
|
v2 *checkEntityEdgeList = createNormalEdgeList(
|
||||||
|
&state->transientArena, checkEntityVertexListOffsetToP,
|
||||||
|
checkEntity->numVertexPoints);
|
||||||
|
|
||||||
|
/* Combine both edge lists into one */
|
||||||
|
i32 totalNumEdges =
|
||||||
|
checkEntity->numVertexPoints + entity->numVertexPoints;
|
||||||
|
v2 *edgeList = memory_pushBytes(&state->transientArena,
|
||||||
|
totalNumEdges * sizeof(v2));
|
||||||
|
for (i32 i = 0; i < entity->numVertexPoints; i++)
|
||||||
{
|
{
|
||||||
entityEdges[i] = v2_perpendicular(entityEdges[i]);
|
edgeList[i] = entityEdgeList[i];
|
||||||
entityEdges[i] = v2_add(entityEdges[i], entity->pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i32 i = 0; i < numCheckEntityEdges; i++)
|
for (i32 i = 0; i < checkEntity->numVertexPoints; i++)
|
||||||
{
|
{
|
||||||
checkEntityEdges[i] = v2_perpendicular(checkEntityEdges[i]);
|
edgeList[i + entity->numVertexPoints] =
|
||||||
checkEntityEdges[i] =
|
checkEntityEdgeList[i];
|
||||||
v2_add(checkEntityEdges[i], checkEntity->pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((checkEntityProjectionOverlap(entity, checkEntity,
|
if (checkEdgeProjectionOverlap(
|
||||||
entityEdges) &&
|
entityVertexListOffsetToP, entity->numVertexPoints,
|
||||||
checkEntityProjectionOverlap(entity, checkEntity,
|
checkEntityVertexListOffsetToP,
|
||||||
checkEntityEdges)))
|
checkEntity->numVertexPoints, edgeList, totalNumEdges))
|
||||||
{
|
{
|
||||||
willCollide = TRUE;
|
willCollide = TRUE;
|
||||||
}
|
}
|
||||||
@ -364,13 +373,17 @@ void moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed)
|
|||||||
entity->dP = newDp;
|
entity->dP = newDp;
|
||||||
entity->pos = newPos;
|
entity->pos = newPos;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entity->dP = v2_scale(newDp, -1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return willCollide;
|
||||||
}
|
}
|
||||||
|
|
||||||
void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
||||||
v2 windowSize, f32 dt)
|
v2 windowSize, f32 dt)
|
||||||
{
|
{
|
||||||
i32 iterations = 16;
|
|
||||||
|
|
||||||
memory_arenaInit(&state->transientArena, memory->transient,
|
memory_arenaInit(&state->transientArena, memory->transient,
|
||||||
memory->transientSize);
|
memory->transientSize);
|
||||||
|
|
||||||
@ -387,8 +400,9 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
|||||||
{ // Init ship entity
|
{ // Init ship entity
|
||||||
Entity *ship = &state->entityList[state->entityIndex];
|
Entity *ship = &state->entityList[state->entityIndex];
|
||||||
ship->id = state->entityIndex++;
|
ship->id = state->entityIndex++;
|
||||||
ship->pos = V2(0, 0);
|
ship->pos = V2(100, 100);
|
||||||
ship->size = V2(25.0f, 50.0f);
|
ship->size = V2(25.0f, 50.0f);
|
||||||
|
ship->rotation = 90.0f;
|
||||||
ship->hitbox = ship->size;
|
ship->hitbox = ship->size;
|
||||||
ship->offset = v2_scale(ship->size, 0.5f);
|
ship->offset = v2_scale(ship->size, 0.5f);
|
||||||
|
|
||||||
@ -411,7 +425,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
|||||||
ship->tex = NULL;
|
ship->tex = NULL;
|
||||||
ship->collides = TRUE;
|
ship->collides = TRUE;
|
||||||
|
|
||||||
i32 numAsteroids = 8;
|
i32 numAsteroids = 1;
|
||||||
for (i32 i = 0; i < numAsteroids; i++)
|
for (i32 i = 0; i < numAsteroids; i++)
|
||||||
{
|
{
|
||||||
Entity *asteroid = &state->entityList[state->entityIndex];
|
Entity *asteroid = &state->entityList[state->entityIndex];
|
||||||
@ -420,7 +434,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
|||||||
i32 randValue = rand();
|
i32 randValue = rand();
|
||||||
i32 randX = (randValue % (i32)windowSize.w);
|
i32 randX = (randValue % (i32)windowSize.w);
|
||||||
i32 randY = (randValue % (i32)windowSize.h);
|
i32 randY = (randValue % (i32)windowSize.h);
|
||||||
asteroid->pos = V2i(randX, randY);
|
asteroid->pos = V2i(500, 500);
|
||||||
|
|
||||||
asteroid->size = V2(100.0f, 100.0f);
|
asteroid->size = V2(100.0f, 100.0f);
|
||||||
asteroid->hitbox = asteroid->size;
|
asteroid->hitbox = asteroid->size;
|
||||||
@ -438,6 +452,19 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
|||||||
asteroid->tex = NULL;
|
asteroid->tex = NULL;
|
||||||
asteroid->collides = TRUE;
|
asteroid->collides = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entity *square = &state->entityList[state->entityIndex];
|
||||||
|
square->id = state->entityIndex++;
|
||||||
|
square->pos = V2(350, 350);
|
||||||
|
square->size = V2(75.0f, 75.0f);
|
||||||
|
square->hitbox = square->size;
|
||||||
|
square->offset = v2_scale(square->size, 0.5f);
|
||||||
|
square->scale = 1;
|
||||||
|
square->type = entitytype_asteroid;
|
||||||
|
square->direction = direction_null;
|
||||||
|
square->renderMode = rendermode_quad;
|
||||||
|
square->tex = NULL;
|
||||||
|
square->collides = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->camera.min = V2(0, 0);
|
state->camera.min = V2(0, 0);
|
||||||
@ -546,6 +573,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
|||||||
}
|
}
|
||||||
|
|
||||||
v2 ddP = {0};
|
v2 ddP = {0};
|
||||||
|
#if 0
|
||||||
switch (entity->direction)
|
switch (entity->direction)
|
||||||
{
|
{
|
||||||
case direction_north:
|
case direction_north:
|
||||||
@ -613,15 +641,20 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
|||||||
// NOTE(doyle): Make asteroids start and move at constant speed
|
// NOTE(doyle): Make asteroids start and move at constant speed
|
||||||
ddPSpeedInMs = 2;
|
ddPSpeedInMs = 2;
|
||||||
entity->dP = v2_scale(ddP, state->pixelsPerMeter * ddPSpeedInMs);
|
entity->dP = v2_scale(ddP, state->pixelsPerMeter * ddPSpeedInMs);
|
||||||
|
#endif
|
||||||
entity->rotation += (randValue % 20) * dt;
|
entity->rotation += (randValue % 20) * dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
moveEntity(state, entity, ddP, dt, ddPSpeedInMs);
|
b32 willCollide = moveEntity(state, entity, ddP, dt, ddPSpeedInMs);
|
||||||
|
|
||||||
|
v4 entityCollisionColor = V4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
if (willCollide) entityCollisionColor = V4(1.0f, 0, 0, 1.0f);
|
||||||
|
|
||||||
RenderFlags flags = renderflag_wireframe | renderflag_no_texture;
|
RenderFlags flags = renderflag_wireframe | renderflag_no_texture;
|
||||||
renderer_entity(&state->renderer, &state->transientArena, state->camera,
|
renderer_entity(&state->renderer, &state->transientArena, state->camera,
|
||||||
entity, V2(0, 0), 0,
|
entity, V2(0, 0), 0,
|
||||||
V4(0.4f, 0.8f, 1.0f, 1.0f), flags);
|
entityCollisionColor, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_drawUi(state, dt);
|
debug_drawUi(state, dt);
|
||||||
|
21
src/Entity.c
21
src/Entity.c
@ -1,6 +1,8 @@
|
|||||||
#include "Dengine/Entity.h"
|
#include "Dengine/Entity.h"
|
||||||
#include "Dengine/AssetManager.h"
|
#include "Dengine/AssetManager.h"
|
||||||
#include "Dengine/Debug.h"
|
#include "Dengine/Debug.h"
|
||||||
|
#include "Dengine/Math.h"
|
||||||
|
#include "Dengine/MemoryArena.h"
|
||||||
|
|
||||||
SubTexture entity_getActiveSubTexture(Entity *const entity)
|
SubTexture entity_getActiveSubTexture(Entity *const entity)
|
||||||
{
|
{
|
||||||
@ -86,3 +88,22 @@ void entity_addAnim(AssetManager *const assetManager, Entity *const entity,
|
|||||||
|
|
||||||
DEBUG_LOG("No more free entity animation slots");
|
DEBUG_LOG("No more free entity animation slots");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v2 *entity_createVertexList(MemoryArena_ *transientArena, Entity *entity)
|
||||||
|
{
|
||||||
|
v2 *result =
|
||||||
|
memory_pushBytes(transientArena, entity->numVertexPoints * sizeof(v2));
|
||||||
|
|
||||||
|
for (i32 i = 0; i < entity->numVertexPoints; i++)
|
||||||
|
{
|
||||||
|
result[i] = v2_sub(entity->vertexPoints[i], entity->offset);
|
||||||
|
result[i] = v2_add(result[i], entity->pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
math_applyRotationToVertexes(result[0], entity->offset,
|
||||||
|
DEGREES_TO_RADIANS(entity->rotation), result,
|
||||||
|
entity->numVertexPoints);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
177
src/Renderer.c
177
src/Renderer.c
@ -10,8 +10,8 @@
|
|||||||
|
|
||||||
typedef struct RenderQuad
|
typedef struct RenderQuad
|
||||||
{
|
{
|
||||||
Vertex vertex[4];
|
RenderVertex vertexList[4];
|
||||||
} RenderQuad_;
|
} RenderQuad;
|
||||||
|
|
||||||
// NOTE(doyle): A vertex batch is the batch of vertexes comprised to make one
|
// NOTE(doyle): A vertex batch is the batch of vertexes comprised to make one
|
||||||
// shape
|
// shape
|
||||||
@ -56,7 +56,8 @@ INTERNAL void endVertexBatch(Renderer *renderer)
|
|||||||
i32 freeVertexSlots = renderer->groupCapacity - group->vertexIndex;
|
i32 freeVertexSlots = renderer->groupCapacity - group->vertexIndex;
|
||||||
if (numDegenerateVertexes < freeVertexSlots)
|
if (numDegenerateVertexes < freeVertexSlots)
|
||||||
{
|
{
|
||||||
Vertex degenerateVertex = group->vertexList[group->vertexIndex-1];
|
RenderVertex degenerateVertex =
|
||||||
|
group->vertexList[group->vertexIndex - 1];
|
||||||
group->vertexList[group->vertexIndex++] = degenerateVertex;
|
group->vertexList[group->vertexIndex++] = degenerateVertex;
|
||||||
group->vertexList[group->vertexIndex++] = degenerateVertex;
|
group->vertexList[group->vertexIndex++] = degenerateVertex;
|
||||||
}
|
}
|
||||||
@ -65,8 +66,38 @@ INTERNAL void endVertexBatch(Renderer *renderer)
|
|||||||
renderer->groupIndexForVertexBatch = -1;
|
renderer->groupIndexForVertexBatch = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INTERNAL void applyRotationToVertexes(v2 pos, v2 pivotPoint, Radians rotate,
|
||||||
|
RenderVertex *vertexList,
|
||||||
|
i32 vertexListSize)
|
||||||
|
{
|
||||||
|
if (rotate == 0) return;
|
||||||
|
// 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 < vertexListSize; i++)
|
||||||
|
{
|
||||||
|
// NOTE(doyle): Manual matrix multiplication since vertex pos is 2D and
|
||||||
|
// matrix is 4D
|
||||||
|
v2 oldP = vertexList[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]);
|
||||||
|
|
||||||
|
vertexList[i].pos = newP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
INTERNAL void addVertexToRenderGroup_(Renderer *renderer, Texture *tex,
|
INTERNAL void addVertexToRenderGroup_(Renderer *renderer, Texture *tex,
|
||||||
v4 color, Vertex *vertexList,
|
v4 color, RenderVertex *vertexList,
|
||||||
i32 numVertexes,
|
i32 numVertexes,
|
||||||
enum RenderMode targetRenderMode,
|
enum RenderMode targetRenderMode,
|
||||||
RenderFlags flags)
|
RenderFlags flags)
|
||||||
@ -208,46 +239,17 @@ INTERNAL inline void flipTexCoord(v4 *texCoords, b32 flipX, b32 flipY)
|
|||||||
|
|
||||||
INTERNAL void bufferRenderGroupToGL(Renderer *renderer, RenderGroup *group)
|
INTERNAL void bufferRenderGroupToGL(Renderer *renderer, RenderGroup *group)
|
||||||
{
|
{
|
||||||
Vertex *vertexList = group->vertexList;
|
RenderVertex *vertexList = group->vertexList;
|
||||||
i32 numVertex = group->vertexIndex;
|
i32 numVertex = group->vertexIndex;
|
||||||
|
|
||||||
// TODO(doyle): We assume that vbo and vao are assigned
|
// TODO(doyle): We assume that vbo and vao are assigned
|
||||||
renderer->numVertexesInVbo = numVertex;
|
renderer->numVertexesInVbo = numVertex;
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo[group->mode]);
|
glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo[group->mode]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, numVertex * sizeof(Vertex), vertexList,
|
glBufferData(GL_ARRAY_BUFFER, numVertex * sizeof(RenderVertex), vertexList,
|
||||||
GL_STREAM_DRAW);
|
GL_STREAM_DRAW);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void applyRotationToVertexes(v2 pos, v2 pivotPoint, Radians rotate,
|
|
||||||
Vertex *vertexList, i32 vertexListSize)
|
|
||||||
{
|
|
||||||
if (rotate == 0) return;
|
|
||||||
// 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 < vertexListSize; i++)
|
|
||||||
{
|
|
||||||
// NOTE(doyle): Manual matrix multiplication since vertex pos is 2D and
|
|
||||||
// matrix is 4D
|
|
||||||
v2 oldP = vertexList[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]);
|
|
||||||
|
|
||||||
vertexList[i].pos = newP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERNAL v4 getTexRectNormaliseDeviceCoords(RenderTex renderTex)
|
INTERNAL v4 getTexRectNormaliseDeviceCoords(RenderTex renderTex)
|
||||||
{
|
{
|
||||||
/* Convert texture coordinates to normalised texture coordinates */
|
/* Convert texture coordinates to normalised texture coordinates */
|
||||||
@ -266,9 +268,9 @@ INTERNAL v4 getTexRectNormaliseDeviceCoords(RenderTex renderTex)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL RenderQuad_ createRenderQuad(Renderer *renderer, v2 pos, v2 size,
|
INTERNAL RenderQuad createRenderQuad(Renderer *renderer, v2 pos, v2 size,
|
||||||
v2 pivotPoint, Radians rotate,
|
v2 pivotPoint, Radians rotate,
|
||||||
RenderTex renderTex)
|
RenderTex renderTex)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Rendering order
|
* Rendering order
|
||||||
@ -291,33 +293,50 @@ INTERNAL RenderQuad_ createRenderQuad(Renderer *renderer, v2 pos, v2 size,
|
|||||||
// NOTE(doyle): Create a quad composed of 4 vertexes to be rendered as
|
// NOTE(doyle): Create a quad composed of 4 vertexes to be rendered as
|
||||||
// a triangle strip using vertices v0, v1, v2, then v2, v1, v3 (note the
|
// a triangle strip using vertices v0, v1, v2, then v2, v1, v3 (note the
|
||||||
// order)
|
// order)
|
||||||
RenderQuad_ result = {0};
|
v2 vertexList[4] = {0};
|
||||||
result.vertex[0].pos = V2(vertexPair.x, vertexPair.w); // Top left
|
v2 texCoordList[4] = {0};
|
||||||
result.vertex[0].texCoord = V2(texRectNdc.x, texRectNdc.w);
|
|
||||||
|
|
||||||
result.vertex[1].pos = V2(vertexPair.x, vertexPair.y); // Bottom left
|
// Top left
|
||||||
result.vertex[1].texCoord = V2(texRectNdc.x, texRectNdc.y);
|
vertexList[0] = V2(vertexPair.x, vertexPair.w);
|
||||||
|
texCoordList[0] = V2(texRectNdc.x, texRectNdc.w);
|
||||||
|
|
||||||
result.vertex[2].pos = V2(vertexPair.z, vertexPair.w); // Top right
|
// Bottom left
|
||||||
result.vertex[2].texCoord = V2(texRectNdc.z, texRectNdc.w);
|
vertexList[1] = V2(vertexPair.x, vertexPair.y);
|
||||||
|
texCoordList[1] = V2(texRectNdc.x, texRectNdc.y);
|
||||||
|
|
||||||
result.vertex[3].pos = V2(vertexPair.z, vertexPair.y); // Bottom right
|
// Top right
|
||||||
result.vertex[3].texCoord = V2(texRectNdc.z, texRectNdc.y);
|
vertexList[2] = V2(vertexPair.z, vertexPair.w);
|
||||||
|
texCoordList[2] = V2(texRectNdc.z, texRectNdc.w);
|
||||||
|
|
||||||
|
// Bottom right
|
||||||
|
vertexList[3] = V2(vertexPair.z, vertexPair.y);
|
||||||
|
texCoordList[3] = V2(texRectNdc.z, texRectNdc.y);
|
||||||
|
|
||||||
// NOTE(doyle): Precalculate rotation on vertex positions
|
// NOTE(doyle): Precalculate rotation on vertex positions
|
||||||
// NOTE(doyle): No translation/scale matrix as we pre-calculate it from
|
// 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
|
// entity data and work in world space until GLSL uses the projection matrix
|
||||||
applyRotationToVertexes(pos, pivotPoint, rotate, result.vertex,
|
|
||||||
ARRAY_COUNT(result.vertex));
|
math_applyRotationToVertexes(pos, pivotPoint, rotate, vertexList,
|
||||||
|
ARRAY_COUNT(vertexList));
|
||||||
|
|
||||||
|
RenderQuad result = {0};
|
||||||
|
|
||||||
|
ASSERT(ARRAY_COUNT(vertexList) == ARRAY_COUNT(result.vertexList));
|
||||||
|
for (i32 i = 0; i < ARRAY_COUNT(vertexList); i++)
|
||||||
|
{
|
||||||
|
result.vertexList[i].pos = vertexList[i];
|
||||||
|
result.vertexList[i].texCoord = texCoordList[i];
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL inline RenderQuad_
|
INTERNAL inline RenderQuad
|
||||||
createDefaultTexQuad(Renderer *renderer, RenderTex *renderTex)
|
createDefaultTexQuad(Renderer *renderer, RenderTex *renderTex)
|
||||||
{
|
{
|
||||||
RenderQuad_ result = {0};
|
RenderQuad result = {0};
|
||||||
result = createRenderQuad(renderer, V2(0, 0), V2(0, 0), V2(0, 0),
|
result = createRenderQuad(renderer, V2(0, 0), V2(0, 0), V2(0, 0), 0.0f,
|
||||||
0.0f, *renderTex);
|
*renderTex);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,12 +403,13 @@ void renderer_rect(Renderer *const renderer, Rect camera, v2 pos, v2 size,
|
|||||||
RenderTex emptyRenderTex = {0};
|
RenderTex emptyRenderTex = {0};
|
||||||
if (!renderTex) renderTex = &emptyRenderTex;
|
if (!renderTex) renderTex = &emptyRenderTex;
|
||||||
|
|
||||||
RenderQuad_ quad = createRenderQuad(renderer, posInCameraSpace, size,
|
RenderQuad quad = createRenderQuad(renderer, posInCameraSpace, size,
|
||||||
pivotPoint, rotate, *renderTex);
|
pivotPoint, rotate, *renderTex);
|
||||||
|
|
||||||
beginVertexBatch(renderer);
|
beginVertexBatch(renderer);
|
||||||
addVertexToRenderGroup_(renderer, renderTex->tex, color, quad.vertex,
|
addVertexToRenderGroup_(renderer, renderTex->tex, color, quad.vertexList,
|
||||||
ARRAY_COUNT(quad.vertex), rendermode_quad, flags);
|
ARRAY_COUNT(quad.vertexList), rendermode_quad,
|
||||||
|
flags);
|
||||||
endVertexBatch(renderer);
|
endVertexBatch(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +428,7 @@ void renderer_polygon(Renderer *const renderer, Rect camera,
|
|||||||
if (!renderTex) renderTex = &emptyRenderTex;
|
if (!renderTex) renderTex = &emptyRenderTex;
|
||||||
|
|
||||||
v2 triangulationBaseP = polygonPoints[0];
|
v2 triangulationBaseP = polygonPoints[0];
|
||||||
Vertex triangulationBaseVertex = {0};
|
RenderVertex triangulationBaseVertex = {0};
|
||||||
triangulationBaseVertex.pos = triangulationBaseP;
|
triangulationBaseVertex.pos = triangulationBaseP;
|
||||||
|
|
||||||
i32 numTrisInTriangulation = numPoints - 2;
|
i32 numTrisInTriangulation = numPoints - 2;
|
||||||
@ -418,13 +438,11 @@ void renderer_polygon(Renderer *const renderer, Rect camera,
|
|||||||
{
|
{
|
||||||
ASSERT((i + 1) < numPoints);
|
ASSERT((i + 1) < numPoints);
|
||||||
|
|
||||||
Vertex triangle[3] = {0};
|
RenderVertex triangle[3] = {0};
|
||||||
triangle[0].pos = triangulationBaseP;
|
triangle[0].pos = triangulationBaseP;
|
||||||
triangle[1].pos = polygonPoints[i];
|
triangle[1].pos = polygonPoints[i];
|
||||||
triangle[2].pos = polygonPoints[i + 1];
|
triangle[2].pos = polygonPoints[i + 1];
|
||||||
|
|
||||||
applyRotationToVertexes(triangulationBaseP, pivotPoint, rotate,
|
|
||||||
triangle, ARRAY_COUNT(triangle));
|
|
||||||
addVertexToRenderGroup_(renderer, renderTex->tex, color, triangle,
|
addVertexToRenderGroup_(renderer, renderTex->tex, color, triangle,
|
||||||
ARRAY_COUNT(triangle), rendermode_polygon,
|
ARRAY_COUNT(triangle), rendermode_polygon,
|
||||||
flags);
|
flags);
|
||||||
@ -453,8 +471,8 @@ void renderer_string(Renderer *const renderer, MemoryArena_ *arena, Rect camera,
|
|||||||
i32 vertexIndex = 0;
|
i32 vertexIndex = 0;
|
||||||
i32 numVertexPerQuad = 4;
|
i32 numVertexPerQuad = 4;
|
||||||
i32 numVertexesToAlloc = (strLen * (numVertexPerQuad + 2));
|
i32 numVertexesToAlloc = (strLen * (numVertexPerQuad + 2));
|
||||||
Vertex *vertexList =
|
RenderVertex *vertexList =
|
||||||
memory_pushBytes(arena, numVertexesToAlloc * sizeof(Vertex));
|
memory_pushBytes(arena, numVertexesToAlloc * sizeof(RenderVertex));
|
||||||
|
|
||||||
v2 posInCameraSpace = v2_sub(pos, camera.min);
|
v2 posInCameraSpace = v2_sub(pos, camera.min);
|
||||||
pos = posInCameraSpace;
|
pos = posInCameraSpace;
|
||||||
@ -480,13 +498,13 @@ void renderer_string(Renderer *const renderer, MemoryArena_ *arena, Rect camera,
|
|||||||
flipTexCoord(&charTexRect, FALSE, TRUE);
|
flipTexCoord(&charTexRect, FALSE, TRUE);
|
||||||
|
|
||||||
RenderTex renderTex = {tex, charTexRect};
|
RenderTex renderTex = {tex, charTexRect};
|
||||||
RenderQuad_ quad = createRenderQuad(renderer, pos, font->maxSize,
|
RenderQuad quad = createRenderQuad(renderer, pos, font->maxSize,
|
||||||
pivotPoint, rotate, renderTex);
|
pivotPoint, rotate, renderTex);
|
||||||
|
|
||||||
beginVertexBatch(renderer);
|
beginVertexBatch(renderer);
|
||||||
addVertexToRenderGroup_(renderer, tex, color, quad.vertex,
|
addVertexToRenderGroup_(renderer, tex, color, quad.vertexList,
|
||||||
ARRAY_COUNT(quad.vertex), rendermode_quad,
|
ARRAY_COUNT(quad.vertexList),
|
||||||
flags);
|
rendermode_quad, flags);
|
||||||
endVertexBatch(renderer);
|
endVertexBatch(renderer);
|
||||||
pos.x += metric.advance;
|
pos.x += metric.advance;
|
||||||
}
|
}
|
||||||
@ -531,24 +549,17 @@ void renderer_entity(Renderer *renderer, MemoryArena_ *transientArena,
|
|||||||
|
|
||||||
if (entity->renderMode == rendermode_quad)
|
if (entity->renderMode == rendermode_quad)
|
||||||
{
|
{
|
||||||
renderer_rect(renderer, camera, entity->pos, entity->size, pivotPoint,
|
renderer_rect(renderer, camera, entity->pos, entity->size,
|
||||||
totalRotation, &renderTex, color, flags);
|
v2_add(entity->offset, pivotPoint), totalRotation,
|
||||||
|
&renderTex, color, flags);
|
||||||
}
|
}
|
||||||
else if (entity->renderMode == rendermode_polygon)
|
else if (entity->renderMode == rendermode_polygon)
|
||||||
{
|
{
|
||||||
ASSERT(entity->numVertexPoints >= 3);
|
ASSERT(entity->numVertexPoints >= 3);
|
||||||
ASSERT(entity->vertexPoints);
|
ASSERT(entity->vertexPoints);
|
||||||
|
|
||||||
v2 *offsetVertexPoints = memory_pushBytes(
|
v2 *offsetVertexPoints =
|
||||||
transientArena, entity->numVertexPoints * sizeof(v2));
|
entity_createVertexList(transientArena, entity);
|
||||||
|
|
||||||
for (i32 i = 0; i < entity->numVertexPoints; i++)
|
|
||||||
{
|
|
||||||
offsetVertexPoints[i] =
|
|
||||||
v2_add(entity->vertexPoints[i], entity->offset);
|
|
||||||
offsetVertexPoints[i] = v2_add(offsetVertexPoints[i], entity->pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderer_polygon(renderer, camera, offsetVertexPoints,
|
renderer_polygon(renderer, camera, offsetVertexPoints,
|
||||||
entity->numVertexPoints,
|
entity->numVertexPoints,
|
||||||
v2_add(entity->offset, pivotPoint), totalRotation,
|
v2_add(entity->offset, pivotPoint), totalRotation,
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "Dengine/Renderer.h"
|
#include "Dengine/Renderer.h"
|
||||||
|
|
||||||
typedef struct AudioRenderer AudioRenderer;
|
typedef struct AudioRenderer AudioRenderer;
|
||||||
|
typedef struct MemoryArena_ MemoryArena;
|
||||||
|
|
||||||
enum Direction
|
enum Direction
|
||||||
{
|
{
|
||||||
@ -66,8 +67,6 @@ typedef struct Entity
|
|||||||
f32 scale;
|
f32 scale;
|
||||||
Degrees rotation;
|
Degrees rotation;
|
||||||
|
|
||||||
b32 invisible;
|
|
||||||
|
|
||||||
enum EntityType type;
|
enum EntityType type;
|
||||||
enum Direction direction;
|
enum Direction direction;
|
||||||
|
|
||||||
@ -95,4 +94,6 @@ void entity_setActiveAnim(Entity *const entity, const char *const animName);
|
|||||||
void entity_updateAnim(Entity *const entity, const f32 dt);
|
void entity_updateAnim(Entity *const entity, const f32 dt);
|
||||||
void entity_addAnim(AssetManager *const assetManager, Entity *const entity,
|
void entity_addAnim(AssetManager *const assetManager, Entity *const entity,
|
||||||
const char *const animName);
|
const char *const animName);
|
||||||
|
|
||||||
|
v2 *entity_createVertexList(MemoryArena_ *transientArena, Entity *entity);
|
||||||
#endif
|
#endif
|
||||||
|
@ -367,4 +367,37 @@ INTERNAL inline v2 math_getRectSize(v4 rect)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INTERNAL inline void math_applyRotationToVertexes(v2 pos, v2 pivotPoint,
|
||||||
|
Radians rotate,
|
||||||
|
v2 *vertexList,
|
||||||
|
i32 vertexListSize)
|
||||||
|
{
|
||||||
|
if (rotate == 0) return;
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
// TODO(doyle): Make it nice for 2d vector, stop using mat4
|
||||||
|
for (i32 i = 0; i < vertexListSize; i++)
|
||||||
|
{
|
||||||
|
// NOTE(doyle): Manual matrix multiplication since vertex pos is 2D and
|
||||||
|
// matrix is 4D
|
||||||
|
v2 oldP = vertexList[i];
|
||||||
|
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]);
|
||||||
|
|
||||||
|
vertexList[i] = newP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -13,11 +13,11 @@ typedef struct MemoryArena MemoryArena_;
|
|||||||
typedef struct Shader Shader;
|
typedef struct Shader Shader;
|
||||||
typedef struct Texture Texture;
|
typedef struct Texture Texture;
|
||||||
|
|
||||||
typedef struct Vertex
|
typedef struct RenderVertex
|
||||||
{
|
{
|
||||||
v2 pos;
|
v2 pos;
|
||||||
v2 texCoord;
|
v2 texCoord;
|
||||||
} Vertex;
|
} RenderVertex;
|
||||||
|
|
||||||
typedef struct RenderTex
|
typedef struct RenderTex
|
||||||
{
|
{
|
||||||
@ -51,7 +51,7 @@ typedef struct RenderGroup
|
|||||||
Texture *tex;
|
Texture *tex;
|
||||||
v4 color;
|
v4 color;
|
||||||
|
|
||||||
Vertex *vertexList;
|
RenderVertex *vertexList;
|
||||||
i32 vertexIndex;
|
i32 vertexIndex;
|
||||||
|
|
||||||
} RenderGroup;
|
} RenderGroup;
|
||||||
@ -82,9 +82,7 @@ typedef struct Renderer
|
|||||||
} Renderer;
|
} Renderer;
|
||||||
|
|
||||||
|
|
||||||
// TODO(doyle): Use z-index occluding for rendering
|
RenderTex renderer_createNullRenderTex(AssetManager *const assetManager);
|
||||||
RenderTex
|
|
||||||
renderer_createNullRenderTex(AssetManager *const assetManager);
|
|
||||||
|
|
||||||
// TODO(doyle): Clean up lines
|
// TODO(doyle): Clean up lines
|
||||||
// Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); }
|
// Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); }
|
||||||
|
Loading…
Reference in New Issue
Block a user