Restore pixel perfect camera code.

This commit is contained in:
2024-11-25 20:59:29 -06:00
parent a2c841288d
commit de55029356
19 changed files with 245 additions and 31 deletions

View File

@ -8,11 +8,11 @@
using namespace Dawn;
void SimpleComponent::onInit() {
this->initMethod(*this, events);
this->initMethod(*this, this->events);
}
void SimpleComponent::onDispose() {
for(auto &event : events) {
for(auto &event : this->events) {
event();
}
}

View File

@ -8,9 +8,6 @@
namespace Dawn {
class SimpleComponent final : public SceneComponent {
private:
std::vector<std::function<void()>> events;
public:
std::function<void(
SceneComponent&,

View File

@ -56,6 +56,20 @@ float_t Camera::getAspect() {
return rt->getWidth() / rt->getHeight();
}
float_t Camera::lookAtPixelPerfect(
const glm::vec3 &position,
const glm::vec3 &look,
const float_t &scale
) {
return this->getItem()->lookAtPixelPerfect(
position,
look,
this->getRenderTarget()->getHeight(),
this->fov,
scale
);
}
void Camera::setRenderTarget(std::shared_ptr<RenderTarget> renderTarget) {
onResizeListener();
this->renderTarget = renderTarget;

View File

@ -57,6 +57,20 @@ namespace Dawn {
*/
glm::mat4 getProjection();
/**
* Shorthand for getItem()->lookAtPixelPerfect()
*
* @param position Position to look from.
* @param look Position to look at.
* @param scale Scale to use. At scale 1 then the centerest pixel is 1:1.
* @return The Z distance that was calculated.
*/
float_t lookAtPixelPerfect(
const glm::vec3 &position,
const glm::vec3 &look,
const float_t &scale = 1.0f
);
/**
* Sets the render target for this camera.
*

View File

@ -35,6 +35,7 @@ void IGame::init() {
void IGame::update() {
this->assetManager->update();
this->inputManager.update();
if(nextFrameScene) {
nextFrameScene->stage();

View File

@ -5,17 +5,17 @@
#pragma once
#include "util/Math.hpp"
#include "input/InputBind.hpp"
namespace Dawn {
class DawnGame;
typedef int_fast16_t inputbind_t;
template<typename T>
class IInputManager {
protected:
std::unordered_map<inputbind_t, std::vector<T>> binds;
std::unordered_map<inputbind_t, float_t> valuesLeft;
std::unordered_map<inputbind_t, float_t> valuesRight;
std::unordered_map<enum InputBind, std::vector<T>> binds;
std::unordered_map<enum InputBind, float_t> valuesLeft;
std::unordered_map<enum InputBind, float_t> valuesRight;
bool_t currentIsLeft = true;
/**
@ -34,7 +34,7 @@ namespace Dawn {
* @param bind Bind to bind the axis to.
* @param axis Axis to use for this bind.
*/
void bind(const inputbind_t bind, const T axis) {
void bind(const enum InputBind bind, const T axis) {
this->binds[bind].push_back(axis);
}
@ -43,7 +43,7 @@ namespace Dawn {
*
* @param bind Bind to remove all binds from.
*/
void unbind(const inputbind_t bind) {
void unbind(const enum InputBind bind) {
this->binds[bind].clear();
}
@ -61,7 +61,7 @@ namespace Dawn {
* @param bind Bind to get the value of.
* @return The current input state (between 0 and 1).
*/
float_t getValue(const inputbind_t bind) {
float_t getValue(const enum InputBind bind) {
if(this->currentIsLeft) {
auto exist = this->valuesLeft.find(bind);
return exist == this->valuesLeft.end() ? 0.0f : exist->second;
@ -77,7 +77,7 @@ namespace Dawn {
* @param bind Bind to get the value of.
* @return The value of the bind, last frame.
*/
float_t getValueLastUpdate(const inputbind_t bind) {
float_t getValueLastUpdate(const enum InputBind bind) {
if(this->currentIsLeft) {
auto exist = this->valuesRight.find(bind);
return exist == this->valuesRight.end() ? 0.0f : exist->second;
@ -99,15 +99,15 @@ namespace Dawn {
* @param positive Bind to use for the positive axis.
* @return A value between -1 and 1.
*/
float_t getAxis(const inputbind_t negative, const inputbind_t positive) {
float_t getAxis(const enum InputBind negative, const enum InputBind positive) {
return -getValue(negative) + getValue(positive);
}
glm::vec2 getAxis2D(
const inputbind_t negativeX,
const inputbind_t positiveX,
const inputbind_t negativeY,
const inputbind_t positiveY
const enum InputBind negativeX,
const enum InputBind positiveX,
const enum InputBind negativeY,
const enum InputBind positiveY
) {
return glm::vec2(
getAxis(negativeX, positiveX),
@ -122,7 +122,7 @@ namespace Dawn {
* @param y Y Axis bind.
* @return 2D vector of the two given input binds.
*/
glm::vec2 getAxis2D(const inputbind_t x, const inputbind_t y) {
glm::vec2 getAxis2D(const enum InputBind x, const enum InputBind y) {
return glm::vec2(getValue(x), getValue(y));
}
@ -133,7 +133,7 @@ namespace Dawn {
* @param bind Bind to check if pressed.
* @return True if value is non-zero, or false for zero.
*/
bool_t isDown(const inputbind_t bind) {
bool_t isDown(const enum InputBind bind) {
return this->getValue(bind) != 0.0f;
}
@ -144,7 +144,7 @@ namespace Dawn {
* @param bind Bind to check if pressed.
* @return True if down this frame and not down last frame.
*/
bool_t isPressed(const inputbind_t bind) {
bool_t isPressed(const enum InputBind bind) {
return this->getValue(bind) != 0 && this->getValueLastUpdate(bind) == 0;
}
@ -155,7 +155,7 @@ namespace Dawn {
* @param bind Bind to check if released.
* @return True if up this frame, and down last frame.
*/
bool_t wasReleased(const inputbind_t bind) {
bool_t wasReleased(const enum InputBind bind) {
return this->getValue(bind) == 0 && this->getValueLastUpdate(bind) != 0;
}

View File

@ -20,6 +20,7 @@ void SceneComponent::init(const std::shared_ptr<SceneItem> item) {
sceneComponentState,
SCENE_COMPONENT_STATE_INIT
);
this->events.clear();
this->item = item;
this->onInit();
}
@ -39,6 +40,11 @@ void SceneComponent::dispose() {
sceneComponentState,
SCENE_COMPONENT_STATE_DISPOSED
);
for(auto &event : this->events) {
event();
}
this->events.clear();
this->onDispose();
this->item.reset();
}

View File

@ -20,6 +20,8 @@ namespace Dawn {
uint_fast8_t sceneComponentState = 0;
protected:
std::vector<std::function<void()>> events;
/**
* Custom component listener that is invoked when the component is meant
* to initialize.

View File

@ -168,6 +168,25 @@ void SceneItemTransform::lookAt(
this->setWorldTransform(glm::lookAt(position, target, up));
}
float_t SceneItemTransform::lookAtPixelPerfect(
const glm::vec3 &position,
const glm::vec3 &look,
const float_t &viewportHeight,
const float_t &fov,
const float_t &scale
) {
float_t z = (
tanf((glm::radians(180.0f) - fov) / 2.0f) *
(viewportHeight/2.0f)
) / scale;
this->lookAt(
glm::vec3(position.x, position.y, position.z + z),
look,
glm::vec3(0, 1, 0)
);
return z;
}
SceneItemTransform::~SceneItemTransform() {
std::for_each(
this->children.begin(),

View File

@ -164,6 +164,24 @@ namespace Dawn {
const glm::vec3 up
);
/**
* Shorthand combined for lookAt and perspectivePixelPerfectDistance
* to allow you to create pixel perfect lookAt camera view matricies.
*
* @param position Position of the camera. Z is for an offset.
* @param look Position in world space this transform looks at.
* @param viewportHeight Height of the viewport.
* @param fov Field of view (in radians).
* @return The Z distance that was calculated.
*/
float_t lookAtPixelPerfect(
const glm::vec3 &position,
const glm::vec3 &look,
const float_t &viewportHeight,
const float_t &fov,
const float_t &scale = 1.0f
);
virtual ~SceneItemTransform();
};
}

View File

@ -33,17 +33,24 @@ void InputManager::init(const std::shared_ptr<Game> game) {
);
});
glfwSetMouseButtonCallback(window, [](
glfwSetKeyCallback(window, [](
GLFWwindow* window,
int32_t button,
int32_t key,
int32_t scancode,
int32_t action,
int32_t mods
) {
auto game = (Game*)glfwGetWindowUserPointer(window);
game->inputManager.rawInputValues[button] = (
game->inputManager.rawInputValues[key] = (
action == GLFW_PRESS ? 1.0f : 0.0f
);
});
// Default bindings
this->bind(InputBind::UP, GLFW_KEY_W);
this->bind(InputBind::DOWN, GLFW_KEY_S);
this->bind(InputBind::LEFT, GLFW_KEY_A);
this->bind(InputBind::RIGHT, GLFW_KEY_D);
}
float_t InputManager::getInputValue(int32_t axis) {

View File

@ -10,6 +10,7 @@ target_include_directories(${DAWN_TARGET_NAME}
)
# Subdirs
add_subdirectory(component)
add_subdirectory(game)
add_subdirectory(scene)

View File

@ -0,0 +1,10 @@
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DAWN_TARGET_NAME}
PRIVATE
RPGEntity.cpp
RPGPlayer.cpp
)

View File

@ -0,0 +1,15 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "RPGEntity.hpp"
#include "scene/Scene.hpp"
using namespace Dawn;
void RPGEntity::onInit() {
}
void RPGEntity::onDispose() {
}

View File

@ -0,0 +1,19 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "component/display/Camera.hpp"
#define RPG_ENTITY_SIZE 16.0f
namespace Dawn {
class RPGEntity final : public SceneComponent {
private:
public:
void onInit() override;
void onDispose() override;
};
}

View File

@ -0,0 +1,46 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "RPGPlayer.hpp"
#include "scene/Scene.hpp"
#include "RPGEntity.hpp"
using namespace Dawn;
void RPGPlayer::onInit() {
events.push_back(getScene()->onUnpausedUpdate.listen([&](
float_t d
) {
glm::vec2 movement = getGame()->inputManager.getAxis2D(
InputBind::LEFT, InputBind::RIGHT,
InputBind::UP, InputBind::DOWN
);
if(movement.x != 0 || movement.y != 0) {
// Normalize angle.
float_t angle = atan2(movement.x, movement.y);
angle -= Math::deg2rad(90.0f);
movement = glm::vec2(cosf(angle), sinf(angle)) * PLAYER_SPEED * d;
// Update position.
auto ePos = getItem()->getLocalPosition();
ePos.x += movement.x;
ePos.y += movement.y;
getItem()->setLocalPosition(ePos);
}
if(this->camera != nullptr) {
this->camera->lookAtPixelPerfect(
getItem()->getLocalPosition() + glm::vec3(0, -32.0f, 0),
getItem()->getLocalPosition(),
2.0f
);
}
}));
}
void RPGPlayer::onDispose() {
}

View File

@ -0,0 +1,21 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "component/display/Camera.hpp"
#define PLAYER_SPEED 5.0f
namespace Dawn {
class RPGPlayer final : public SceneComponent {
private:
public:
std::shared_ptr<Camera> camera;
void onInit() override;
void onDispose() override;
};
}

View File

@ -0,0 +1,16 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
namespace Dawn {
enum class InputBind : int_fast16_t {
UP,
DOWN,
LEFT,
RIGHT
};
}

View File

@ -11,6 +11,9 @@
#include "display/mesh/QuadMesh.hpp"
#include "component/ui/UICanvas.hpp"
#include "component/RPGEntity.hpp"
#include "component/RPGPlayer.hpp"
using namespace Dawn;
void Dawn::helloWorldScene(Scene &s) {
@ -20,12 +23,12 @@ void Dawn::helloWorldScene(Scene &s) {
auto cameraItem = s.createSceneItem();
auto camera = cameraItem->addComponent<Camera>();
cameraItem->lookAt({ 3, 3, 3 }, { 0, 0, 0 }, { 0, 1, 0 });
camera->clipFar = 99999.99f;
glm::vec2 position = { 0, 0 };
glm::vec2 size = { 1, 1 };
auto quad = s.createSceneItem();
auto player = s.createSceneItem();
glm::vec2 size = { RPG_ENTITY_SIZE, RPG_ENTITY_SIZE };
glm::vec2 position = -size;
auto quadMesh = std::make_shared<Mesh>();
quadMesh->createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT);
QuadMesh::buffer(
@ -35,12 +38,17 @@ void Dawn::helloWorldScene(Scene &s) {
0, 0, 0
);
auto quadRenderer = quad->addComponent<MeshRenderer>();
auto quadRenderer = player->addComponent<MeshRenderer>();
quadRenderer->mesh = quadMesh;
auto quadMaterial = quad->addComponent<SimpleTexturedMaterial>();
auto quadMaterial = player->addComponent<SimpleTexturedMaterial>();
quadMaterial->setColor(COLOR_WHITE);
auto ent = player->addComponent<RPGEntity>();
auto ePlyr = player->addComponent<RPGPlayer>();
ePlyr->camera = camera;
auto uiCanvasItem = s.createSceneItem();
auto uiCanvas = uiCanvasItem->addComponent<UICanvas>();
}