#include "basicOrderedSpriteSetShader.hpp" #include "BehaviourScripts/Renderable.hpp" #include "BehaviourScripts/OrdererSpriteSet.hpp" #include "Color.hpp" #include "basicOrderedSpriteSetShaderGLSL.hpp" using namespace TSE; using namespace TSE::OpenGL; #define SHADER_MESH_INDEX 0 #define SHADER_POS_INDEX 1 #define SHADER_LAYER_HEIGHT_INDEX 2 #define SHADER_SPRITE_INDEX 3 #define SHADER_NORMAL_INDEX 4 #define SHADER_SCALE_INDEX 5 #define SHADER_PACKAGE_SIZE sizeof(float) * (3 + 1 + 1 + 1 + 2) TSE::OpenGL::BasicOrderedSpriteSetShader* BasicOrderedSpriteSetShader::instance = nullptr; TSE::OpenGL::BasicOrderedSpriteSetShader *TSE::OpenGL::BasicOrderedSpriteSetShader::Instance() { return instance; } void TSE::OpenGL::BasicOrderedSpriteSetShader::Destroy() { if(instance != nullptr) delete instance; instance = nullptr; } void TSE::OpenGL::BasicOrderedSpriteSetShader::Init(float width, float height) { std::vector> parts; parts.push_back(ShaderPart::LoadFromString(vertOrderedSet, GL_VERTEX_SHADER)); parts.push_back(ShaderPart::LoadFromString(fragOrderedSet, GL_FRAGMENT_SHADER)); instance = new BasicOrderedSpriteSetShader(std::move(parts)); instance->Enable(); int texIDs[] = { 0 }; instance->SetUniform("atlas", 0); instance->Disable(); } TSE::OpenGL::BasicOrderedSpriteSetShader::BasicOrderedSpriteSetShader(std::vector> &&parts) : Shader(parts) { PackageSize = SHADER_PACKAGE_SIZE; } TSE::OpenGL::BasicOrderedSpriteSetShader::~BasicOrderedSpriteSetShader() { if (meshVBO) glDeleteBuffers(1, &meshVBO); if (meshIBO) glDeleteBuffers(1, &meshIBO); } void TSE::OpenGL::BasicOrderedSpriteSetShader::SetMesh(const void *verts, int vertCount, int stride, int floatCountPerVertex, int posOffsetBytes, GLenum primitive, const void *indices, int indexCount, GLenum indexType) { GLint prevVAO = 0, prevArrayBuffer = 0, prevElementBuffer = 0; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &prevVAO); glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prevArrayBuffer); glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &prevElementBuffer); if (!meshVBO) glGenBuffers(1, &meshVBO); glBindBuffer(GL_ARRAY_BUFFER, meshVBO); glBufferData(GL_ARRAY_BUFFER, vertCount * stride, verts, GL_STATIC_DRAW); if (indices && indexCount > 0) { if (!meshIBO) glGenBuffers(1, &meshIBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshIBO); GLsizeiptr idxSize = (indexType == GL_UNSIGNED_INT ? 4 : indexType == GL_UNSIGNED_SHORT? 2 : 1) * indexCount; glBufferData(GL_ELEMENT_ARRAY_BUFFER, idxSize, indices, GL_STATIC_DRAW); meshIndexCount = indexCount; meshIndexType = indexType; } else { // Kein Index-Buffer if (meshIBO) { glDeleteBuffers(1, &meshIBO); meshIBO = 0; } meshIndexCount = 0; } meshVertexCount = vertCount; meshStride = stride; meshPosOffset = posOffsetBytes; meshPosSize = floatCountPerVertex; meshPrimitive = primitive; meshReady = true; glBindBuffer(GL_ARRAY_BUFFER, prevArrayBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prevElementBuffer); glBindVertexArray(prevVAO); } void TSE::OpenGL::BasicOrderedSpriteSetShader::OnEnable() const { if (!meshReady) { // Fallback: unit-Quad als TRIANGLE_FAN (4 Vertices, 2D Positionen) const float quad[8] = { -0.5f,0, 0.5f,0, 0.5f,1, -0.5f,1 }; const_cast(this)->SetMesh( quad, 4, sizeof(float)*2, 2, 0, GL_TRIANGLE_FAN ); } GLint prevArrayBuffer = 0; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prevArrayBuffer); glBindBuffer(GL_ARRAY_BUFFER, meshVBO); glEnableVertexAttribArray(SHADER_MESH_INDEX); // LOC_QUAD/pos glVertexAttribPointer(SHADER_MESH_INDEX, meshPosSize, GL_FLOAT, GL_FALSE, meshStride, (void*)meshPosOffset); glVertexAttribDivisor(SHADER_MESH_INDEX, 0); // per-vertex (Mesh) glBindBuffer(GL_ARRAY_BUFFER, prevArrayBuffer); glEnableVertexAttribArray(SHADER_POS_INDEX); glVertexAttribPointer(SHADER_POS_INDEX, 3, GL_FLOAT, GL_FALSE, PackageSize, (void*)0); glVertexAttribDivisor(SHADER_POS_INDEX, 1); glEnableVertexAttribArray(SHADER_LAYER_HEIGHT_INDEX); glVertexAttribPointer(SHADER_LAYER_HEIGHT_INDEX, 1, GL_FLOAT, GL_FALSE, PackageSize, (void*)(sizeof(float)*3)); glVertexAttribDivisor(SHADER_LAYER_HEIGHT_INDEX, 1); glEnableVertexAttribArray(SHADER_SPRITE_INDEX); glVertexAttribPointer(SHADER_SPRITE_INDEX, 1, GL_FLOAT, GL_FALSE, PackageSize, (void*)(sizeof(float)*4)); glVertexAttribDivisor(SHADER_SPRITE_INDEX, 1); glEnableVertexAttribArray(SHADER_NORMAL_INDEX); glVertexAttribPointer(SHADER_NORMAL_INDEX, 1, GL_FLOAT, GL_FALSE, PackageSize, (void*)(sizeof(float)*5)); glVertexAttribDivisor(SHADER_NORMAL_INDEX, 1); glEnableVertexAttribArray(SHADER_SCALE_INDEX); glVertexAttribPointer(SHADER_SCALE_INDEX, 2, GL_FLOAT, GL_FALSE, PackageSize, (void*)(sizeof(float)*6)); glVertexAttribDivisor(SHADER_SCALE_INDEX, 1); } void TSE::OpenGL::BasicOrderedSpriteSetShader::OnDisable() const { glDisableVertexAttribArray(SHADER_MESH_INDEX); glDisableVertexAttribArray(SHADER_POS_INDEX); glDisableVertexAttribArray(SHADER_LAYER_HEIGHT_INDEX); glDisableVertexAttribArray(SHADER_SPRITE_INDEX); glDisableVertexAttribArray(SHADER_NORMAL_INDEX); glDisableVertexAttribArray(SHADER_SCALE_INDEX); } void TSE::OpenGL::BasicOrderedSpriteSetShader::OnFlush() { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, TextureID); glDisable(GL_BLEND); } void TSE::OpenGL::BasicOrderedSpriteSetShader::OnDrawCall(int indexCount) { if (instanceCount <= 0) return; SetUniform("spriteCount", &SpriteCount); GLint prevElementBuffer = 0; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &prevElementBuffer); if (meshIBO && meshIndexCount > 0) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshIBO); glDrawElementsInstanced(meshPrimitive, meshIndexCount, meshIndexType, (void*)0, instanceCount); } else { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDrawArraysInstanced(meshPrimitive, 0, meshVertexCount, instanceCount); } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)prevElementBuffer); } void TSE::OpenGL::BasicOrderedSpriteSetShader::OnPostDraw() { glEnable(GL_BLEND); instanceCount = 0; } void TSE::OpenGL::BasicOrderedSpriteSetShader::OnSubmit(const Transformable &t, float *&target, TransformationStack &stack, void (*restartDrawcall)(IRenderer &), IRenderer &rnd) { auto* r = dynamic_cast(t.GetBehaviourScript(RENDERABLE)); if (!r) return; auto* tm = dynamic_cast(t.GetBehaviourScript(ORDERERSPRITESET)); if (!tm) return; auto tileSet = tm->GetTileSet(); TextureID = tileSet->GetTextueID(); SpriteCount = tileSet->GetCount(); const std::vector orderedChunks = *tm->GetChunkPositionsInOrder(); Matrix4x4 matr = t.GetLocalMatrix(); stack.Push(matr); for(auto chunkPos : orderedChunks) { auto chunk = tm->GetChunk(chunkPos); const int spriteCount = chunk->GetSpriteCount(); const std::vector spritePositions = *chunk->GetOrderedPositions(); const std::vector spriteIds = *chunk->GetOrderedSpriteIds(); const std::vector spriteScales = *chunk->GetOrderedScales(); int chunkSize = chunk->GetChunksize(); for (int i = 0; i < spriteCount; i++) { Matrix4x4 mat = Matrix4x4::ToTranslationMatrix(chunkPos + spritePositions[i].ToVector2()) * Matrix4x4::ToRotationMatrix(Quaternion()) * Matrix4x4::ToScaleMatrix({1,1,1}); stack.Push(mat); Vector3 pos = stack.Top() * Vector3(0,0,0); *target++ = pos.x; *target++ = pos.y; *target++ = pos.z; *target++ = spritePositions[i].z; *target++ = spriteIds[i].x; *target++ = spriteIds[i].y; *target++ = spriteScales[i].x; *target++ = spriteScales[i].y; ++instanceCount; stack.Pop(); if(instanceCount >= 16000) restartDrawcall(rnd); } } stack.Pop(); restartDrawcall(rnd); }