diff --git a/data/blackboard.art b/data/blackboard.art index 61c8d0c..4f8a217 100644 Binary files a/data/blackboard.art and b/data/blackboard.art differ diff --git a/src/Asteroid.c b/src/Asteroid.c index 758dead..c0c2863 100644 --- a/src/Asteroid.c +++ b/src/Asteroid.c @@ -163,10 +163,146 @@ INTERNAL b32 getKeyStatus(KeyState *key, enum ReadKeyType readType, return FALSE; } +typedef struct Basis +{ + v2 basis; + v2 pivotPoint; +} Basis; +enum RectBaseline +{ + rectbaseline_top, + rectbaseline_topLeft, + rectbaseline_topRight, + rectbaseline_bottom, + rectbaseline_bottomRight, + rectbaseline_bottomLeft, + rectbaseline_left, + rectbaseline_right, + rectbaseline_center, + rectbaseline_count, + +}; + +Basis getBasis(Entity *entity, enum RectBaseline baseline) +{ + ASSERT(baseline < rectbaseline_count); + + v2 basis = v2_sub(entity->pos, entity->offset); + v2 pivotPoint = v2_scale(entity->size, 0.5f); + v2 size = entity->size; + switch (baseline) + { + case rectbaseline_top: + basis.y += (size.h); + basis.x += (size.w * 0.5f); + break; + case rectbaseline_topLeft: + basis.y += (size.h); + break; + case rectbaseline_topRight: + basis.y += (size.h); + basis.x += (size.w); + break; + case rectbaseline_bottom: + basis.x += (size.w * 0.5f); + break; + case rectbaseline_bottomRight: + basis.x += (size.w); + break; + case rectbaseline_left: + basis.y += (size.h * 0.5f); + break; + case rectbaseline_right: + basis.x += (size.w); + basis.y += (size.h * 0.5f); + break; + + case rectbaseline_bottomLeft: + break; + default: + DEBUG_LOG( + "getPosRelativeToRect() warning: baseline enum not recognised"); + break; + } + + Basis result = {0}; + result.basis = basis; + result.pivotPoint = pivotPoint; + + return result; +} + +Basis getDefaultBasis(Entity *entity) +{ + Basis result = getBasis(entity, rectbaseline_bottomLeft); + return result; +} + +#include +#include +v2 *createAsteroidVertexList(MemoryArena_ *arena, v2 pos, i32 iterations) +{ + f32 iterationAngle = 360.0f / iterations; + iterationAngle = DEGREES_TO_RADIANS(iterationAngle); + v2 *result = + memory_pushBytes(arena, iterations * sizeof(v2)); + + srand(time(NULL)); + for (i32 i = 0; i < iterations; i++) + { + i32 randValue = rand(); + i32 asteroidRadius = (randValue % 100) + 50; + + result[i] = V2(math_cosf(iterationAngle * i) * asteroidRadius, + math_sinf(iterationAngle * i) * asteroidRadius); + result[i] = v2_add(result[i], pos); + +#if 1 + f32 displacementDist = 0.25f * asteroidRadius; + i32 vertexDisplacement = + randValue % (i32)displacementDist + (i32)(displacementDist * 0.1f); + + i32 quadrantSize = iterations / 4; + + i32 firstQuadrant = quadrantSize; + i32 secondQuadrant = quadrantSize * 2; + i32 thirdQuadrant = quadrantSize * 3; + i32 fourthQuadrant = quadrantSize * 4; + + if (i < firstQuadrant) + { + result[i].x += vertexDisplacement; + result[i].y += vertexDisplacement; + } + else if (i < secondQuadrant) + { + result[i].x -= vertexDisplacement; + result[i].y += vertexDisplacement; + } + else if (i < thirdQuadrant) + { + result[i].x -= vertexDisplacement; + result[i].y -= vertexDisplacement; + } + else + { + result[i].x += vertexDisplacement; + result[i].y -= vertexDisplacement; + } +#endif + } + + return result; +} + +LOCAL_PERSIST v2 *asteroidVertexList = NULL; +LOCAL_PERSIST f32 updateAsteroidListTimerThreshold = 1.0f; +LOCAL_PERSIST f32 updateAsteroidListTimer = 1.0f; void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, v2 windowSize, f32 dt) { + i32 iterations = 16; if (!state->init) { @@ -200,11 +336,22 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, debug_init(&state->persistentArena, windowSize, state->assetManager.font); + + asteroidVertexList = + createAsteroidVertexList(&state->persistentArena, V2(500, 500), 16); } memory_arenaInit(&state->transientArena, memory->transient, memory->transientSize); + updateAsteroidListTimer -= dt; + if (updateAsteroidListTimer < 0) + { + asteroidVertexList = createAsteroidVertexList(&state->persistentArena, + V2(500, 500), iterations); + updateAsteroidListTimer = updateAsteroidListTimerThreshold; + } + { KeyState *keys = state->input.keys; for (enum KeyCode code = 0; code < keycode_count; code++) @@ -236,8 +383,20 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, ASSERT(entity->type != entitytype_invalid); v2 pivotPoint = {0}; - if (entity->type == entitytype_ship) { + // Loop entity around world + 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; + + if (entity->type == entitytype_ship) + { v2 ddP = {0}; if (getKeyStatus(&state->input.keys[keycode_up], readkeytype_repeat, 0.0f, dt)) @@ -245,9 +404,11 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, // 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)); - ddP = direction; + Radians rotation = + DEGREES_TO_RADIANS((entity->rotation + 90.0f)); + + v2 direction = V2(math_cosf(rotation), math_sinf(rotation)); + ddP = direction; } if (getKeyStatus(&state->input.keys[keycode_left], @@ -293,47 +454,27 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, entity->pos = v2_add(v2_add(ddPHalfDtSquared, oldDpDt), oldPos); pivotPoint = v2_scale(entity->size, 0.5f); + + 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); + + Basis entityBasis = getDefaultBasis(entity); + renderer_rect(&state->renderer, state->camera, entityBasis.basis, + V2(4, 4), entityBasis.pivotPoint, + DEGREES_TO_RADIANS(entity->rotation), NULL, + V4(1.0f, 0, 0, 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 leftAlignedP = v2_sub(entity->pos, entity->offset); - renderer_rect(&state->renderer, state->camera, leftAlignedP, - entity->size, v2_scale(entity->size, 0.5f), - DEGREES_TO_RADIANS(entity->rotation), NULL, - V4(1.0f, 0.8f, 1.0f, 1.0f), flags); - - v2 rightAlignedP = v2_add(leftAlignedP, entity->size); - renderer_rect(&state->renderer, state->camera, rightAlignedP, V2(4, 4), - v2_scale(pivotPoint, -1.0f), - DEGREES_TO_RADIANS(entity->rotation), NULL, - V4(0.4f, 0.8f, 1.0f, 1.0f), flags); } + renderer_polygon(&state->renderer, &state->transientArena, state->camera, + asteroidVertexList, iterations, V2(0, 0), 0, NULL, + V4(0.0f, 0.0f, 1.0f, 1.0f), 0); + TrianglePoints triangle = {0}; triangle.points[0] = V2(100, 200); triangle.points[1] = V2(200, 100); diff --git a/src/Renderer.c b/src/Renderer.c index 61785fa..be78ff5 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -376,6 +376,52 @@ void renderer_rect(Renderer *const renderer, Rect camera, v2 pos, v2 size, ARRAY_COUNT(vertexList), rendermode_quad, flags); } +void renderer_polygon(Renderer *const renderer, MemoryArena_ *arena, Rect camera, + v2 *polygonPoints, i32 numPoints, v2 pivotPoint, + Radians rotate, RenderTex *renderTex, v4 color, + RenderFlags flags) +{ + ASSERT(numPoints > 3); + + for (i32 i = 0; i < numPoints; i++) + polygonPoints[i] = v2_sub(polygonPoints[i], camera.min); + + RenderTex emptyRenderTex = {0}; + if (!renderTex) renderTex = &emptyRenderTex; + + i32 numTrisInTriangulation = numPoints - 2; + RenderTriangle_ *polygonTriangulation = memory_pushBytes( + arena, (sizeof(RenderTriangle_) * numTrisInTriangulation)); + + v2 triangulationBaseP = polygonPoints[0]; + i32 triangulationIndex = 0; + + Vertex triangulationBaseVertex = {0}; + triangulationBaseVertex.pos = triangulationBaseP; + + addVertexToRenderGroup(renderer, renderTex->tex, color, + &triangulationBaseVertex, 1, rendermode_polygon, + flags); + for (i32 i = 1; triangulationIndex < numTrisInTriangulation; i++) + { + RenderTriangle_ *tri = &polygonTriangulation[triangulationIndex++]; + tri->vertex[0].pos = triangulationBaseP; + tri->vertex[1].pos = polygonPoints[i + 1]; + tri->vertex[2].pos = polygonPoints[i]; + + addVertexToRenderGroup(renderer, renderTex->tex, color, tri->vertex, 3, + rendermode_polygon, flags); + } + RenderTriangle_ tri = polygonTriangulation[numTrisInTriangulation-1]; + addVertexToRenderGroup(renderer, renderTex->tex, color, &tri.vertex[2], 1, + rendermode_polygon, flags); + /* + // NOTE(doyle): Create degenerate vertex setup + Vertex triVertexList[5] = {tri->vertex[0], tri->vertex[0], tri->vertex[1], + tri->vertex[2], tri->vertex[2]}; + */ +} + void renderer_triangle(Renderer *const renderer, Rect camera, TrianglePoints triangle, v2 pivotPoint, Radians rotate, RenderTex *renderTex, v4 color, RenderFlags flags) @@ -472,6 +518,7 @@ void renderer_string(Renderer *const renderer, MemoryArena_ *arena, Rect camera, void renderer_entity(Renderer *renderer, Rect camera, Entity *entity, v2 pivotPoint, Degrees rotate, v4 color, RenderFlags flags) { + // TODO(doyle): Add early exit on entities out of camera bounds Radians totalRotation = DEGREES_TO_RADIANS((entity->rotation + rotate)); RenderTex renderTex = {0}; if (entity->tex) diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h index 6a292c8..7a92723 100644 --- a/src/include/Dengine/Renderer.h +++ b/src/include/Dengine/Renderer.h @@ -35,10 +35,14 @@ enum RenderFlag { renderflag_no_texture = 0x2, }; +// TODO(doyle): Since all vertexes are built with degenerate vertices and +// in a triangle strip format, we should not split render groups by render mode +// nor either generate buffers vao/vbo based on rendermode count enum RenderMode { rendermode_quad, rendermode_triangle, + rendermode_polygon, rendermode_count, rendermode_invalid, }; @@ -48,7 +52,6 @@ typedef struct RenderGroup b32 init; RenderFlags flags; enum RenderMode mode; - u32 glRenderMode; Texture *tex; v4 color; @@ -82,12 +85,18 @@ renderer_createNullRenderTex(AssetManager *const assetManager); // TODO(doyle): Clean up lines // Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); } void renderer_rect(Renderer *const renderer, Rect camera, v2 pos, v2 size, - v2 pivotPoint, Radians rotate, RenderTex *renderTex, v4 color, - RenderFlags flags); + v2 pivotPoint, Radians rotate, RenderTex *renderTex, + v4 color, RenderFlags flags); + +void renderer_polygon(Renderer *const renderer, MemoryArena_ *arena, + Rect camera, v2 *polygonPoints, i32 numPoints, + v2 pivotPoint, Radians rotate, RenderTex *renderTex, + v4 color, RenderFlags flags); inline void renderer_staticRect(Renderer *const renderer, v2 pos, v2 size, - v2 pivotPoint, Radians rotate, RenderTex *renderTex, - v4 color, RenderFlags flags) + v2 pivotPoint, Radians rotate, + RenderTex *renderTex, v4 color, + RenderFlags flags) { Rect staticCamera = {V2(0, 0), renderer->size}; renderer_rect(renderer, staticCamera, pos, size, pivotPoint, rotate, @@ -98,15 +107,15 @@ void renderer_triangle(Renderer *const renderer, Rect camera, TrianglePoints triangle, v2 pivotPoint, Radians rotate, RenderTex *renderTex, v4 color, RenderFlags flags); -void renderer_string(Renderer *const renderer, MemoryArena_ *arena, - Rect camera, Font *const font, - const char *const string, v2 pos, v2 pivotPoint, - Radians rotate, v4 color, RenderFlags flags); +void renderer_string(Renderer *const renderer, MemoryArena_ *arena, Rect camera, + Font *const font, const char *const string, v2 pos, + v2 pivotPoint, Radians rotate, v4 color, + RenderFlags flags); inline void renderer_staticString(Renderer *const renderer, MemoryArena_ *arena, Font *const font, const char *const string, - v2 pos, v2 pivotPoint, Radians rotate, v4 color, - RenderFlags flags) + v2 pos, v2 pivotPoint, Radians rotate, + v4 color, RenderFlags flags) { Rect staticCamera = {V2(0, 0), renderer->size}; renderer_string(renderer, arena, staticCamera, font, string, pos,