summaryrefslogtreecommitdiff
path: root/themes/Snowflake.cpp
diff options
context:
space:
mode:
authormattkae <mattkae@protonmail.com>2022-01-16 18:32:50 -0500
committermattkae <mattkae@protonmail.com>2022-01-16 18:32:50 -0500
commit1d47e3aa120539e053ffa41293f3f756b9d07844 (patch)
tree864069813b642d7634f83b6a8843c3d23a8d4926 /themes/Snowflake.cpp
parenteef48388c610bf37b07aedef03c55344d450386b (diff)
Successful beginnings of the winter theme
Diffstat (limited to 'themes/Snowflake.cpp')
-rw-r--r--themes/Snowflake.cpp136
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;
}