From bf4b3a5c35152c1292757134123b3363d0f81bf6 Mon Sep 17 00:00:00 2001 From: Matt Kosarek Date: Mon, 29 Dec 2025 09:34:00 -0500 Subject: Renamed PascalCase files to snake_case --- themes/src/winter/Snowflake.cpp | 189 ------------------------------------- themes/src/winter/Snowflake.h | 48 ---------- themes/src/winter/Windfield.cpp | 28 ------ themes/src/winter/Windfield.hpp | 39 -------- themes/src/winter/WinterTheme.cpp | 32 ------- themes/src/winter/WinterTheme.hpp | 25 ----- themes/src/winter/snowflake.cpp | 189 +++++++++++++++++++++++++++++++++++++ themes/src/winter/snowflake.h | 48 ++++++++++ themes/src/winter/windfield.cpp | 28 ++++++ themes/src/winter/windfield.hpp | 39 ++++++++ themes/src/winter/winter_theme.cpp | 32 +++++++ themes/src/winter/winter_theme.hpp | 25 +++++ 12 files changed, 361 insertions(+), 361 deletions(-) delete mode 100644 themes/src/winter/Snowflake.cpp delete mode 100644 themes/src/winter/Snowflake.h delete mode 100644 themes/src/winter/Windfield.cpp delete mode 100644 themes/src/winter/Windfield.hpp delete mode 100644 themes/src/winter/WinterTheme.cpp delete mode 100644 themes/src/winter/WinterTheme.hpp create mode 100644 themes/src/winter/snowflake.cpp create mode 100644 themes/src/winter/snowflake.h create mode 100644 themes/src/winter/windfield.cpp create mode 100644 themes/src/winter/windfield.hpp create mode 100644 themes/src/winter/winter_theme.cpp create mode 100644 themes/src/winter/winter_theme.hpp (limited to 'themes/src/winter') diff --git a/themes/src/winter/Snowflake.cpp b/themes/src/winter/Snowflake.cpp deleted file mode 100644 index 57f1a8f..0000000 --- a/themes/src/winter/Snowflake.cpp +++ /dev/null @@ -1,189 +0,0 @@ -#include "Snowflake.h" -#include "../Renderer2d.h" -#include "../mathlib.h" -#include "../list.h" -#include - -/* - - What else to do? - - - Windstream that blows a certain selection of snowflakes in a loop-dee-loop pattern - - Snowflakes that land on the ground and melt - - Snowflakes that spin along the Y-axis for a three dimensional effect - - */ - -const Vector4 snowColor = Vector4(1.0, 0.98, 0.98, 1); -const Vector2 NUM_ARMS_RANGE = Vector2(6.f, 8.f); -const Vector2 RADIUS_RANGE = Vector2(8.f, 32.f); -const Vector2 VELOCITY_RANGE_X = Vector2(-10.f, 10.f); -const Vector2 VELOCITY_RANGE_Y = Vector2(-100.f, -85.f); -const Vector2 ROTATION_VELOCITY_RANGE = Vector2(-PI / 8.f, PI / 8.f); -const Vector2 WIND_VELOCITY_RANGE_X = Vector2(-3.f, 3.f); -const Vector2 WIND_VELOCITY_RANGE_Y = Vector2(3.f, 10.f); -const f32 GRAVITY = 5.f; - -inline void generateSnowflakeArm(f32 width, f32 height, f32 angle, matte::List* vertices, Mat4x4 transform = Mat4x4()) { - f32 halfWidth = width / 2.f; - Vector2 leftStart = transform * Vector2(-halfWidth, 0).rotate(angle); - Vector2 leftEnd = transform * Vector2(-halfWidth, height).rotate(angle); - Vector2 rightStart = transform * Vector2(halfWidth, 0).rotate(angle); - Vector2 rightEnd = transform * Vector2(halfWidth, height).rotate(angle); - - vertices->add({ leftStart, snowColor, Mat4x4() }); - vertices->add({ leftEnd, snowColor, Mat4x4() }); - vertices->add({ rightEnd, snowColor, Mat4x4() }); - vertices->add({ leftStart, snowColor, Mat4x4() }); - vertices->add({ rightEnd, snowColor, Mat4x4() }); - vertices->add({ rightStart, snowColor, Mat4x4() }); -} - -/** - Fills in the vertices array vertices that represent a snowflake shape. The snowflake shape consists - of numArms jutting out of the center radially. The center of the flake is connected. The radius is - used to determine the length of the arms. The first third of each arm is barren, after which branches - extends on either side of the arm at an angle of about 60 degrees. Each branch can itself have tiny - sub branches jutting out of it, but these should be not nearly as large as the regular branches. - - With all of this in mind, we should be able to build a convincing snowflake. - - :param vertices List of vertices to be filled in - :param numArms Number of arms radially sticking out of the snowflake - :param radius Length of the snowflake arms - */ -inline void generateSnowflakeShape(matte::List* vertices, i32 numArms, f32 radius, f32 armWidthRatio = 0.08f) { - f32 innerRadius = 0; - f32 outerRadius = 2 * radius; - f32 dx = ((2 * PI) / numArms); - for (i32 armIndex = 0; armIndex < numArms; armIndex++) { - f32 armAngle = dx * armIndex; - generateSnowflakeArm(armWidthRatio * radius, radius, armAngle, vertices); - f32 armLeftAngle = DEG_TO_RAD(60.f); - f32 armRightAngle = DEG_TO_RAD(-60.f); - - const i32 NUM_SUB_ARMS = 4; - for (i32 subArmIndex = 0; subArmIndex < NUM_SUB_ARMS; subArmIndex++) { - f32 height = (radius / static_cast(subArmIndex)); - f32 width = (armWidthRatio / (subArmIndex + 1)) * height; - f32 transY = (radius / (NUM_SUB_ARMS + 1)) * (subArmIndex + 1); - Vector2 translation = Vector2(0, transY).rotate(armAngle); - generateSnowflakeArm(width, height, armAngle, vertices, Mat4x4().translateByVec2(translation).rotate2D(armLeftAngle)); - generateSnowflakeArm(width, height, armAngle, vertices, Mat4x4().translateByVec2(translation).rotate2D(armRightAngle)); - } - } -} - -inline void initFlake(SnowflakeParticleRenderer* renderer, SnowflakeUpdateData* ud) { - ud->radius = randomFloatBetween(RADIUS_RANGE.x, RADIUS_RANGE.y); - ud->vtxIdx = renderer->vertices.numElements; - generateSnowflakeShape(&renderer->vertices, - randomFloatBetween(NUM_ARMS_RANGE.x, NUM_ARMS_RANGE.y), - ud->radius); - - ud->numVertices = renderer->vertices.numElements - ud->vtxIdx; - ud->velocity = Vector2(randomFloatBetween(VELOCITY_RANGE_X.x, VELOCITY_RANGE_X.y), randomFloatBetween(VELOCITY_RANGE_Y.x, VELOCITY_RANGE_Y.y)); - ud->position = Vector2(randomFloatBetween(0, renderer->xMax), randomFloatBetween(renderer->yMax, 4 * renderer->yMax)); - ud->rotateVelocity = randomFloatBetween(ROTATION_VELOCITY_RANGE.x, ROTATION_VELOCITY_RANGE.y); -} - -void SnowflakeParticleRenderer::load(SnowflakeLoadParameters params, Renderer2d* renderer) { - numSnowflakes = params.numSnowflakes; - - updateData = new SnowflakeUpdateData[params.numSnowflakes]; - - xMax = static_cast(renderer->context->width); - yMax = static_cast(renderer->context->height); - - vertices.deallocate(); - vertices.growDynamically = true; - - // Initialize each snow flake with its shape - for (i32 s = 0; s < numSnowflakes; s++) { - auto ud = &updateData[s]; - initFlake(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(Vertex2D), &vertices.data[0], GL_DYNAMIC_DRAW); - - glEnableVertexAttribArray(renderer->attributes.position); - glVertexAttribPointer(renderer->attributes.position, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (GLvoid *)0); - - glEnableVertexAttribArray(renderer->attributes.color); - glVertexAttribPointer(renderer->attributes.color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (GLvoid *)offsetof(Vertex2D, color)); - - for (i32 idx = 0; idx < 4; idx++) { - i32 offset = (4 * sizeof(f32)) * idx; - glEnableVertexAttribArray(renderer->attributes.vMatrix + idx); - glVertexAttribPointer(renderer->attributes.vMatrix + idx, - 4, - GL_FLOAT, - GL_FALSE, - sizeof(Vertex2D), - (GLvoid *)(offsetof(Vertex2D, vMatrix) + offset)); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -inline void resetFlake(SnowflakeParticleRenderer* renderer, SnowflakeUpdateData* ud) { - ud->position.y = 2 * renderer->yMax; - ud->velocity = Vector2(randomFloatBetween(-10, 10), randomFloatBetween(-100, -85)); - ud->rotation = 0; -} - -inline void updateFlake(SnowflakeParticleRenderer* renderer, SnowflakeUpdateData* ud, i32 s, f32 dtSeconds) { - ud->velocity = ud->velocity + Vector2(0, -(GRAVITY * dtSeconds)); - //if (addWind) ud->velocity += renderer->windSpeed; - ud->position += ud->velocity * dtSeconds; - ud->rotation += ud->rotateVelocity * dtSeconds; - - Mat4x4 m = Mat4x4().translateByVec2(ud->position).rotate2D(ud->rotation); - for (i32 v = ud->vtxIdx; v < (ud->vtxIdx + ud->numVertices); v++) { - renderer->vertices.data[v].vMatrix = m; - } - - if (ud->position.y <= -ud->radius) { - resetFlake(renderer, ud); - } -} - -void SnowflakeParticleRenderer::update(f32 dtSeconds) { - timeUntilNextWindSeconds -= dtSeconds; - if (timeUntilNextWindSeconds < 0) { - timeUntilNextWindSeconds = randomFloatBetween(2.5f, 10.f); - } - - for (i32 s = 0; s < numSnowflakes; s++) { - SnowflakeUpdateData* ud = &updateData[s]; - updateFlake(this, ud, s, dtSeconds); - } -} - -void SnowflakeParticleRenderer::render(Renderer2d* renderer) { - setShaderMat4(renderer->uniforms.model, model); - - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.numElements * sizeof(Vertex2D), &vertices.data[0]); - - glBindVertexArray(vao); - glDrawArrays(GL_TRIANGLES, 0, vertices.numElements); - glBindVertexArray(0); -} - -void SnowflakeParticleRenderer::unload() { - glDeleteVertexArrays(1, &vao); - glDeleteBuffers(1, &vbo); - vao = 0; - vbo = 0; - vertices.deallocate(); - delete [] updateData; -} diff --git a/themes/src/winter/Snowflake.h b/themes/src/winter/Snowflake.h deleted file mode 100644 index ad027f6..0000000 --- a/themes/src/winter/Snowflake.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef SNOWFLAKE_H -#define SNOWFLAKE_H - -#include "../types.h" -#include "../mathlib.h" -#include "../list.h" -#include "Windfield.hpp" - -struct Renderer2d; -struct Vertex2D; - -struct SnowflakeLoadParameters { - i32 numSnowflakes = 480; - f32 windIntervalSeconds = 1.5f; -}; - -struct SnowflakeUpdateData { - Vector2 velocity; - Vector2 position; - f32 rotateVelocity = 0.f; - f32 rotation = 0; - f32 radius; - - i32 vtxIdx = 0; - i32 numVertices = 0; -}; - -struct SnowflakeParticleRenderer { - f32 xMax = 0; - f32 yMax = 0; - f32 windIntervalSeconds = 1.5; - i32 numSnowflakes = 0; - f32 timeUntilNextWindSeconds = 0; - WindField<100, 100, 10> wind; - SnowflakeUpdateData* updateData; - - u32 vao; - u32 vbo; - Mat4x4 model; - matte::List vertices; - - void load(SnowflakeLoadParameters params, Renderer2d* renderer); - void update(f32 dtSeconds); - void render(Renderer2d* renderer); - void unload(); -}; - -#endif diff --git a/themes/src/winter/Windfield.cpp b/themes/src/winter/Windfield.cpp deleted file mode 100644 index 88fb74b..0000000 --- a/themes/src/winter/Windfield.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "Windfield.hpp" - - -template -void WindField::load(f32 cellSizePixels, i32 fieldWithCells, i32 fieldHeightCells, f32 ttl, Vector2 origin) { - this->ttl = ttl; - this->origin = origin; - this->end = this->origin + Vector2(Width * CellDimension, Height * CellDimension); -} - -template -bool WindField::addVector(i32 x, i32 y, Vector2& v) { - field[x][y] = v; - return false; -} - -template -Vector2 WindField::getWindFactor(Vector2& v) { - if (v.x >= origin.x && v.x <= end.x - && v.y >= origin.y && v.y <= end.y) { - Vector2 positionInField = v - this->origin; - i32 cellX = static_cast(Width / positionInField.x); - i32 cellY = static_cast(Height / positionInField.y); - return field[cellX][cellY]; - } - - return Vector2(); -} diff --git a/themes/src/winter/Windfield.hpp b/themes/src/winter/Windfield.hpp deleted file mode 100644 index 5bf0c38..0000000 --- a/themes/src/winter/Windfield.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef WIND_FIELD_HPP -#define WIND_FIELD_HPP -#include "../types.h" -#include "../mathlib.h" - -/** - A Windfield represents a field of vectors in a rectangular region. - The Width and Height are given in units of CellDimenions. The CellDimension - is given in pixels. - */ -template -struct WindField { - f32 ttl = 0.f; - Vector2 origin; - Vector2 end; - - /* - Granularity of each cell in pixels. - */ - const f32 cellDimension = CellDimension; - - /* - Width of the vector field in CellDimensions. - */ - const f32 width = Width; - - /* - Height of the vector vield in CellDimensions. - */ - const f32 height = Height; - - Vector2** field; - - void load(f32 cellSizePixels, i32 fieldWithCells, i32 fieldHeightCells, f32 ttl, Vector2 origin); - bool addVector(i32 x, i32 y, Vector2& v); - Vector2 getWindFactor(Vector2& v); -}; - -#endif diff --git a/themes/src/winter/WinterTheme.cpp b/themes/src/winter/WinterTheme.cpp deleted file mode 100644 index 052670e..0000000 --- a/themes/src/winter/WinterTheme.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "WinterTheme.hpp" -#include "../Renderer2d.h" - -WinterTheme::WinterTheme(WebglContext* context) -{ - renderer.load(context); - load(); -} - -WinterTheme::~WinterTheme() -{ - unload(); -} - -void WinterTheme::load() { - renderer.clearColor = Vector4(200, 229, 239, 255).toNormalizedColor(); - SnowflakeLoadParameters lp; - spr.load(lp, &renderer); -} - -void WinterTheme::update(f32 dtSeconds) { - spr.update(dtSeconds); -} - -void WinterTheme::render() { - renderer.render(); - spr.render(&renderer); -} - -void WinterTheme::unload() { - spr.unload(); -} diff --git a/themes/src/winter/WinterTheme.hpp b/themes/src/winter/WinterTheme.hpp deleted file mode 100644 index 5ba6d94..0000000 --- a/themes/src/winter/WinterTheme.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef WINTER_THEME_HPP -#define WINTER_THEME_HPP - -#include "Snowflake.h" -#include "../types.h" -#include "../theme.h" -#include "../Renderer2d.h" - -struct WebglContext; - -struct WinterTheme : public Theme { -public: - WinterTheme(WebglContext*); - ~WinterTheme(); - SnowflakeParticleRenderer spr; - - void load(); - void update(f32 dtSeconds); - void render(); - void unload(); -private: - Renderer2d renderer; -}; - -#endif diff --git a/themes/src/winter/snowflake.cpp b/themes/src/winter/snowflake.cpp new file mode 100644 index 0000000..4ce8f3a --- /dev/null +++ b/themes/src/winter/snowflake.cpp @@ -0,0 +1,189 @@ +#include "snowflake.h" +#include "../renderer_2d.h" +#include "../mathlib.h" +#include "../list.h" +#include + +/* + + What else to do? + + - Windstream that blows a certain selection of snowflakes in a loop-dee-loop pattern + - Snowflakes that land on the ground and melt + - Snowflakes that spin along the Y-axis for a three dimensional effect + + */ + +const Vector4 snowColor = Vector4(1.0, 0.98, 0.98, 1); +const Vector2 NUM_ARMS_RANGE = Vector2(6.f, 8.f); +const Vector2 RADIUS_RANGE = Vector2(8.f, 32.f); +const Vector2 VELOCITY_RANGE_X = Vector2(-10.f, 10.f); +const Vector2 VELOCITY_RANGE_Y = Vector2(-100.f, -85.f); +const Vector2 ROTATION_VELOCITY_RANGE = Vector2(-PI / 8.f, PI / 8.f); +const Vector2 WIND_VELOCITY_RANGE_X = Vector2(-3.f, 3.f); +const Vector2 WIND_VELOCITY_RANGE_Y = Vector2(3.f, 10.f); +const f32 GRAVITY = 5.f; + +inline void generateSnowflakeArm(f32 width, f32 height, f32 angle, matte::List* vertices, Mat4x4 transform = Mat4x4()) { + f32 halfWidth = width / 2.f; + Vector2 leftStart = transform * Vector2(-halfWidth, 0).rotate(angle); + Vector2 leftEnd = transform * Vector2(-halfWidth, height).rotate(angle); + Vector2 rightStart = transform * Vector2(halfWidth, 0).rotate(angle); + Vector2 rightEnd = transform * Vector2(halfWidth, height).rotate(angle); + + vertices->add({ leftStart, snowColor, Mat4x4() }); + vertices->add({ leftEnd, snowColor, Mat4x4() }); + vertices->add({ rightEnd, snowColor, Mat4x4() }); + vertices->add({ leftStart, snowColor, Mat4x4() }); + vertices->add({ rightEnd, snowColor, Mat4x4() }); + vertices->add({ rightStart, snowColor, Mat4x4() }); +} + +/** + Fills in the vertices array vertices that represent a snowflake shape. The snowflake shape consists + of numArms jutting out of the center radially. The center of the flake is connected. The radius is + used to determine the length of the arms. The first third of each arm is barren, after which branches + extends on either side of the arm at an angle of about 60 degrees. Each branch can itself have tiny + sub branches jutting out of it, but these should be not nearly as large as the regular branches. + + With all of this in mind, we should be able to build a convincing snowflake. + + :param vertices List of vertices to be filled in + :param numArms Number of arms radially sticking out of the snowflake + :param radius Length of the snowflake arms + */ +inline void generateSnowflakeShape(matte::List* vertices, i32 numArms, f32 radius, f32 armWidthRatio = 0.08f) { + f32 innerRadius = 0; + f32 outerRadius = 2 * radius; + f32 dx = ((2 * PI) / numArms); + for (i32 armIndex = 0; armIndex < numArms; armIndex++) { + f32 armAngle = dx * armIndex; + generateSnowflakeArm(armWidthRatio * radius, radius, armAngle, vertices); + f32 armLeftAngle = DEG_TO_RAD(60.f); + f32 armRightAngle = DEG_TO_RAD(-60.f); + + const i32 NUM_SUB_ARMS = 4; + for (i32 subArmIndex = 0; subArmIndex < NUM_SUB_ARMS; subArmIndex++) { + f32 height = (radius / static_cast(subArmIndex)); + f32 width = (armWidthRatio / (subArmIndex + 1)) * height; + f32 transY = (radius / (NUM_SUB_ARMS + 1)) * (subArmIndex + 1); + Vector2 translation = Vector2(0, transY).rotate(armAngle); + generateSnowflakeArm(width, height, armAngle, vertices, Mat4x4().translateByVec2(translation).rotate2D(armLeftAngle)); + generateSnowflakeArm(width, height, armAngle, vertices, Mat4x4().translateByVec2(translation).rotate2D(armRightAngle)); + } + } +} + +inline void initFlake(SnowflakeParticleRenderer* renderer, SnowflakeUpdateData* ud) { + ud->radius = randomFloatBetween(RADIUS_RANGE.x, RADIUS_RANGE.y); + ud->vtxIdx = renderer->vertices.numElements; + generateSnowflakeShape(&renderer->vertices, + randomFloatBetween(NUM_ARMS_RANGE.x, NUM_ARMS_RANGE.y), + ud->radius); + + ud->numVertices = renderer->vertices.numElements - ud->vtxIdx; + ud->velocity = Vector2(randomFloatBetween(VELOCITY_RANGE_X.x, VELOCITY_RANGE_X.y), randomFloatBetween(VELOCITY_RANGE_Y.x, VELOCITY_RANGE_Y.y)); + ud->position = Vector2(randomFloatBetween(0, renderer->xMax), randomFloatBetween(renderer->yMax, 4 * renderer->yMax)); + ud->rotateVelocity = randomFloatBetween(ROTATION_VELOCITY_RANGE.x, ROTATION_VELOCITY_RANGE.y); +} + +void SnowflakeParticleRenderer::load(SnowflakeLoadParameters params, Renderer2d* renderer) { + numSnowflakes = params.numSnowflakes; + + updateData = new SnowflakeUpdateData[params.numSnowflakes]; + + xMax = static_cast(renderer->context->width); + yMax = static_cast(renderer->context->height); + + vertices.deallocate(); + vertices.growDynamically = true; + + // Initialize each snow flake with its shape + for (i32 s = 0; s < numSnowflakes; s++) { + auto ud = &updateData[s]; + initFlake(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(Vertex2D), &vertices.data[0], GL_DYNAMIC_DRAW); + + glEnableVertexAttribArray(renderer->attributes.position); + glVertexAttribPointer(renderer->attributes.position, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (GLvoid *)0); + + glEnableVertexAttribArray(renderer->attributes.color); + glVertexAttribPointer(renderer->attributes.color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (GLvoid *)offsetof(Vertex2D, color)); + + for (i32 idx = 0; idx < 4; idx++) { + i32 offset = (4 * sizeof(f32)) * idx; + glEnableVertexAttribArray(renderer->attributes.vMatrix + idx); + glVertexAttribPointer(renderer->attributes.vMatrix + idx, + 4, + GL_FLOAT, + GL_FALSE, + sizeof(Vertex2D), + (GLvoid *)(offsetof(Vertex2D, vMatrix) + offset)); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + +inline void resetFlake(SnowflakeParticleRenderer* renderer, SnowflakeUpdateData* ud) { + ud->position.y = 2 * renderer->yMax; + ud->velocity = Vector2(randomFloatBetween(-10, 10), randomFloatBetween(-100, -85)); + ud->rotation = 0; +} + +inline void updateFlake(SnowflakeParticleRenderer* renderer, SnowflakeUpdateData* ud, i32 s, f32 dtSeconds) { + ud->velocity = ud->velocity + Vector2(0, -(GRAVITY * dtSeconds)); + //if (addWind) ud->velocity += renderer->windSpeed; + ud->position += ud->velocity * dtSeconds; + ud->rotation += ud->rotateVelocity * dtSeconds; + + Mat4x4 m = Mat4x4().translateByVec2(ud->position).rotate2D(ud->rotation); + for (i32 v = ud->vtxIdx; v < (ud->vtxIdx + ud->numVertices); v++) { + renderer->vertices.data[v].vMatrix = m; + } + + if (ud->position.y <= -ud->radius) { + resetFlake(renderer, ud); + } +} + +void SnowflakeParticleRenderer::update(f32 dtSeconds) { + timeUntilNextWindSeconds -= dtSeconds; + if (timeUntilNextWindSeconds < 0) { + timeUntilNextWindSeconds = randomFloatBetween(2.5f, 10.f); + } + + for (i32 s = 0; s < numSnowflakes; s++) { + SnowflakeUpdateData* ud = &updateData[s]; + updateFlake(this, ud, s, dtSeconds); + } +} + +void SnowflakeParticleRenderer::render(Renderer2d* renderer) { + setShaderMat4(renderer->uniforms.model, model); + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.numElements * sizeof(Vertex2D), &vertices.data[0]); + + glBindVertexArray(vao); + glDrawArrays(GL_TRIANGLES, 0, vertices.numElements); + glBindVertexArray(0); +} + +void SnowflakeParticleRenderer::unload() { + glDeleteVertexArrays(1, &vao); + glDeleteBuffers(1, &vbo); + vao = 0; + vbo = 0; + vertices.deallocate(); + delete [] updateData; +} diff --git a/themes/src/winter/snowflake.h b/themes/src/winter/snowflake.h new file mode 100644 index 0000000..11a1438 --- /dev/null +++ b/themes/src/winter/snowflake.h @@ -0,0 +1,48 @@ +#ifndef SNOWFLAKE_H +#define SNOWFLAKE_H + +#include "../types.h" +#include "../mathlib.h" +#include "../list.h" +#include "windfield.hpp" + +struct Renderer2d; +struct Vertex2D; + +struct SnowflakeLoadParameters { + i32 numSnowflakes = 480; + f32 windIntervalSeconds = 1.5f; +}; + +struct SnowflakeUpdateData { + Vector2 velocity; + Vector2 position; + f32 rotateVelocity = 0.f; + f32 rotation = 0; + f32 radius; + + i32 vtxIdx = 0; + i32 numVertices = 0; +}; + +struct SnowflakeParticleRenderer { + f32 xMax = 0; + f32 yMax = 0; + f32 windIntervalSeconds = 1.5; + i32 numSnowflakes = 0; + f32 timeUntilNextWindSeconds = 0; + WindField<100, 100, 10> wind; + SnowflakeUpdateData* updateData; + + u32 vao; + u32 vbo; + Mat4x4 model; + matte::List vertices; + + void load(SnowflakeLoadParameters params, Renderer2d* renderer); + void update(f32 dtSeconds); + void render(Renderer2d* renderer); + void unload(); +}; + +#endif diff --git a/themes/src/winter/windfield.cpp b/themes/src/winter/windfield.cpp new file mode 100644 index 0000000..f6c3be3 --- /dev/null +++ b/themes/src/winter/windfield.cpp @@ -0,0 +1,28 @@ +#include "windfield.hpp" + + +template +void WindField::load(f32 cellSizePixels, i32 fieldWithCells, i32 fieldHeightCells, f32 ttl, Vector2 origin) { + this->ttl = ttl; + this->origin = origin; + this->end = this->origin + Vector2(Width * CellDimension, Height * CellDimension); +} + +template +bool WindField::addVector(i32 x, i32 y, Vector2& v) { + field[x][y] = v; + return false; +} + +template +Vector2 WindField::getWindFactor(Vector2& v) { + if (v.x >= origin.x && v.x <= end.x + && v.y >= origin.y && v.y <= end.y) { + Vector2 positionInField = v - this->origin; + i32 cellX = static_cast(Width / positionInField.x); + i32 cellY = static_cast(Height / positionInField.y); + return field[cellX][cellY]; + } + + return Vector2(); +} diff --git a/themes/src/winter/windfield.hpp b/themes/src/winter/windfield.hpp new file mode 100644 index 0000000..5bf0c38 --- /dev/null +++ b/themes/src/winter/windfield.hpp @@ -0,0 +1,39 @@ +#ifndef WIND_FIELD_HPP +#define WIND_FIELD_HPP +#include "../types.h" +#include "../mathlib.h" + +/** + A Windfield represents a field of vectors in a rectangular region. + The Width and Height are given in units of CellDimenions. The CellDimension + is given in pixels. + */ +template +struct WindField { + f32 ttl = 0.f; + Vector2 origin; + Vector2 end; + + /* + Granularity of each cell in pixels. + */ + const f32 cellDimension = CellDimension; + + /* + Width of the vector field in CellDimensions. + */ + const f32 width = Width; + + /* + Height of the vector vield in CellDimensions. + */ + const f32 height = Height; + + Vector2** field; + + void load(f32 cellSizePixels, i32 fieldWithCells, i32 fieldHeightCells, f32 ttl, Vector2 origin); + bool addVector(i32 x, i32 y, Vector2& v); + Vector2 getWindFactor(Vector2& v); +}; + +#endif diff --git a/themes/src/winter/winter_theme.cpp b/themes/src/winter/winter_theme.cpp new file mode 100644 index 0000000..a628f18 --- /dev/null +++ b/themes/src/winter/winter_theme.cpp @@ -0,0 +1,32 @@ +#include "winter_theme.hpp" +#include "../renderer_2d.h" + +WinterTheme::WinterTheme(WebglContext* context) +{ + renderer.load(context); + load(); +} + +WinterTheme::~WinterTheme() +{ + unload(); +} + +void WinterTheme::load() { + renderer.clearColor = Vector4(200, 229, 239, 255).toNormalizedColor(); + SnowflakeLoadParameters lp; + spr.load(lp, &renderer); +} + +void WinterTheme::update(f32 dtSeconds) { + spr.update(dtSeconds); +} + +void WinterTheme::render() { + renderer.render(); + spr.render(&renderer); +} + +void WinterTheme::unload() { + spr.unload(); +} diff --git a/themes/src/winter/winter_theme.hpp b/themes/src/winter/winter_theme.hpp new file mode 100644 index 0000000..d1c3e05 --- /dev/null +++ b/themes/src/winter/winter_theme.hpp @@ -0,0 +1,25 @@ +#ifndef WINTER_THEME_HPP +#define WINTER_THEME_HPP + +#include "snowflake.h" +#include "../types.h" +#include "../theme.h" +#include "../renderer_2d.h" + +struct WebglContext; + +struct WinterTheme : public Theme { +public: + WinterTheme(WebglContext*); + ~WinterTheme(); + SnowflakeParticleRenderer spr; + + void load(); + void update(f32 dtSeconds); + void render(); + void unload(); +private: + Renderer2d renderer; +}; + +#endif -- cgit v1.2.1