Spieleprogrammierung/RubiksCube/PartitionedCube.h
2025-01-19 14:17:36 +01:00

180 lines
5.4 KiB
C++

#pragma once
#include "Color.h"
#include <stdint.h>
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <glm/ext/quaternion_float.hpp>
#include <math.h>
#include <vector>
#include "Entity.h"
#include "Texture.h"
#include "Shader.h"
#include "Mesh.h"
struct VertexData {
glm::vec3 position;
glm::vec3 normal;
glm::vec2 uv0;
glm::vec3 tangent;
glm::vec3 bitangent;
Color color;
VertexData(const glm::vec3& position, const glm::vec3& normal, const glm::vec2 uv0, Color color) : position(position), color(color), normal(normal), uv0(uv0), tangent(0.0f), bitangent(0.0f) {
}
};
class PartitionedCubeMesh : public Mesh<VertexData> {
private:
static Shader _shader;
static Texture _diffuse;
static Texture _roughness;
static Texture _normal;
GLuint _uniformDiffuse;
GLuint _uniformRoughness;
GLuint _uniformNormal;
public:
PartitionedCubeMesh() : Mesh(&_shader) {
_shader.Use();
glBindVertexArray(_vba);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
int shd = shader->Reference();
_uniformDiffuse = glGetUniformLocation(shd, "diffuse");
_uniformRoughness = glGetUniformLocation(shd, "roughness");
_uniformNormal = glGetUniformLocation(shd, "normal");
glUniform1i(_uniformDiffuse, 0);
glUniform1i(_uniformRoughness, 1);
glUniform1i(_uniformNormal, 2);
glVertexAttribPointer(glGetAttribLocation(shd, "position"), 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, position));
glVertexAttribPointer(glGetAttribLocation(shd, "normal"), 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, normal));
glVertexAttribPointer(glGetAttribLocation(shd, "uv0"), 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, uv0));
glVertexAttribPointer(glGetAttribLocation(shd, "tangent"), 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, tangent));
glVertexAttribPointer(glGetAttribLocation(shd, "bitangent"), 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, bitangent));
glVertexAttribPointer(glGetAttribLocation(shd, "color"), 4, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, color));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
_shader.Disable();
}
virtual void Render(const DefaultUniform& uniform) override {
_shader.Use();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _diffuse.Reference());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _roughness.Reference());
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, _normal.Reference());
_shader.Disable();
Mesh::Render(uniform);
}
static void LoadResources() {
_diffuse = Texture("diffuse.png");
_roughness = Texture("roughness.png");
_normal = Texture("normal.png");
}
void CalculateTangents() {
for(int i=0;i<_vertexData.size();i += 3) {
VertexData& d0 = _vertexData.at(i + 0);
VertexData& d1 = _vertexData.at(i + 1);
VertexData& d2 = _vertexData.at(i + 2);
glm::vec3 deltaPos1 = d1.position - d0.position;
glm::vec3 deltaPos2 = d2.position - d0.position;
glm::vec2 deltaUV1 = d1.uv0 - d0.uv0;
glm::vec2 deltaUV2 = d2.uv0 - d0.uv0;
float r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
d0.tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
d0.bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r;
d1.tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
d1.bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r;
d2.tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
d2.bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r;
}
}
};
enum Side {
Left, Right, Bottom, Top, Back, Forward
};
constexpr glm::vec3 SideToDirection[6] = {
glm::vec3(-1.0f, 0.0f, 0.0f),
glm::vec3(1.0f, 0.0f, 0.0f),
glm::vec3(0.0f, -1.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(0.0f, 0.0f, -1.0f),
glm::vec3(0.0f, 0.0f, 1.0f),
};
class Cube;
class PartitionedCube : public Entity
{
private:
glm::mat4 _transformTem;
glm::quat _animationTransform;
float _animationTime;
float _animationTimeExtend;
bool _animationFinished;
Color _faces[6];
PartitionedCubeMesh _mesh;
public:
PartitionedCube(Cube* parent, const glm::vec3& position, Color* sideColors);
void Update(double deltaTime) override;
void Render(DefaultUniform& uniform) override;
const glm::mat4 TransformCustom() const {
// Need to use slerp since rotations are non-linear and would not interpolate this way
//
// However a lerp can be used and then normalized, with not that much of an
// error but being much more performant thus preferred function
if (false == _animationFinished) {
float lerpFactor = 1.0f - ( _animationTime / _animationTimeExtend);
glm::mat4 animationView = glm::mat4_cast(glm::normalize(glm::lerp(glm::quat(1.0f, 0.0f, 0.0f, 0.0f), _animationTransform, lerpFactor)));
return Parent()->LocalToWorld() * animationView * LocalObjectTransform();
}
return Parent()->LocalToWorld() * _transformTem * LocalObjectTransform();
}
void TransformData(const glm::ivec3& axis, int turns);
void TransformAnimation(const glm::quat& transform, float duration);
void TransformTemp(const glm::mat4& transform);
void UndoTransformTemp();
};