#pragma once #include "Color.h" #include #include #include #include #include #include #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 { 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(); };