diff --git a/src/Asteroid.c b/src/Asteroid.c index b8895ea..2034c11 100644 --- a/src/Asteroid.c +++ b/src/Asteroid.c @@ -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); } diff --git a/src/Debug.c b/src/Debug.c index 1b6afa3..64ac6d2 100644 --- a/src/Debug.c +++ b/src/Debug.c @@ -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(); } diff --git a/src/Renderer.c b/src/Renderer.c index e15ea6e..ded7d88 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -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); + } } } diff --git a/src/include/Dengine/Asteroid.h b/src/include/Dengine/Asteroid.h index 3a9b6b4..401efa2 100644 --- a/src/include/Dengine/Asteroid.h +++ b/src/include/Dengine/Asteroid.h @@ -15,6 +15,8 @@ typedef struct GameState { i32 entityIndex; f32 pixelsPerMeter; + v2 worldSize; + Rect camera; AssetManager assetManager; diff --git a/src/include/Dengine/Debug.h b/src/include/Dengine/Debug.h index 7c88e29..ba117d5 100644 --- a/src/include/Dengine/Debug.h +++ b/src/include/Dengine/Debug.h @@ -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); diff --git a/src/include/Dengine/Entity.h b/src/include/Dengine/Entity.h index 8667824..3682147 100644 --- a/src/include/Dengine/Entity.h +++ b/src/include/Dengine/Entity.h @@ -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; diff --git a/src/include/Dengine/Math.h b/src/include/Dengine/Math.h index 650f3ff..5d75a94 100644 --- a/src/include/Dengine/Math.h +++ b/src/include/Dengine/Math.h @@ -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 { diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h index c65a60f..6a292c8 100644 --- a/src/include/Dengine/Renderer.h +++ b/src/include/Dengine/Renderer.h @@ -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);