diff options
Diffstat (limited to 'themes/Snowflake.cpp')
-rw-r--r-- | themes/Snowflake.cpp | 136 |
1 files changed, 128 insertions, 8 deletions
diff --git a/themes/Snowflake.cpp b/themes/Snowflake.cpp index 54654f0..3c9afa4 100644 --- a/themes/Snowflake.cpp +++ b/themes/Snowflake.cpp @@ -1,26 +1,146 @@ #include "Snowflake.h" +#include "Renderer2d.h" +#include "mathlib.h" +#include "List.h" + +const Vector4 snowColor = Vector4(1.0, 0.98, 0.98, 1); + +inline void generateSnowflakeShape(List<Renderer2dVertex>* vertices, int32 numArms, float32 radius) { + float32 dx = ((2 * PI) / numArms) / 3.0; + for (int32 centerIdx = 0; centerIdx < (3 * numArms); centerIdx+=3) { + float32 degreeStart = dx * centerIdx; + float32 degreeEnd = dx * (centerIdx + 1); + + float32 cosStart = cosf(degreeStart); + float32 cosEnd = cosf(degreeEnd); + + float32 sinStart = sinf(degreeStart); + float32 sinEnd = sinf(degreeEnd); + + Vector2 leftEnd = Vector2(radius * cosStart, radius * sinStart); + Vector2 rightEnd = Vector2(radius * cosEnd, radius * sinEnd); + Vector2 diff = (rightEnd - leftEnd) / 2.0; + Vector2 leftStart = Vector2(-diff.x, -diff.y); + Vector2 rightStart = diff; + + vertices->add({ leftStart, snowColor, Mat4x4() }); + vertices->add({ leftEnd, snowColor, Mat4x4() }); + vertices->add({ rightEnd, snowColor, Mat4x4() }); + vertices->add({ rightEnd, snowColor, Mat4x4() }); + vertices->add({ rightStart, snowColor, Mat4x4() }); + vertices->add({ leftStart, snowColor, Mat4x4() }); + } +} + +inline void initFlake(SnowflakeParticleRenderer* renderer, SnowflakeUpdateData* ud) { + ud->vtxIdx = renderer->vertices.numElements; + generateSnowflakeShape(&renderer->vertices, 6, randomFloatBetween(8.f, 24.f); + ud->numVertices = renderer->vertices.numElements - ud->vtxIdx; +} + +inline void spawnFlake(SnowflakeParticleRenderer* renderer, SnowflakeUpdateData* ud) { + ud->velocity = Vector2(randomFloatBetween(-10, 10), randomFloatBetween(-100, -85)); + ud->position = Vector2(randomFloatBetween(0, renderer->xMax), randomFloatBetween(renderer->yMax, renderer->yMax + 256)); +} + +inline void findAndSpawnNextFlake(SnowflakeParticleRenderer* renderer) { + do { + renderer->endIndex++; + + if (renderer->endIndex >= renderer->numSnowflakes) + renderer->endIndex = 0; + } while (renderer->updateData[renderer->endIndex].onGround); + + spawnFlake(renderer, &renderer->updateData[renderer->endIndex]); +} void SnowflakeParticleRenderer::load(SnowflakeLoadParameters params, Renderer2d* renderer) { - updateData = new SnowflakeUpdateData[maxSnowflakes]; - renderData = new SnowflakeRenderData[maxSnowflakes]; - activeIndex = 0; + startIndex = 0; + spawnIntervalSeconds = params.spawnIntervalSeconds; + endIndex = params.initialSnowflakeCount; + numSnowflakes = params.maxSnowflakes; + + updateData = new SnowflakeUpdateData[params.maxSnowflakes]; - for (int32 s = 0; s < maxSnowflakes; s++) { + xMax = static_cast<float32>(renderer->context->width); + yMax = static_cast<float32>(renderer->context->height); + + // Initialize each snow flake with its shape + for (int32 s = 0; s < numSnowflakes; s++) { auto ud = &updateData[s]; - auto rd = &renderData[s]; + initFlake(this, ud); + + if (s < endIndex) { + spawnFlake(this, ud); + } + } + + useShader(renderer->shader); + + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, vertices.numElements * sizeof(Renderer2dVertex), &vertices.data[0], GL_DYNAMIC_DRAW); + + glEnableVertexAttribArray(renderer->attributes.position); + glVertexAttribPointer(renderer->attributes.position, 2, GL_FLOAT, GL_FALSE, sizeof(Renderer2dVertex), (GLvoid *)0); + + glEnableVertexAttribArray(renderer->attributes.color); + glVertexAttribPointer(renderer->attributes.color, 4, GL_FLOAT, GL_FALSE, sizeof(Renderer2dVertex), (GLvoid *)offsetof(Renderer2dVertex, color)); - ud->velocity = params->flakeV0; + for (int32 idx = 0; idx < 4; idx++) { + int32 offset = (4 * sizeof(float32)) * idx; + glEnableVertexAttribArray(renderer->attributes.vMatrix + idx); + glVertexAttribPointer(renderer->attributes.vMatrix + idx, + 4, + GL_FLOAT, + GL_FALSE, + sizeof(Renderer2dVertex), + (GLvoid *)(offsetof(Renderer2dVertex, vMatrix) + offset)); + //glVertexAttribDivisor(renderer->attributes.vMatrix + idx, 1); } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); } void SnowflakeParticleRenderer::update(float32 dtSeconds) { - + timeUntilNextSpawnSeconds -= dtSeconds; + if (timeUntilNextSpawnSeconds < 0) { + timeUntilNextSpawnSeconds = spawnIntervalSeconds; + findAndSpawnNextFlake(this); + } + + for (int32 s = startIndex; s < endIndex; s++) { + SnowflakeUpdateData* ud = &updateData[s]; + ud->position += ud->velocity * dtSeconds; + + Mat4x4 m = Mat4x4().translateByVec2(ud->position); + for (int32 v = ud->vtxIdx; v < (ud->vtxIdx + ud->numVertices); v++) { + vertices.data[v].vMatrix = m; + } + } } void SnowflakeParticleRenderer::render(Renderer2d* renderer) { + auto startVertex = &updateData[startIndex]; + auto endVertex = &updateData[endIndex]; + int32 numVertices = (endVertex->vtxIdx + endVertex->numVertices) - startVertex->vtxIdx; + setShaderMat4(renderer->uniforms.model, model); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices * sizeof(Renderer2dVertex), &vertices.data[startVertex->vtxIdx]); + + glBindVertexArray(vao); + glDrawArrays(GL_TRIANGLES, 0, numVertices); + glBindVertexArray(0); } void SnowflakeParticleRenderer::unload() { - + glDeleteVertexArrays(1, &vao); + glDeleteBuffers(1, &vbo); + vertices.deallocate(); + delete [] updateData; } |