Fix triangle rendering and wireframe

This commit is contained in:
Doyle Thai 2016-11-16 13:00:59 +11:00
parent 339ae38b38
commit 21bf650298
8 changed files with 210 additions and 127 deletions

View File

@ -42,10 +42,7 @@ void initAssetManager(GameState *state)
i32 result =
asset_loadTTFont(assetManager, arena, "C:/Windows/Fonts/Arialbd.ttf");
if (result) {
ASSERT(TRUE);
}
if (result) ASSERT(TRUE);
}
void initRenderer(GameState *state, v2 windowSize) {
@ -76,11 +73,12 @@ void initRenderer(GameState *state, v2 windowSize) {
glGenBuffers(ARRAY_COUNT(renderer->vbo), renderer->vbo);
GL_CHECK_ERROR();
// Bind buffers and configure vao, vao automatically intercepts
// glBindCalls and associates the state with that buffer for us
for (enum RenderMode mode = 0; mode < rendermode_count; mode++)
{
// Bind buffers and configure vao, vao automatically intercepts
// glBindCalls and associates the state with that buffer for us
glBindVertexArray(renderer->vao[rendermode_quad]);
glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo[rendermode_quad]);
glBindVertexArray(renderer->vao[mode]);
glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo[mode]);
glEnableVertexAttribArray(0);
u32 numVertexElements = 4;
@ -92,20 +90,6 @@ void initRenderer(GameState *state, v2 windowSize) {
glBindVertexArray(0);
}
{
glBindVertexArray(renderer->vao[rendermode_triangle]);
glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo[rendermode_triangle]);
glEnableVertexAttribArray(0);
u32 numVertexElements = 3;
u32 stride = sizeof(Vertex);
glVertexAttribPointer(0, numVertexElements, GL_FLOAT,
GL_FALSE, stride, (GLvoid *)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
/* Unbind */
GL_CHECK_ERROR();
@ -183,37 +167,44 @@ INTERNAL b32 getKeyStatus(KeyState *key, enum ReadKeyType readType,
void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
v2 windowSize, f32 dt)
{
if (!state->init) {
if (!state->init)
{
memory_arenaInit(&state->persistentArena, memory->persistent,
memory->persistentSize);
memory_arenaInit(&state->transientArena, memory->transient,
memory->transientSize);
initAssetManager(state);
initRenderer(state, windowSize);
state->pixelsPerMeter = 70.0f;
{ // Init ship entity
Entity *ship = &state->entityList[state->entityIndex++];
ship->id = 0;
ship->pos = V2(100.0f, 100.0f);
ship->hitbox = V2(100.0f, 100.0f);
ship->size = V2(100.0f, 100.0f);
ship->scale = 1;
ship->type = entitytype_ship;
ship->direction = direction_null;
ship->tex = NULL;
ship->collides = FALSE;
Entity *ship = &state->entityList[state->entityIndex++];
ship->id = 0;
ship->pos = V2(100, 100);
ship->size = V2(25.0f, 50.0f);
ship->hitbox = ship->size;
ship->offset = v2_scale(ship->size, 0.5f);
ship->scale = 1;
ship->type = entitytype_ship;
ship->direction = direction_null;
ship->renderMode = rendermode_triangle;
ship->tex = NULL;
ship->collides = FALSE;
}
state->camera.pos = V2(0, 0);
state->camera.pos = V2(0, 0);
state->camera.size = state->renderer.size;
state->init = TRUE;
state->worldSize = windowSize;
state->init = TRUE;
debug_init(&state->persistentArena, windowSize,
state->assetManager.font);
}
memory_arenaInit(&state->transientArena, memory->transient,
memory->transientSize);
{
KeyState *keys = state->input.keys;
for (enum KeyCode code = 0; code < keycode_count; code++)
@ -244,40 +235,40 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
Entity *entity = &state->entityList[i];
ASSERT(entity->type != entitytype_invalid);
v2 pivotPoint = {0};
if (entity->type == entitytype_ship) {
v2 acceleration = {0};
v2 ddP = {0};
if (getKeyStatus(&state->input.keys[keycode_up], readkeytype_repeat,
0.0f, dt))
{
acceleration.y = 1.0f;
}
// TODO(doyle): Renderer creates upfacing triangles by default,
// but we need to offset rotation so that our base "0 degrees"
// is right facing for trig to work
Radians rotation = DEGREES_TO_RADIANS((entity->rotation + 90.0f));
v2 direction = V2(math_cosf(rotation), math_sinf(rotation));
if (getKeyStatus(&state->input.keys[keycode_down],
readkeytype_repeat, 0.0f, dt))
{
acceleration.y = -1.0f;
ddP = v2_normalise(direction);
}
if (getKeyStatus(&state->input.keys[keycode_left],
readkeytype_repeat, 0.0f, dt))
{
acceleration.x = -1.0f;
entity->rotation += (120.0f) * dt;
}
if (getKeyStatus(&state->input.keys[keycode_right],
readkeytype_repeat, 0.0f, dt))
{
acceleration.x = 1.0f;
entity->rotation -= (120.0f) * dt;
}
if (acceleration.x != 0.0f && acceleration.y != 0.0f)
if (ddP.x != 0.0f && ddP.y != 0.0f)
{
// NOTE(doyle): Cheese it and pre-compute the vector for
// diagonal using pythagoras theorem on a unit triangle 1^2
// + 1^2 = c^2
acceleration = v2_scale(acceleration, 0.70710678118f);
ddP = v2_scale(ddP, 0.70710678118f);
}
/*
@ -285,41 +276,77 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
newVelocity = a*t + oldVelocity
newPos = (a*t^2)/2 + oldVelocity*t + oldPos
*/
acceleration = v2_scale(acceleration, state->pixelsPerMeter * 25);
ddP = v2_scale(ddP, state->pixelsPerMeter * 25);
v2 oldVelocity = entity->velocity;
v2 resistance = v2_scale(oldVelocity, 4.0f);
acceleration = v2_sub(acceleration, resistance);
v2 oldDp = entity->dP;
v2 resistance = v2_scale(oldDp, 2.0f);
ddP = v2_sub(ddP, resistance);
entity->velocity = v2_add(v2_scale(acceleration, dt), oldVelocity);
entity->dP = v2_add(v2_scale(ddP, dt), oldDp);
v2 halfAcceleration = v2_scale(acceleration, 0.5f);
v2 halfAccelerationDtSquared =
v2_scale(halfAcceleration, (SQUARED(dt)));
v2 oldVelocityDt = v2_scale(oldVelocity, dt);
v2 oldPos = entity->pos;
entity->pos = v2_add(
v2_add(halfAccelerationDtSquared, oldVelocityDt), oldPos);
v2 ddPHalf = v2_scale(ddP, 0.5f);
v2 ddPHalfDtSquared = v2_scale(ddPHalf, (SQUARED(dt)));
v2 oldDpDt = v2_scale(oldDp, dt);
v2 oldPos = entity->pos;
entity->pos = v2_add(v2_add(ddPHalfDtSquared, oldDpDt), oldPos);
pivotPoint = v2_scale(entity->size, 0.5f);
}
RenderFlags flags = renderflag_wireframe;
renderer_entity(&state->renderer, state->camera, entity, V2(0, 0),
0, V4(0.4f, 0.8f, 1.0f, 1.0f), flags);
if (entity->pos.y >= state->worldSize.h)
{
entity->pos.y = 0;
}
else if (entity->pos.y < 0)
{
entity->pos.y = state->worldSize.h;
}
if (entity->pos.x >= state->worldSize.w)
{
entity->pos.x = 0;
}
else if (entity->pos.x < 0)
{
entity->pos.x = state->worldSize.w;
}
DEBUG_PUSH_VAR("Pos: %5.2f, %5.2f", entity->pos, "v2");
DEBUG_PUSH_VAR("Velocity: %5.2f, %5.2f", entity->dP, "v2");
DEBUG_PUSH_VAR("Rotation: %5.2f", entity->rotation, "f32");
RenderFlags flags = renderflag_wireframe | renderflag_no_texture;
renderer_entity(&state->renderer, state->camera, entity, pivotPoint, 0,
V4(0.4f, 0.8f, 1.0f, 1.0f), flags);
v2 rightAlignedP = v2_add(entity->pos, entity->hitbox);
renderer_rect(&state->renderer, state->camera, rightAlignedP, V2(10, 10),
V2(0, 0), DEGREES_TO_RADIANS(entity->rotation), NULL,
V4(0.4f, 0.8f, 1.0f, 1.0f), flags);
v2 leftAlignedP = entity->pos;
renderer_rect(&state->renderer, state->camera, leftAlignedP, V2(10, 10),
V2(0, 0), DEGREES_TO_RADIANS(entity->rotation), NULL,
V4(0.4f, 0.8f, 1.0f, 1.0f), flags);
}
TrianglePoints triangle = {0};
triangle.points[0] = V2(100, 200);
triangle.points[2] = V2(100, 300);
triangle.points[1] = V2(200, 100);
triangle.points[2] = V2(100, 300);
LOCAL_PERSIST Radians rotation = 0.0f;
rotation += DEGREES_TO_RADIANS(((60.0f) * dt));
RenderFlags flags = renderflag_wireframe;
RenderFlags flags = renderflag_wireframe | renderflag_no_texture;
renderer_triangle(&state->renderer, state->camera, triangle, V2(0, 0),
rotation, NULL, V4(1, 1, 1, 1), flags);
debug_drawUi(state, dt);
debug_clearCounter();
renderer_renderGroups(&state->renderer);
}

View File

@ -30,7 +30,7 @@ GLOBAL_VAR DebugState GLOBAL_debug;
void debug_init(MemoryArena_ *arena, v2 windowSize, Font font)
{
GLOBAL_debug.font = font;
GLOBAL_debug.font = font;
GLOBAL_debug.callCount =
memory_pushBytes(arena, debugcount_num * sizeof(i32));
GLOBAL_debug.stringLineGap = CAST(f32) font.verticalSpacing;
@ -228,7 +228,7 @@ INTERNAL void updateAndRenderDebugStack(Renderer *renderer, MemoryArena_ *arena,
for (i32 i = 0; i < GLOBAL_debug.numDebugStrings; i++)
{
f32 rotate = 0;
v4 color = V4(0, 0, 0, 1);
v4 color = V4(1, 1, 1, 1);
renderer_staticString(
renderer, arena, &GLOBAL_debug.font, GLOBAL_debug.debugStrings[i],
GLOBAL_debug.currStringP, V2(0, 0), rotate, color, 0);
@ -270,5 +270,7 @@ INTERNAL void renderConsole(Renderer *renderer, MemoryArena_ *arena)
void debug_drawUi(GameState *state, f32 dt)
{
updateAndRenderDebugStack(&state->renderer, &state->transientArena, dt);
renderConsole(&state->renderer, &state->transientArena);
debug_clearCounter();
}

View File

@ -75,7 +75,7 @@ INTERNAL void addVertexToRenderGroup(Renderer *renderer, Texture *tex, v4 color,
// NOTE(doyle): Mark first vertex as degenerate vertex, but where we
// request wireframe mode- we can't use degenerate vertexes for line
// mode
if (!(flags & renderflag_wireframe)) group->vertexIndex++;
group->vertexIndex++;
group->init = TRUE;
group->tex = tex;
group->color = color;
@ -158,6 +158,7 @@ INTERNAL void bufferRenderGroupToGL(Renderer *renderer, RenderGroup *group)
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.
@ -238,7 +239,6 @@ INTERNAL RenderQuad_ createRenderQuad(Renderer *renderer, v2 pos, v2 size,
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
@ -266,7 +266,6 @@ INTERNAL RenderTriangle_ createRenderTriangle(Renderer *renderer,
result.vertex[2].pos = triangle.points[2];
result.vertex[2].texCoord = V2(texRectNdc.z, texRectNdc.w);
if (rotate == 0) return result;
applyRotationToVertexes(triangle.points[0], pivotPoint, rotate,
result.vertex, ARRAY_COUNT(result.vertex));
@ -286,35 +285,38 @@ INTERNAL void renderGLBufferedData(Renderer *renderer, RenderGroup *group)
{
ASSERT(group->mode < rendermode_invalid);
u32 drawMethod = GL_TRIANGLE_STRIP;
if (group->flags & renderflag_wireframe)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
GL_CHECK_ERROR();
if (group->flags & renderflag_no_texture)
{
drawMethod = GL_LINE_LOOP;
renderer->activeShaderId =
renderer->shaderList[shaderlist_default_no_tex];
shader_use(renderer->activeShaderId);
}
else
{
renderer->activeShaderId = renderer->shaderList[shaderlist_default];
shader_use(renderer->activeShaderId);
Texture *tex = group->tex;
if (tex)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex->id);
shader_uniformSet1i(renderer->activeShaderId, "tex", 0);
GL_CHECK_ERROR();
}
}
shader_use(renderer->activeShaderId);
/* Set color modulation value */
shader_uniformSetVec4f(renderer->activeShaderId, "spriteColor",
group->color);
GL_CHECK_ERROR();
Texture *tex = group->tex;
if (tex)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex->id);
shader_uniformSet1i(renderer->activeShaderId, "tex", 0);
}
glBindVertexArray(renderer->vao[group->mode]);
glDrawArrays(drawMethod, 0, renderer->numVertexesInVbo);
glDrawArrays(GL_TRIANGLE_STRIP, 0, renderer->numVertexesInVbo);
GL_CHECK_ERROR();
debug_countIncrement(debugcount_drawArrays);
@ -322,6 +324,7 @@ INTERNAL void renderGLBufferedData(Renderer *renderer, RenderGroup *group)
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
GL_CHECK_ERROR();
}
RenderTex renderer_createNullRenderTex(AssetManager *const assetManager)
@ -344,44 +347,33 @@ void renderer_rect(Renderer *const renderer, Rect camera, v2 pos, v2 size,
RenderQuad_ quad = createRenderQuad(renderer, posInCameraSpace, size,
pivotPoint, rotate, *renderTex);
// addRenderQuadToRenderGroup
if (flags & renderflag_wireframe)
{
Vertex vertexList[4] = {quad.vertex[0], quad.vertex[1], quad.vertex[3],
quad.vertex[2]};
addVertexToRenderGroup(renderer, renderTex->tex, color, vertexList,
ARRAY_COUNT(vertexList), rendermode_quad,
flags);
}
else
{
/*
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.
/*
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.
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.
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.
*/
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, color, vertexList,
ARRAY_COUNT(vertexList), rendermode_quad, flags);
}
}
void renderer_triangle(Renderer *const renderer, Rect camera,
@ -401,9 +393,13 @@ void renderer_triangle(Renderer *const renderer, Rect camera,
RenderTriangle_ renderTriangle = createRenderTriangle(
renderer, triangleInCamSpace, pivotPoint, rotate, *renderTex);
addVertexToRenderGroup(
renderer, renderTex->tex, color, renderTriangle.vertex,
ARRAY_COUNT(renderTriangle.vertex), rendermode_triangle, flags);
// NOTE(doyle): Create degenerate vertex setup
Vertex vertexList[5] = {renderTriangle.vertex[0], renderTriangle.vertex[0],
renderTriangle.vertex[1], renderTriangle.vertex[2],
renderTriangle.vertex[2]};
addVertexToRenderGroup(renderer, renderTex->tex, color, vertexList,
ARRAY_COUNT(vertexList), rendermode_triangle, flags);
}
void renderer_string(Renderer *const renderer, MemoryArena_ *arena, Rect camera,
@ -474,7 +470,7 @@ void renderer_string(Renderer *const renderer, MemoryArena_ *arena, Rect camera,
}
void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
v2 pivotPoint, Radians rotate, v4 color, RenderFlags flags)
v2 pivotPoint, Degrees rotate, v4 color, RenderFlags flags)
{
// TODO(doyle): Batch into render groups
@ -518,8 +514,36 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
renderTex.texRect = texRect;
}
renderer_rect(renderer, camera, entity->pos, entity->size, pivotPoint,
entity->rotation + rotate, &renderTex, color, flags);
Radians totalRotation = DEGREES_TO_RADIANS((entity->rotation + rotate));
if (entity->renderMode == rendermode_quad)
{
renderer_rect(renderer, camera, entity->pos, entity->size,
pivotPoint, totalRotation, &renderTex,
color, flags);
}
else if (entity->renderMode == rendermode_triangle)
{
TrianglePoints triangle = {0};
v2 entityPWithOffset = v2_add(entity->pos, entity->offset);
v2 triangleTopPoint =
V2(entityPWithOffset.x + (entity->size.w * 0.5f),
entityPWithOffset.y + entity->size.h);
v2 triangleRightSide =
V2(entityPWithOffset.x + entity->size.w, entityPWithOffset.y);
triangle.points[0] = entityPWithOffset;
triangle.points[1] = triangleRightSide;
triangle.points[2] = triangleTopPoint;
renderer_triangle(renderer, camera, triangle, pivotPoint,
totalRotation, &renderTex, color, flags);
}
else
{
ASSERT(INVALID_CODE_PATH);
}
}
}

View File

@ -15,6 +15,8 @@ typedef struct GameState {
i32 entityIndex;
f32 pixelsPerMeter;
v2 worldSize;
Rect camera;
AssetManager assetManager;

View File

@ -27,6 +27,7 @@ void debug_recursivePrintXmlTree(XmlNode *root, i32 levelsDeep);
void debug_countIncrement(enum DebugCount id);
void debug_clearCounter();
#define DEBUG_LOG(string) debug_consoleLog(string, __FILE__, __LINE__);
void debug_consoleLog(char *string, char *file, int lineNum);

View File

@ -3,6 +3,7 @@
#include "Dengine/Assets.h"
#include "Dengine/Common.h"
#include "Dengine/Renderer.h"
typedef struct AudioRenderer AudioRenderer;
@ -40,12 +41,16 @@ typedef struct Entity
i32 numChilds;
v2 pos;
v2 velocity;
v2 dP;
v2 hitbox;
v2 size;
v2 offset;
enum RenderMode renderMode;
f32 scale;
f32 rotation;
Degrees rotation;
b32 invisible;

View File

@ -7,11 +7,12 @@
#define MATH_PI 3.14159265359f
#define SQUARED(x) (x * x)
#define ABS(x) ((x) > 0 ? (x) : -(x))
#define DEGREES_TO_RADIANS(x) (x * (MATH_PI / 180.0f))
#define RADIANS_TO_DEGREES(x) (x * (180.0f / MATH_PI))
#define DEGREES_TO_RADIANS(x) ((x * (MATH_PI / 180.0f)))
#define RADIANS_TO_DEGREES(x) ((x * (180.0f / MATH_PI)))
#define SQRT(x) (sqrtf(x))
typedef f32 Radians;
typedef f32 Degrees;
INTERNAL inline f32 math_acosf(f32 a)
{
@ -19,12 +20,31 @@ INTERNAL inline f32 math_acosf(f32 a)
return result;
}
INTERNAL inline Radians math_cosf(Radians a)
{
Radians result = cosf(a);
return result;
}
INTERNAL inline Radians math_sinf(Radians a)
{
Radians result = sinf(a);
return result;
}
INTERNAL inline f32 math_atan2f(f32 y, f32 x)
{
f32 result = atan2f(y, x);
return result;
}
INTERNAL inline f32 math_tanf(Radians angle)
{
f32 result = tanf(angle);
return result;
}
/* VECTORS */
typedef union v2
{

View File

@ -32,6 +32,7 @@ typedef struct TrianglePoints {
typedef u32 RenderFlags;
enum RenderFlag {
renderflag_wireframe = 0x1,
renderflag_no_texture = 0x2,
};
enum RenderMode
@ -47,6 +48,7 @@ typedef struct RenderGroup
b32 init;
RenderFlags flags;
enum RenderMode mode;
u32 glRenderMode;
Texture *tex;
v4 color;
@ -112,7 +114,7 @@ inline void renderer_staticString(Renderer *const renderer, MemoryArena_ *arena,
}
void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
v2 pivotPoint, Radians rotate, v4 color,
v2 pivotPoint, Degrees rotate, v4 color,
RenderFlags flags);
void renderer_renderGroups(Renderer *renderer);