diff options
author | mattkae <mattkae@protonmail.com> | 2023-04-03 06:35:27 -0400 |
---|---|---|
committer | mattkae <mattkae@protonmail.com> | 2023-04-03 06:35:27 -0400 |
commit | 5d3ff36045bfb11af0f373d5ecee7c9b54e4c4f9 (patch) | |
tree | 1877c85fc652603312c1093ff31678ab807616b2 /themes/src/spring | |
parent | 9e21251ea16e594c8ef416cf8a6b8ebbbb42a858 (diff) |
Folderized all of the seasons and loading the shaders from a remote source
Diffstat (limited to 'themes/src/spring')
-rw-r--r-- | themes/src/spring/GrassRenderer.cpp | 29 | ||||
-rw-r--r-- | themes/src/spring/GrassRenderer.hpp | 33 | ||||
-rw-r--r-- | themes/src/spring/SpringTheme.cpp | 198 | ||||
-rw-r--r-- | themes/src/spring/SpringTheme.hpp | 41 |
4 files changed, 301 insertions, 0 deletions
diff --git a/themes/src/spring/GrassRenderer.cpp b/themes/src/spring/GrassRenderer.cpp new file mode 100644 index 0000000..b69d111 --- /dev/null +++ b/themes/src/spring/GrassRenderer.cpp @@ -0,0 +1,29 @@ +#include "GrassRenderer.hpp" +#include "Renderer3d.h" + +void GrassRenderer::load(GrassRendererLoadData params, Renderer3d* renderer) { + const f32 COLUMN_INCREMENT = GRASS_BLADES_PER_COL / params.area.x; + const f32 ROW_INCREMENT = GRASS_BLADES_PER_ROW / params.area.y; + for (i32 r = 0; r < GRASS_BLADES_PER_ROW; r++) { + i32 indexOffset = r * GRASS_BLADES_PER_ROW; + f32 y = ROW_INCREMENT * r; + for (i32 c = 0; c < GRASS_BLADES_PER_COL; c++) { + f32 x = COLUMN_INCREMENT * c; + i32 index = indexOffset + c; + grassBlades[index].position = Vector3(x, y, 0); + grassBlades[index].top_offset = Vector2(0, 0); + } + } +} + +void GrassRenderer::update(f32 seconds) { + +} + +void GrassRenderer::render(Renderer3d* renderer) { + +} + +void GrassRenderer::unload() { + +} diff --git a/themes/src/spring/GrassRenderer.hpp b/themes/src/spring/GrassRenderer.hpp new file mode 100644 index 0000000..8c96724 --- /dev/null +++ b/themes/src/spring/GrassRenderer.hpp @@ -0,0 +1,33 @@ +#ifndef GRASS_RENDERER_HPP +#define GRASS_RENDERER_HPP + +#include "Renderer3d.h" +#include "mathlib.h" +#include "types.h" + +const i32 GRASS_BLADES_PER_ROW = 24; +const i32 GRASS_BLADES_PER_COL = 24; +const i32 NUM_GRASS_BLADES = GRASS_BLADES_PER_ROW * GRASS_BLADES_PER_COL; + +struct GrassRendererLoadData { + Vector2 origin = Vector2(0, 0); + Vector2 area = Vector2(480, 480); + f32 grassHeight = 12.f; +}; + +struct GrassUpdateData { + Vector3 position; + Vector2 top_offset; +}; + +struct GrassRenderer { + + GrassUpdateData grassBlades[NUM_GRASS_BLADES]; + + void load(GrassRendererLoadData params, Renderer3d* renderer); + void update(f32 dtSeconds); + void render(Renderer3d* renderer); + void unload(); +}; + +#endif diff --git a/themes/src/spring/SpringTheme.cpp b/themes/src/spring/SpringTheme.cpp new file mode 100644 index 0000000..abe8c6e --- /dev/null +++ b/themes/src/spring/SpringTheme.cpp @@ -0,0 +1,198 @@ +#include "SpringTheme.hpp" +#include "../Renderer3d.h" +#include "../shader_fetcher.hpp" +#include <cstdio> +#include <emscripten/fetch.h> + +void onBunnySuccess(emscripten_fetch_t *fetch) { + SpringTheme* springTheme = (SpringTheme*)fetch->userData; + springTheme->state = SpringThemeState::LoadedBunny; + printf("Finished downloading %llu bytes from URL %s.\n", fetch->numBytes, fetch->url); + const i32 len = fetch->numBytes; + springTheme->bunnyMesh = Mesh3d_fromObj(&springTheme->renderer, fetch->data, len); + // The data is now available at fetch->data[0] through fetch->data[fetch->numBytes-1]; + emscripten_fetch_close(fetch); // Free data associated with the fetch. +} + +void onBunnyFail(emscripten_fetch_t *fetch) { + printf("Downloading %s failed, HTTP failure status code: %d.\n", fetch->url, fetch->status); + emscripten_fetch_close(fetch); // Also free data on failure. +} + +inline void fetch_bunny(SpringTheme* theme) { + emscripten_fetch_attr_t attr; + emscripten_fetch_attr_init(&attr); + strcpy(attr.requestMethod, "GET"); + attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY; + attr.onsuccess = onBunnySuccess; + attr.onerror = onBunnyFail; + auto* bunny_fetch = emscripten_fetch(&attr, "themes/resources/bunny.obj"); + bunny_fetch->userData = theme; +} + +inline void on_shaders_loader(ShaderFetchResult* result) { + SpringTheme* theme = (SpringTheme*)result->user_data; + theme->renderer.load(theme->renderer.context, result->vertex.c_str(), result->fragment.c_str()); + theme->state = SpringThemeState::LoadedShader; + fetch_bunny(theme); +} + +void SpringTheme::load(WebglContext* context) { + state = SpringThemeState::Loading; + renderer.context = context; + renderer.clearColor = Vector4(160, 231, 160, 255.f).toNormalizedColor(); + + fetch_shader( + { + "themes/src/shaders/renderer3d.vert", + "themes/src/shaders/renderer3d.frag" + }, + on_shaders_loader, + this + ); +} + +inline Vector3 bunnyLerp(Vector3& start, Vector3& target, f32 t) { + t = 3 * t *t - 2 * t * t * t; + return start + ((target - start) * t); +} + +inline f32 verticalHopLerp(f32 start, f32 target, f32 t) { + f32 ogt = t; + t = 3 * t *t - 2 * t * t * t; + if (ogt >= 0.5f) t = 1.f - t; + return start + ((target - start) * t); +} + +inline f32 rotationLerp(f32 start, f32 target, f32 t) { + return start + ((target - start) * t); +} + +void SpringTheme::update(f32 dtSeconds) { + switch (state) { + case SpringThemeState::Loading: return; + case SpringThemeState::LoadedShader: return; + case SpringThemeState::LoadedBunny: + state = SpringThemeState::Idle; + stateTimer = 0.f; + bunnyHopAnimationTimer = 0.f; + break; + case SpringThemeState::Idle: { + bunnyHopAnimationTimer += dtSeconds; + const f32 HOP_FREQUENCY = 6.f; + + if (bunnyHopAnimationTimer > stateTimer) { + state = SpringThemeState::PreHop; + f32 xDir = 1; + f32 yDir = 1; + if (bunnyTarget.x > 0) xDir = -1; + if (bunnyTarget.z > 0) yDir = -1; + bunnyTarget = bunnyPosition + Vector3(randomFloatBetween(0, xDir * 25), 0, randomFloatBetween(0, yDir * 25)); + auto direction = (bunnyTarget - bunnyPosition); + auto distance = direction.length(); + direction = direction.normalize(); + numHops = ceil(distance / HOP_FREQUENCY); + hopCount = 0; + + targetRotation = PI - atan2(direction.y, direction.x); + stateTimer = ((bunnyTarget - bunnyPosition).length() / bunnySpeed) / numHops; + bunnyHopAnimationTimer = 0.f; + hopIncrement = (bunnyTarget - bunnyPosition) / numHops; + } + break; + } + case SpringThemeState::PreHop: { + const f32 ROTATION_TIME = 0.5f; + bunnyHopAnimationTimer += dtSeconds; + f32 current = bunnyRotation + (targetRotation - bunnyRotation) * (bunnyHopAnimationTimer / ROTATION_TIME); + bunnyMesh.model = Mat4x4().rotate(0, current, 0).translate(bunnyPosition); + + if (bunnyHopAnimationTimer > ROTATION_TIME) { + bunnyRotation = targetRotation; + bunnyHopAnimationTimer = 0; + state = SpringThemeState::Hopping; + } + break; + } + case SpringThemeState::Hopping: { + bunnyHopAnimationTimer += dtSeconds; + f32 t = bunnyHopAnimationTimer / stateTimer; + + Vector3 nextPosition = bunnyPosition + hopIncrement; + auto renderPos = bunnyLerp(bunnyPosition, nextPosition, t); + if ((renderPos - nextPosition).length() < 0.01f) { + hopCount += 1; + bunnyHopAnimationTimer = 0.f; + bunnyPosition = nextPosition; + } + + renderPos.y = verticalHopLerp(0.f, 4.f, t); + + const f32 RMAX = PI / 16.f; + f32 zRotation = 0; + f32 start = 0.f; + f32 end = PI / 8.f; + f32 startTime = 0.f; + f32 endTime = 0.f; + bool disableRot = false; + + if (t >= 0.9f) { + disableRot = true; + } + else if (t >= 0.7f) { + start = -RMAX; + end = 0.f; + startTime = 0.7f; + endTime = 0.9f; + } + else if (t >= 0.50f) { + start = 0.f; + end = -RMAX; + startTime = 0.50f; + endTime = 0.70f; + } + else if (t >= 0.40f) { + disableRot = true; + } + else if (t >= 0.20f) { + start = RMAX; + end = 0.f; + startTime = 0.20f; + endTime = 0.40f; + } + else { + start = 0.f; + end = RMAX; + startTime = 0.f; + endTime = 0.20f; + } + + + if (!disableRot) { + f32 totalTime = endTime - startTime; + zRotation = rotationLerp(start, end, (totalTime - (endTime - t)) / totalTime); + } + + bunnyMesh.model = Mat4x4().getZRotationMatrix(zRotation).rotate(0, bunnyRotation, 0).translate(renderPos); + if (hopCount == numHops) { + bunnyPosition = bunnyTarget; + bunnyHopAnimationTimer = 0.f; + state = SpringThemeState::Idle; + stateTimer = randomFloatBetween(0.5f, 1.f); + } + break; + } + } +} + +void SpringTheme::render() { + renderer.render(); + if (state != SpringThemeState::Loading) { + bunnyMesh.render(&renderer); + } +} + +void SpringTheme::unload() { + renderer.unload(); + bunnyMesh.unload(); +} diff --git a/themes/src/spring/SpringTheme.hpp b/themes/src/spring/SpringTheme.hpp new file mode 100644 index 0000000..0866921 --- /dev/null +++ b/themes/src/spring/SpringTheme.hpp @@ -0,0 +1,41 @@ +#ifndef SPRING_THEME_HPP +#define SPRING_THEME_HPP + +#include "../mathlib.h" +#include "../types.h" +#include "../Renderer3d.h" + + +enum class SpringThemeState { + Loading = 0, + LoadedShader, + LoadedBunny, + PreHop, + Hopping, + Idle +}; + +struct SpringTheme { + Renderer3d renderer; + SpringThemeState state; + f32 bunnySpeed = 5.f; + Vector3 bunnyPosition = Vector3(0, 0, 0); + Vector3 bunnyTarget = Vector3(0, 0, 0); + Vector3 hopIncrement = Vector3(0, 0, 0); + + f32 numHops = 0; + f32 hopCount = 0; + f32 bunnyHopAnimationTimer = 0.f; + f32 stateTimer = 0.f; + f32 bunnyRotation = 0.f; + f32 targetRotation = 0.f; + + Mesh3d bunnyMesh; + + void load(WebglContext*); + void update(f32 dtSeconds); + void render(); + void unload(); +}; + +#endif
\ No newline at end of file |