diff --git a/ROADMAP.txt b/ROADMAP.txt index f657171..86a27dc 100644 --- a/ROADMAP.txt +++ b/ROADMAP.txt @@ -1,6 +1,5 @@ ------------ Tyra's v2.0 roadmap to publish on GitHub ------------ - [General] Tyra version -- [Renderer] Test clipper - [Renderer] Fog - [Demo] Create cool demo which will show all features of Tyra - [General] CI in Github via docker image diff --git a/demo/inc/states/game/player/camera.hpp b/demo/inc/states/game/player/camera.hpp index b6ca32f..7c28329 100644 --- a/demo/inc/states/game/player/camera.hpp +++ b/demo/inc/states/game/player/camera.hpp @@ -31,7 +31,7 @@ class Camera { CameraInfo3D getCameraInfo() { return CameraInfo3D(&position, &lookAt); } - void update(const Vec4& playerPosition); + void update(const Vec4& playerPosition, const float& terrainHeight); private: float circleRotation, lengthFromOrigin, height; diff --git a/demo/inc/states/game/player/player.hpp b/demo/inc/states/game/player/player.hpp index 8525c26..9c797af 100644 --- a/demo/inc/states/game/player/player.hpp +++ b/demo/inc/states/game/player/player.hpp @@ -27,17 +27,18 @@ class Player { Player(Engine* engine); ~Player(); + const Vec4& getPosition() const { return position; } CameraInfo3D getCameraInfo() { return camera.getCameraInfo(); } std::vector staticPairs; std::vector dynamicPairs; - void update(); + void update(const float& terrainHeight); private: - void handlePlayerPosition(); + void handlePlayerPosition(const float& terrainHeight); -float speed; + float speed; Pad* pad; Vec4 position; Weapon weapon; diff --git a/demo/inc/states/game/terrain/heightmap.hpp b/demo/inc/states/game/terrain/heightmap.hpp new file mode 100644 index 0000000..14f0e3d --- /dev/null +++ b/demo/inc/states/game/terrain/heightmap.hpp @@ -0,0 +1,42 @@ +/* +# ______ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licenced under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" +#include "loaders/texture/png_loader.hpp" + +using Tyra::Vec4; + +namespace Demo { + +class Heightmap { + public: + Heightmap(const float& minHeight, const float& maxHeight, const Vec4& leftUp, + const Vec4& rightDown); + ~Heightmap(); + + const float& getHeightOffset(const Vec4& playerPosition); + + float** map; + s16 mapWidth, mapHeight; + float minHeight, maxHeight; + Vec4 leftUp, rightDown; + + private: + float getWidthPercentage(const Vec4& playerPosition); + float getHeightPercentage(const Vec4& playerPosition); + void allocateMap(const unsigned char* data, const int& width, + const int& height); + float getGameHeight(const u8& inputColor, const u8& minColor, + const u8& maxColor); +}; + +} // namespace Demo diff --git a/demo/inc/states/game/terrain/terrain.hpp b/demo/inc/states/game/terrain/terrain.hpp index 3c6e7be..815381e 100644 --- a/demo/inc/states/game/terrain/terrain.hpp +++ b/demo/inc/states/game/terrain/terrain.hpp @@ -14,10 +14,12 @@ #include #include "states/game/renderer/renderer_static_pair.hpp" #include +#include "./heightmap.hpp" using Tyra::StaPipOptions; using Tyra::StaticMesh; using Tyra::TextureRepository; +using Tyra::Vec4; namespace Demo { @@ -26,11 +28,12 @@ class Terrain { Terrain(TextureRepository* repo); ~Terrain(); + Heightmap heightmap; StaticMesh* mesh; StaPipOptions* options; RendererStaticPair* pair; - void update(); + float getHeightOffset(const Vec4& playerPosition); private: void allocateOptions(); diff --git a/demo/src/states/game/game_state.cpp b/demo/src/states/game/game_state.cpp index 5819020..2816f9f 100644 --- a/demo/src/states/game/game_state.cpp +++ b/demo/src/states/game/game_state.cpp @@ -51,7 +51,9 @@ void GameState::update() { auto cameraInfo = player.getCameraInfo(); engine->renderer.beginFrame(cameraInfo); - player.update(); + float terrainHeight = terrain.getHeightOffset(player.getPosition()); + player.update(terrainHeight); + dbgObj.setPosition(*cameraInfo.looksAt); renderer.clear(); diff --git a/demo/src/states/game/player/camera.cpp b/demo/src/states/game/player/camera.cpp index 6be3c9f..1974220 100644 --- a/demo/src/states/game/player/camera.cpp +++ b/demo/src/states/game/player/camera.cpp @@ -21,7 +21,7 @@ Camera::Camera(Pad* t_pad) : lookAt(0.0F), position(0.0F), pad(t_pad) { Camera::~Camera() {} -void Camera::update(const Vec4& playerPosition) { +void Camera::update(const Vec4& playerPosition, const float& terrainHeight) { const float rotationOffset = 0.03F; const float heightOffset = 0.5F; @@ -40,7 +40,7 @@ void Camera::update(const Vec4& playerPosition) { } unitCircle.x = (sin(circleRotation) * lengthFromOrigin); - unitCircle.y = height + playerPosition.y; + unitCircle.y = height + playerPosition.y + terrainHeight; unitCircle.z = (cos(circleRotation) * lengthFromOrigin); lookAt = unitCircle + playerPosition; diff --git a/demo/src/states/game/player/player.cpp b/demo/src/states/game/player/player.cpp index 706e1ec..365c260 100644 --- a/demo/src/states/game/player/player.cpp +++ b/demo/src/states/game/player/player.cpp @@ -18,7 +18,7 @@ Player::Player(Engine* engine) camera(&engine->pad) { staticPairs.push_back(new RendererStaticPair{weapon.mesh, weapon.options}); pad = &engine->pad; - position = Vec4(3.0F, 15.0F, 0.0F); + position = Vec4(3.0F, 50.0F, 0.0F); camera.lookAt = Vec4(0.0F, 0.0F, -30.0F); speed = 2.0F; } @@ -32,13 +32,13 @@ Player::~Player() { } } -void Player::update() { - handlePlayerPosition(); - camera.update(position); +void Player::update(const float& terrainHeight) { + handlePlayerPosition(terrainHeight); + camera.update(position, terrainHeight); weapon.update(); } -void Player::handlePlayerPosition() { +void Player::handlePlayerPosition(const float& terrainHeight) { const auto& leftJoy = pad->getLeftJoyPad(); auto normalizedCamera = Vec4(camera.unitCircle); @@ -46,6 +46,7 @@ void Player::handlePlayerPosition() { normalizedCamera *= speed; Vec4 nextPosition(position); + nextPosition.y = terrainHeight; if (leftJoy.v <= 100) { nextPosition.x += normalizedCamera.x; diff --git a/demo/src/states/game/terrain/heightmap.cpp b/demo/src/states/game/terrain/heightmap.cpp new file mode 100644 index 0000000..64a1da8 --- /dev/null +++ b/demo/src/states/game/terrain/heightmap.cpp @@ -0,0 +1,110 @@ +/* +# ______ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licenced under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/terrain/heightmap.hpp" +#include "file/file_utils.hpp" +#include "debug/debug.hpp" + +using Tyra::FileUtils; +using Tyra::PngLoader; +using Tyra::PngPixel3; +using Tyra::Vec4; + +namespace Demo { + +Heightmap::Heightmap(const float& t_minHeight, const float& t_maxHeight, + const Vec4& t_leftUp, const Vec4& t_rightDown) + : minHeight(t_minHeight), + maxHeight(t_maxHeight), + leftUp(t_leftUp), + rightDown(t_rightDown) { + PngLoader loader; + auto* data = + loader.load(FileUtils::fromCwd("game/models/terrain/heightmap.png")); + + allocateMap(data->data, data->width, data->height); + + delete data; +} + +Heightmap::~Heightmap() { + if (map) { + for (int i = 0; i < mapHeight; i++) { + delete[] map[i]; + } + delete[] map; + } +} + +const float& Heightmap::getHeightOffset(const Vec4& playerPosition) { + float widthPercentage = getWidthPercentage(playerPosition); + float heightPercentage = getHeightPercentage(playerPosition); + + auto x = static_cast(widthPercentage * mapWidth); + auto y = static_cast(heightPercentage * mapHeight); + + TYRA_ASSERT(x >= 0 && x < mapWidth, "x is out of range"); + TYRA_ASSERT(y >= 0 && y < mapHeight, "y is out of range"); + + return map[x][y]; +} + +float Heightmap::getWidthPercentage(const Vec4& playerPosition) { + return (playerPosition.x - leftUp.x) / (rightDown.x - leftUp.x); +} + +float Heightmap::getHeightPercentage(const Vec4& playerPosition) { + return (playerPosition.z - leftUp.z) / (rightDown.z - leftUp.z); +} + +void Heightmap::allocateMap(const unsigned char* data, const int& width, + const int& height) { + auto* pixels = (struct PngPixel3*)data; + + u8 min = pixels[0].r; // in grayscale every r,g,b is the same + u8 max = pixels[0].r; + + // Get min and max + for (int i = 0; i < width * height; i++) { + const auto& value = pixels[i].r; + if (value < min) { + min = value; + } + if (value > max) { + max = value; + } + } + + // Allocate + mapWidth = width; + mapHeight = height; + map = new float*[width]; + for (int i = 0; i < width; i++) { + map[i] = new float[height]; + } + + // Fill + int k = 0; + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + map[i][j] = getGameHeight(pixels[k++].r, min, max); + } + } +} + +float Heightmap::getGameHeight(const u8& inputColor, const u8& minColor, + const u8& maxColor) { + const float mapRange = maxColor - minColor; + const float gameRange = maxHeight - minHeight; + + return (inputColor - minColor) / mapRange * gameRange + minHeight; +} + +} // namespace Demo diff --git a/demo/src/states/game/terrain/terrain.cpp b/demo/src/states/game/terrain/terrain.cpp index 1813c89..233a879 100644 --- a/demo/src/states/game/terrain/terrain.cpp +++ b/demo/src/states/game/terrain/terrain.cpp @@ -16,8 +16,12 @@ using Tyra::FileUtils; using Tyra::TyrobjLoader; namespace Demo { - -Terrain::Terrain(TextureRepository* repo) { +Terrain::Terrain(TextureRepository* repo) + : heightmap(-5.0F, // Min height + 70.0F, // Max height + Vec4(-196.6F, 0.0F, -412.0F, 1.0F), // Left up + Vec4(286.0F, 0.0F, 443.3F, 1.0F) // Right down + ) { TyrobjLoader loader; auto* data = loader.load( FileUtils::fromCwd("game/models/terrain/terrain.obj"), 1, 25.0F, true); @@ -35,14 +39,8 @@ Terrain::Terrain(TextureRepository* repo) { pair = new RendererStaticPair{mesh, options}; } -// float testRotation = 0.0F; - -void Terrain::update() { - // testRotation += 0.001F; - mesh->rotation.identity(); - mesh->rotation.rotateZ(0.1F); - mesh->rotation.rotateY(-4.3F); - // TYRA_LOG(testRotation); +float Terrain::getHeightOffset(const Vec4& playerPosition) { + return heightmap.getHeightOffset(playerPosition); } Terrain::~Terrain() { diff --git a/engine/inc/loaders/texture/png_loader.hpp b/engine/inc/loaders/texture/png_loader.hpp index f6afc16..d122340 100644 --- a/engine/inc/loaders/texture/png_loader.hpp +++ b/engine/inc/loaders/texture/png_loader.hpp @@ -24,11 +24,23 @@ typedef void* png_colorp; namespace Tyra { +struct PngPixel3 { + u8 r, g, b; +}; + +struct PngPixel4 { + u8 r, g, b, a; +}; + class PngLoader : public TextureLoader { public: PngLoader(); ~PngLoader(); + inline TextureBuilderData* load(const std::string& fullpath) { + return load(fullpath.c_str()); + } + TextureBuilderData* load(const char* fullpath); private: diff --git a/engine/src/loaders/texture/png_loader.cpp b/engine/src/loaders/texture/png_loader.cpp index 6344021..a7c17b1 100644 --- a/engine/src/loaders/texture/png_loader.cpp +++ b/engine/src/loaders/texture/png_loader.cpp @@ -107,11 +107,7 @@ void PngLoader::handle32bpp(TextureBuilderData* result, png_structp pngPtr, png_read_image(pngPtr, rowPointers); - struct Pixel { - u8 r, g, b, a; - }; - - struct Pixel* pixels = (struct Pixel*)result->data; + struct PngPixel4* pixels = (struct PngPixel4*)result->data; int k = 0; for (int i = 0; i < result->height; i++) { @@ -145,10 +141,7 @@ void PngLoader::handle24bpp(TextureBuilderData* result, png_structp pngPtr, png_read_image(pngPtr, rowPointers); - struct Pixel3 { - u8 r, g, b; - }; - struct Pixel3* pixels = (struct Pixel3*)result->data; + struct PngPixel3* pixels = (struct PngPixel3*)result->data; int k = 0; for (int i = 0; i < result->height; i++) {