summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/AssetManager.cpp15
-rw-r--r--src/AssetManager.hpp15
-rw-r--r--src/TextureAtlas.cpp104
-rw-r--r--src/TextureAtlas.hpp35
4 files changed, 167 insertions, 2 deletions
diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp
index 25e9f24..9e360c0 100644
--- a/src/AssetManager.cpp
+++ b/src/AssetManager.cpp
@@ -603,7 +603,20 @@ AssetTreeNode * AssetManager::GetAssetByAssetName(const std::string & assetName)
}
void AssetManager::LoadTextures() {
-
+ std::vector<TextureData> textureData;
+ size_t id = 0;
+ RecursiveWalkAsset("/minecraft/textures/", [&](AssetTreeNode &node) {
+ TextureData data;
+ AssetTexture *textureAsset = dynamic_cast<AssetTexture*>(node.asset.get());
+ if (!textureAsset)
+ return;
+ data.data = std::move(textureAsset->textureData);
+ data.width = textureAsset->realWidth;
+ data.height = textureAsset->realHeight;
+ textureData.push_back(data);
+ textureAsset->id = id++;
+ });
+ atlas = std::make_unique<TextureAtlas>(textureData);
}
void AssetManager::ParseAssetTexture(AssetTreeNode &node) {
diff --git a/src/AssetManager.hpp b/src/AssetManager.hpp
index b8748ae..1b64215 100644
--- a/src/AssetManager.hpp
+++ b/src/AssetManager.hpp
@@ -11,6 +11,7 @@
#include "Vector.hpp"
#include "Block.hpp"
+#include "TextureAtlas.hpp"
class Texture;
@@ -160,8 +161,8 @@ struct AssetBlockModel : Asset {
struct AssetTexture : Asset {
std::vector<unsigned char> textureData;
- double x, y, w, h;
unsigned int realWidth, realHeight;
+ size_t id;
};
class AssetManager {
@@ -171,6 +172,7 @@ class AssetManager {
std::map<BlockTextureId,glm::vec4> textureAtlasIndexes;
std::map<BlockId, std::string> blockIdToBlockName;
std::unique_ptr<AssetTreeNode> assetTree;
+ std::unique_ptr<TextureAtlas> atlas;
public:
AssetManager();
@@ -219,4 +221,15 @@ public:
void LoadTextures();
void ParseAssetTexture(AssetTreeNode &node);
+
+ inline GLuint GetTextureAtlasId() {
+ return atlas->GetRawTextureId();
+ }
+
+ inline TextureCoord GetTexture(const std::string assetName) {
+ AssetTexture *asset = GetAsset<AssetTexture>(assetName);
+ if (!asset)
+ return {};
+ return atlas->GetTexture(asset->id);
+ }
};
diff --git a/src/TextureAtlas.cpp b/src/TextureAtlas.cpp
new file mode 100644
index 0000000..23ab92d
--- /dev/null
+++ b/src/TextureAtlas.cpp
@@ -0,0 +1,104 @@
+#include "TextureAtlas.hpp"
+
+#define STB_RECT_PACK_IMPLEMENTATION
+
+#include <stb_rect_pack.h>
+#include <easylogging++.h>
+
+#include "Utility.hpp"
+
+TextureAtlas::TextureAtlas(std::vector<TextureData> &textures) {
+ LOG(INFO) << "Initializing texture atlas...";
+ LOG(INFO) << "Textures count: " << textures.size();
+
+ //Texture packing
+ const int textureSize = 1024;
+
+ std::vector<stbrp_rect> totalRects;
+ for (int i = 0; i < textures.size(); i++) {
+ stbrp_rect rect;
+ rect.id = i;
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = textures[i].width;
+ rect.h = textures[i].height;
+ rect.was_packed = 0;
+ totalRects.push_back(rect);
+ }
+
+ textureCoords.resize(textures.size());
+
+ int layer = 0;
+ for (;;layer++) {
+ stbrp_context context;
+ std::vector<stbrp_node> nodes;
+ int nodesCount = textureSize * 2;
+ nodes.resize(nodesCount);
+ stbrp_init_target(&context, textureSize, textureSize, nodes.data(), nodesCount);
+
+ std::vector<stbrp_rect> rects;
+ for (const auto &it : totalRects) {
+ if (it.was_packed != 0)
+ continue;
+
+ rects.push_back(it);
+ }
+ stbrp_pack_rects(&context, rects.data(), rects.size());
+
+ int unpackedTextures = 0;
+ for (auto &it : rects) {
+ if (!it.was_packed) {
+ unpackedTextures++;
+ continue;
+ }
+ textureCoords[it.id].pixelX = it.x;
+ textureCoords[it.id].pixelY = it.y;
+ textureCoords[it.id].pixelW = it.w;
+ textureCoords[it.id].pixelH = it.h;
+ textureCoords[it.id].layer = layer;
+ textureCoords[it.id].x = (double)it.x / textureSize;
+ textureCoords[it.id].y = (double)it.y / textureSize;
+ textureCoords[it.id].w = (double)it.w / textureSize;
+ textureCoords[it.id].h = (double)it.h / textureSize;
+ totalRects[it.id].was_packed = 1;
+ }
+ if (unpackedTextures == 0)
+ break;
+ }
+ LOG(INFO) << "Texture atlas size is " << textureSize << "x" << textureSize << "x" << layer;
+
+ //OpenGL
+ int mipLevelCount = 1;
+
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
+ glTexStorage3D(GL_TEXTURE_2D_ARRAY, mipLevelCount, GL_RGBA8, textureSize, textureSize, layer+1);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glCheckError();
+
+ //Uploading texture data
+ for (int i = 0; i < textureCoords.size(); i++) {
+ size_t bytesPerLine = textureCoords[i].pixelW * 4;
+ for (int y = 0; y < textureCoords[i].pixelH / 2; y++) {
+ int invY = textureCoords[i].pixelH - y - 1;
+ unsigned char *src = textures[i].data.data() + y * bytesPerLine;
+ unsigned char *dst = textures[i].data.data() + invY * bytesPerLine;
+ for (int j = 0; j < bytesPerLine; j++) {
+ std::swap(*(src + j), *(dst + j));
+ }
+ }
+ glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, textureCoords[i].pixelX, textureSize - textureCoords[i].pixelY - textureCoords[i].pixelH, textureCoords[i].layer,
+ textureCoords[i].pixelW, textureCoords[i].pixelH, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, textures[i].data.data());
+ glCheckError();
+ }
+
+ LOG(INFO) << "Texture atlas initialized";
+}
+
+TextureAtlas::~TextureAtlas() {
+ glDeleteTextures(1, &texture);
+}
diff --git a/src/TextureAtlas.hpp b/src/TextureAtlas.hpp
new file mode 100644
index 0000000..76a6c49
--- /dev/null
+++ b/src/TextureAtlas.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <vector>
+
+#include <gl/glew.h>
+
+struct TextureData {
+ std::vector<unsigned char> data; //expected format RGBA8888
+ int width, height;
+};
+
+struct TextureCoord {
+ double x, y, w, h;
+ int pixelX, pixelY, pixelW, pixelH;
+ size_t layer;
+};
+
+class TextureAtlas {
+ GLuint texture;
+ std::vector<TextureCoord> textureCoords;
+public:
+ TextureAtlas(std::vector<TextureData> &textures);
+
+ TextureAtlas(const TextureAtlas &) = delete;
+
+ ~TextureAtlas();
+
+ inline GLuint GetRawTextureId() {
+ return texture;
+ }
+
+ TextureCoord GetTexture(int id) {
+ return textureCoords[id];
+ }
+}; \ No newline at end of file