#include "graphics/instancedraw.h" #include "graphics/texture.h" TileTextureInstance::TileTextureInstance(const char* texturePath) { texture = new Texture(); texture->loadTexture(texturePath); if (texture) setup(); } TileTextureInstance::TileTextureInstance(const std::vector texturePaths) { textures = new TextureArray(); if (textures->loadTextures(texturePaths)) setup(); } void TileTextureInstance::setup() { glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, 0); glGenBuffers(1, &instanceVBO); glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(InstanceData) * MAX_INSTANCES, nullptr, GL_DYNAMIC_DRAW); // tileIndex instanceData layout position 2 glVertexAttribIPointer(2, 1, GL_INT, sizeof(InstanceData), (void*)(offsetof(InstanceData, tileIndex))); glEnableVertexAttribArray(2); glVertexAttribDivisor(2, 1); // textureIndex instanceData layout position 3 -> We are using multiple textures to hold each tileset glVertexAttribIPointer(3, 1, GL_INT, sizeof(InstanceData), (void*)(offsetof(InstanceData, textureIndex))); glEnableVertexAttribArray(3); glVertexAttribDivisor(3, 1); // tilesPerRow instanceData layout position 4, This is needed since we are supporting multiple tilesets // of different sizes glVertexAttribIPointer(4, 1, GL_INT, sizeof(InstanceData), (void*)(offsetof(InstanceData, tilesPerRow))); glEnableVertexAttribArray(4); glVertexAttribDivisor(4, 1); // startID instanceData layout position 5 glVertexAttribIPointer(5, 1, GL_INT, sizeof(InstanceData), (void*)(offsetof(InstanceData, startID))); glEnableVertexAttribArray(5); glVertexAttribDivisor(5, 1); // originalSize instanceData layout position 6 glVertexAttribPointer(6, 2, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (void*)(offsetof(InstanceData, originalSize))); glEnableVertexAttribArray(6); glVertexAttribDivisor(6, 1); // modelMatrix instanceData as 4 vec 4s (a 4x4 matrix) layout head position 7 for (int i = 0; i < 4; i++) { glVertexAttribPointer(7 + i, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (void*)(offsetof(InstanceData, modelMatrix) + (sizeof(glm::vec4) * i))); glEnableVertexAttribArray(7 + i); glVertexAttribDivisor(7 + i, 1); } glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } void TileTextureInstance::updateInstanceData(const std::vector& instanceData) { if (instanceData.empty()) return; numOfInstances = instanceData.size(); glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); InstanceData* instances = (InstanceData*)glMapBufferRange(GL_ARRAY_BUFFER, 0, sizeof(InstanceData) * instanceData.size(), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT); if (!instances) return; if (instances) { std::memcpy(instances, instanceData.data(), sizeof(InstanceData) * instanceData.size()); glUnmapBuffer(GL_ARRAY_BUFFER); } /* for (int i = 0; i < instanceData.size(); i++) { instances[i].modelMatrix = instanceData[i].modelMatrix; instances[i].originalSize = instanceData[i].originalSize; instances[i].tileIndex = instanceData[i].tileIndex; instances[i].textureIndex = instanceData[i].textureIndex; instances[i].tilesPerRow = instanceData[i].tilesPerRow; instances[i].startID = instanceData[i].startID; } */ glBindBuffer(GL_ARRAY_BUFFER, 0); } void TileTextureInstance::draw() { // bind textures if (texture) texture->bind(); else if (textures) textures->bind(); glBindVertexArray(VAO); glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr, numOfInstances); glBindVertexArray(0); } TileTextureInstance::~TileTextureInstance() { if (texture) delete texture; else if (textures) delete textures; glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &EBO); glDeleteVertexArrays(1, &VAO); }