diff --git a/data/blackboard.art b/data/blackboard.art index 4f8a217..f09515e 100644 Binary files a/data/blackboard.art and b/data/blackboard.art differ diff --git a/src/Asteroid.c b/src/Asteroid.c index 6928e45..614f31d 100644 --- a/src/Asteroid.c +++ b/src/Asteroid.c @@ -172,8 +172,7 @@ v2 *createAsteroidVertexList(MemoryArena_ *arena, i32 iterations, { f32 iterationAngle = 360.0f / iterations; iterationAngle = DEGREES_TO_RADIANS(iterationAngle); - v2 *result = - memory_pushBytes(arena, iterations * sizeof(v2)); + v2 *result = memory_pushBytes(arena, iterations * sizeof(v2)); for (i32 i = 0; i < iterations; i++) { @@ -285,7 +284,8 @@ b32 checkEdgeProjectionOverlap(v2 *vertexList, i32 listSize, return result; } -b32 moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed) +b32 moveEntity(GameState *state, Entity *entity, i32 entityIndex, v2 ddP, + f32 dt, f32 ddPSpeed) { ASSERT(ABS(ddP.x) <= 1.0f && ABS(ddP.y) <= 1.0f); /* @@ -311,13 +311,14 @@ b32 moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed) b32 willCollide = FALSE; + // TODO(doyle): Collision for rects, (need to create vertex list for it) #if 1 if (entity->renderMode == rendermode_polygon && entity->collides) { - for (i32 i = 0; i < state->entityIndex; i++) + for (i32 i = entityIndex + 1; i < state->entityIndex; i++) { Entity *checkEntity = &state->entityList[i]; - if (checkEntity->id == entity->id) continue; + ASSERT(checkEntity->id != entity->id); if (checkEntity->renderMode == rendermode_polygon && checkEntity->collides) @@ -325,6 +326,7 @@ b32 moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed) /* Create entity edge lists */ v2 *entityVertexListOffsetToP = entity_createVertexList(&state->transientArena, entity); + v2 *checkEntityVertexListOffsetToP = entity_createVertexList( &state->transientArena, checkEntity); @@ -368,6 +370,7 @@ b32 moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed) } #endif +#if 0 if (!willCollide) { entity->dP = newDp; @@ -378,6 +381,11 @@ b32 moveEntity(GameState *state, Entity *entity, v2 ddP, f32 dt, f32 ddPSpeed) entity->dP = v2_scale(newDp, -1.0f); } +#else + entity->dP = newDp; + entity->pos = newPos; +#endif + return willCollide; } @@ -389,7 +397,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, if (!state->init) { - srand(time(NULL)); + srand((u32)time(NULL)); memory_arenaInit(&state->persistentArena, memory->persistent, memory->persistentSize); initAssetManager(state); @@ -397,12 +405,43 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, state->pixelsPerMeter = 70.0f; + { // Init asteroid entities + i32 numAsteroids = 1; + for (i32 i = 0; i < numAsteroids; i++) + { + Entity *asteroid = &state->entityList[state->entityIndex]; + asteroid->id = state->entityIndex++; + + i32 randValue = rand(); + i32 randX = (randValue % (i32)windowSize.w); + i32 randY = (randValue % (i32)windowSize.h); + asteroid->pos = V2i(100 + (i * 100), 500); + + asteroid->size = V2(100.0f, 100.0f); + asteroid->hitbox = asteroid->size; + asteroid->offset = V2(asteroid->size.w * -0.5f, 0); + asteroid->scale = 1; + asteroid->rotation = 45; + asteroid->type = entitytype_asteroid; + asteroid->direction = direction_null; + asteroid->renderMode = rendermode_polygon; + + asteroid->numVertexPoints = i + 10; + asteroid->vertexPoints = createAsteroidVertexList( + &state->persistentArena, asteroid->numVertexPoints, + (i32)(asteroid->size.x * 0.5f)); + + asteroid->tex = NULL; + asteroid->collides = TRUE; + } + } + +#if 1 { // Init ship entity Entity *ship = &state->entityList[state->entityIndex]; ship->id = state->entityIndex++; ship->pos = V2(100, 100); ship->size = V2(25.0f, 50.0f); - ship->rotation = 90.0f; ship->hitbox = ship->size; ship->offset = v2_scale(ship->size, 0.5f); @@ -425,47 +464,9 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, ship->tex = NULL; ship->collides = TRUE; - i32 numAsteroids = 1; - for (i32 i = 0; i < numAsteroids; i++) - { - Entity *asteroid = &state->entityList[state->entityIndex]; - asteroid->id = state->entityIndex++; - - i32 randValue = rand(); - i32 randX = (randValue % (i32)windowSize.w); - i32 randY = (randValue % (i32)windowSize.h); - asteroid->pos = V2i(500, 500); - - asteroid->size = V2(100.0f, 100.0f); - asteroid->hitbox = asteroid->size; - asteroid->offset = V2(asteroid->size.w * -0.5f, 0); - asteroid->scale = 1; - asteroid->type = entitytype_asteroid; - asteroid->direction = direction_null; - asteroid->renderMode = rendermode_polygon; - - asteroid->numVertexPoints = 8; - asteroid->vertexPoints = createAsteroidVertexList( - &state->persistentArena, asteroid->numVertexPoints, - (i32)(asteroid->size.x * 0.5f)); - - asteroid->tex = NULL; - 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; } +#endif + state->camera.min = V2(0, 0); state->camera.max = state->renderer.size; @@ -639,26 +640,31 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, v2_scale(ddP, dirOffset); // NOTE(doyle): Make asteroids start and move at constant speed - ddPSpeedInMs = 2; + ddPSpeedInMs = 1; entity->dP = v2_scale(ddP, state->pixelsPerMeter * ddPSpeedInMs); #endif - entity->rotation += (randValue % 20) * dt; + entity->rotation += (60 * dt); } - 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); + b32 willCollide = moveEntity(state, entity, i, ddP, dt, ddPSpeedInMs); + v4 entityColor = V4(1.0f, 1.0f, 1.0f, 1.0f); +#if 1 + if (willCollide) + { + entityColor = V4(1.0f, 1.0f, 0, 1.0f); + } +#endif RenderFlags flags = renderflag_wireframe | renderflag_no_texture; renderer_entity(&state->renderer, &state->transientArena, state->camera, entity, V2(0, 0), 0, - entityCollisionColor, flags); + entityColor, flags); } +#if 0 debug_drawUi(state, dt); debug_clearCounter(); +#endif renderer_renderGroups(&state->renderer); } diff --git a/src/Debug.c b/src/Debug.c index ba6a8e3..b961d11 100644 --- a/src/Debug.c +++ b/src/Debug.c @@ -287,5 +287,8 @@ void debug_drawUi(GameState *state, f32 dt) DEBUG_PUSH_VAR("Permanent Size: %.0f", persistent->size, "f32"); DEBUG_PUSH_VAR("Permanent Usage: %.0f/%.0f", persistentUsage, "v2"); + DEBUG_PUSH_VAR("Num Vertex: %d", + GLOBAL_debug.callCount[debugcount_numVertex], "i32"); + debug_clearCounter(); } diff --git a/src/Entity.c b/src/Entity.c index 9795ba6..6555c06 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -96,7 +96,7 @@ v2 *entity_createVertexList(MemoryArena_ *transientArena, Entity *entity) for (i32 i = 0; i < entity->numVertexPoints; i++) { - result[i] = v2_sub(entity->vertexPoints[i], entity->offset); + result[i] = v2_add(entity->vertexPoints[i], entity->offset); result[i] = v2_add(result[i], entity->pos); } diff --git a/src/Renderer.c b/src/Renderer.c index fc3d604..48a8694 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -26,31 +26,20 @@ INTERNAL void beginVertexBatch(Renderer *renderer) 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. + rendering. - 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 + The 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 initial degenrate - vertexes are added in the add to vertex group and the ending degenerates at - on ending a vertex batch. */ INTERNAL void endVertexBatch(Renderer *renderer) { ASSERT(renderer->vertexBatchState != vertexbatchstate_off); ASSERT(renderer->groupIndexForVertexBatch != -1); - i32 numDegenerateVertexes = 2; + i32 numDegenerateVertexes = 1; RenderGroup *group = &renderer->groups[renderer->groupIndexForVertexBatch]; i32 freeVertexSlots = renderer->groupCapacity - group->vertexIndex; @@ -59,7 +48,6 @@ INTERNAL void endVertexBatch(Renderer *renderer) RenderVertex degenerateVertex = group->vertexList[group->vertexIndex - 1]; group->vertexList[group->vertexIndex++] = degenerateVertex; - group->vertexList[group->vertexIndex++] = degenerateVertex; } renderer->vertexBatchState = vertexbatchstate_off; @@ -168,10 +156,9 @@ INTERNAL void addVertexToRenderGroup_(Renderer *renderer, Texture *tex, // NOTE(doyle): Two at start, two at end i32 numDegenerateVertexes = 0; + if (renderer->vertexBatchState == vertexbatchstate_initial_add) - { - numDegenerateVertexes = 2; - } + numDegenerateVertexes = 1; if ((numDegenerateVertexes + numVertexes) < freeVertexSlots) { @@ -190,10 +177,37 @@ INTERNAL void addVertexToRenderGroup_(Renderer *renderer, Texture *tex, /* Valid group, add to the render group for rendering */ if (targetGroup) { + // NOTE(doyle): If we are adding 3 vertexes, then we are adding a + // triangle to the triangle strip. If so, then depending on which "n-th" + // triangle it is we're adding, the winding order in a t-strip + // alternates with each triangle (including degenerates). Hence we track + // so we know the last winding order in the group. + + // For this to work, we must ensure all incoming vertexes are winding in + // ccw order initially. There is also the presumption that, other + // rendering methods, such as the quad, consists of an even number of + // triangles such that the winding order gets alternated back to the + // same order it started with. + if (numVertexes == 3) + { + if (targetGroup->clockwiseWinding) + { + RenderVertex tmp = vertexList[0]; + vertexList[0] = vertexList[2]; + vertexList[2] = tmp; + } + + targetGroup->clockwiseWinding = + (targetGroup->clockwiseWinding) ? FALSE : TRUE; + } + if (renderer->vertexBatchState == vertexbatchstate_initial_add) { - targetGroup->vertexList[targetGroup->vertexIndex++] = vertexList[0]; - targetGroup->vertexList[targetGroup->vertexIndex++] = vertexList[0]; + if (targetGroup->vertexIndex != 0) + { + targetGroup->vertexList[targetGroup->vertexIndex++] = + vertexList[0]; + } renderer->vertexBatchState = vertexbatchstate_active; // NOTE(doyle): We swap groups to the front if it is valid, so @@ -202,6 +216,7 @@ INTERNAL void addVertexToRenderGroup_(Renderer *renderer, Texture *tex, renderer->groupIndexForVertexBatch = 0; } + for (i32 i = 0; i < numVertexes; i++) { targetGroup->vertexList[targetGroup->vertexIndex++] = vertexList[i]; @@ -345,9 +360,13 @@ INTERNAL void renderGLBufferedData(Renderer *renderer, RenderGroup *group) ASSERT(group->mode < rendermode_invalid); 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) @@ -370,6 +389,10 @@ INTERNAL void renderGLBufferedData(Renderer *renderer, RenderGroup *group) } } +#if 0 + glDisable(GL_CULL_FACE); +#endif + /* Set color modulation value */ shader_uniformSetVec4f(renderer->activeShaderId, "spriteColor", group->color); @@ -420,35 +443,39 @@ void renderer_polygon(Renderer *const renderer, Rect camera, { ASSERT(numPoints >= 3); - for (i32 i = 0; i < numPoints; i++) + for (i32 i = 0; i < numPoints; i++) polygonPoints[i] = v2_sub(polygonPoints[i], camera.min); // TODO(doyle): Do something with render texture RenderTex emptyRenderTex = {0}; if (!renderTex) renderTex = &emptyRenderTex; - v2 triangulationBaseP = polygonPoints[0]; + v2 triangulationBaseP = polygonPoints[0]; RenderVertex triangulationBaseVertex = {0}; - triangulationBaseVertex.pos = triangulationBaseP; + triangulationBaseVertex.pos = triangulationBaseP; i32 numTrisInTriangulation = numPoints - 2; i32 triangulationIndex = 0; - beginVertexBatch(renderer); for (i32 i = 1; triangulationIndex < numTrisInTriangulation; i++) { ASSERT((i + 1) < numPoints); + v2 vertexList[3] = {triangulationBaseP, polygonPoints[i], + polygonPoints[i + 1]}; + + beginVertexBatch(renderer); + RenderVertex triangle[3] = {0}; - triangle[0].pos = triangulationBaseP; - triangle[1].pos = polygonPoints[i]; - triangle[2].pos = polygonPoints[i + 1]; + triangle[0].pos = vertexList[0]; + triangle[1].pos = vertexList[1]; + triangle[2].pos = vertexList[2]; addVertexToRenderGroup_(renderer, renderTex->tex, color, triangle, ARRAY_COUNT(triangle), rendermode_polygon, flags); + endVertexBatch(renderer); triangulationIndex++; } - endVertexBatch(renderer); } void renderer_string(Renderer *const renderer, MemoryArena_ *arena, Rect camera, @@ -560,6 +587,7 @@ void renderer_entity(Renderer *renderer, MemoryArena_ *transientArena, v2 *offsetVertexPoints = entity_createVertexList(transientArena, entity); + renderer_polygon(renderer, camera, offsetVertexPoints, entity->numVertexPoints, v2_add(entity->offset, pivotPoint), totalRotation, diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h index efc4b1d..c02fe93 100644 --- a/src/include/Dengine/Renderer.h +++ b/src/include/Dengine/Renderer.h @@ -48,6 +48,10 @@ typedef struct RenderGroup RenderFlags flags; enum RenderMode mode; + // NOTE(doyle): Only for when adding singular triangles in triangle strip + // mode + b32 clockwiseWinding; + Texture *tex; v4 color;