Skip to content

Commit 5b2a175

Browse files
committed
Now using filenames instead of IDs when loading/retrieving textures.
1 parent 42bdc64 commit 5b2a175

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+348
-235
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,5 @@ server/openminer_server
5656

5757
# Misc
5858
*.zip
59+
test_atlas.png
5960

client/include/graphics/TextureAtlas.hpp

+17-8
Original file line numberDiff line numberDiff line change
@@ -17,36 +17,45 @@
1717
#include <memory>
1818
#include <string>
1919
#include <unordered_map>
20+
#include <vector>
2021

2122
#include <gk/core/IntTypes.hpp>
2223
#include <gk/core/SDLHeaders.hpp>
24+
#include <gk/core/Rect.hpp>
25+
#include <gk/gl/Texture.hpp>
2326

2427
class TextureAtlas {
2528
public:
2629
TextureAtlas() = default;
2730

28-
void addFile(const std::string &filename);
31+
void addFile(const std::string &path, const std::string &filename);
2932
void packTextures();
30-
void saveToFile(const std::string &filename);
3133

32-
u16 getTextureID(const std::string &filename);
34+
void loadFromRegistry();
3335

34-
const SDL_Surface *getSurface() const { return m_atlas.get(); }
36+
u16 getTextureID(const std::string &filename) const;
37+
gk::FloatRect getTexCoords(const std::string &filename, bool normalized = true) const;
38+
39+
const gk::Texture &texture() const { return m_texture; }
40+
41+
bool isReady() const { return m_isReady; }
3542

3643
private:
3744
// Expected texture size
38-
u16 m_width = 0;
39-
u16 m_height = 0;
45+
u16 m_tileSize = 0;
4046

4147
// Mapping between filename and internal texture ID
4248
std::unordered_map<std::string, u16> m_textureMap;
4349

4450
// Textures to pack together
4551
using SurfacePtr = std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)>;
46-
std::unordered_map<std::string, SurfacePtr> m_textures;
52+
std::vector<SurfacePtr> m_textures;
4753

4854
// Packed texture
49-
SurfacePtr m_atlas{nullptr, &SDL_FreeSurface};
55+
gk::Texture m_texture;
56+
57+
// Is the texture atlas ready to use?
58+
bool m_isReady = false;
5059
};
5160

5261
#endif // TEXTUREATLAS_HPP_

client/include/gui/Cube.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <gk/gl/VertexBuffer.hpp>
2020

2121
class Block;
22+
class TextureAtlas;
2223

2324
class Cube : public gk::Drawable, public gk::Transformable {
2425
public:
@@ -31,7 +32,7 @@ class Cube : public gk::Drawable, public gk::Transformable {
3132

3233
float m_size = 1.0f;
3334

34-
const gk::Texture &m_texture;
35+
const TextureAtlas &m_textureAtlas;
3536

3637
gk::VertexBuffer m_vbo;
3738
bool m_isVboInitialized = false;

client/include/gui/ItemWidget.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class ItemWidget : public Widget {
3939
unsigned int m_x = 0;
4040
unsigned int m_y = 0;
4141

42+
TextureAtlas &m_textureAtlas;
43+
4244
gk::Image m_image;
4345
Text m_text;
4446

client/include/states/GameState.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "HUD.hpp"
2929
#include "PlayerBox.hpp"
3030

31+
class TextureAtlas;
32+
3133
class GameState : public gk::ApplicationState {
3234
public:
3335
GameState(const std::string &host, int port);
@@ -57,6 +59,8 @@ class GameState : public gk::ApplicationState {
5759
ClientCommandHandler m_clientCommandHandler{m_client, m_world, m_player, m_camera, m_playerBoxes};
5860

5961
HUD m_hud{m_player, m_world, m_clientCommandHandler};
62+
63+
TextureAtlas *m_textureAtlas = nullptr;
6064
};
6165

6266
#endif // GAMESTATE_HPP_

client/include/world/ChunkBuilder.hpp

+5
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@
2525

2626
class Block;
2727
class ClientChunk;
28+
class TextureAtlas;
2829

2930
class ChunkBuilder {
3031
public:
32+
ChunkBuilder(TextureAtlas &textureAtlas) : m_textureAtlas(textureAtlas) {}
33+
3134
static constexpr u8 layers = 3;
3235

3336
std::array<std::size_t, layers> buildChunk(const ClientChunk &chunk, const std::array<gk::VertexBuffer, layers> &vbo);
@@ -62,6 +65,8 @@ class ChunkBuilder {
6265
Front,
6366
Back
6467
};
68+
69+
TextureAtlas &m_textureAtlas;
6570
};
6671

6772
#endif // CHUNKBUILDER_HPP_

client/include/world/ClientChunk.hpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
#include "ChunkBuilder.hpp"
2222
#include "Config.hpp"
2323

24+
class TextureAtlas;
25+
2426
class ClientChunk : public Chunk {
2527
public:
26-
ClientChunk(s32 x, s32 y, s32 z, gk::Texture &texture)
27-
: Chunk(x, y, z), m_texture(texture) {}
28+
ClientChunk(s32 x, s32 y, s32 z, TextureAtlas &textureAtlas)
29+
: Chunk(x, y, z), m_textureAtlas(textureAtlas), m_builder{textureAtlas} {}
2830

2931
void update();
3032

@@ -39,7 +41,7 @@ class ClientChunk : public Chunk {
3941
bool areAllNeighboursTooFar() const;
4042

4143
private:
42-
gk::Texture &m_texture;
44+
TextureAtlas &m_textureAtlas;
4345

4446
ChunkBuilder m_builder;
4547

client/include/world/ClientWorld.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "World.hpp"
2222

2323
class ClientCommandHandler;
24+
class TextureAtlas;
2425

2526
class ClientWorld : public World, public gk::Drawable {
2627
using ChunkMap = std::unordered_map<gk::Vector3i, std::unique_ptr<ClientChunk>>;
@@ -48,7 +49,7 @@ class ClientWorld : public World, public gk::Drawable {
4849

4950
ChunkMap m_chunks;
5051

51-
gk::Texture &m_texture;
52+
TextureAtlas &m_textureAtlas;
5253

5354
ClientCommandHandler *m_client = nullptr;
5455

client/source/core/ClientApplication.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "ClientApplication.hpp"
2020
#include "Config.hpp"
21+
#include "TextureAtlas.hpp"
2122
#include "TextureLoader.hpp"
2223

2324
#include "GameState.hpp"
@@ -51,6 +52,7 @@ void ClientApplication::init() {
5152

5253
m_resourceHandler.loadConfigFile<TextureLoader>("resources/config/textures.xml");
5354
m_resourceHandler.add<gk::Font>("font-default", "resources/fonts/default.ttf");
55+
m_resourceHandler.add<TextureAtlas>("atlas-blocks");
5456

5557
Registry::setInstance(m_registry);
5658

client/source/graphics/TextureAtlas.cpp

+68-33
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,39 @@
1313
*/
1414
#include <gk/core/Exception.hpp>
1515

16+
#include "Registry.hpp"
1617
#include "TextureAtlas.hpp"
1718

18-
void TextureAtlas::addFile(const std::string &filename) {
19-
SurfacePtr surface{IMG_Load(filename.c_str()), &SDL_FreeSurface};
20-
if(!surface) {
21-
throw EXCEPTION("Failed to load texture:", filename);
22-
}
19+
void TextureAtlas::addFile(const std::string &path, const std::string &filename) {
20+
auto it = m_textureMap.find(filename);
21+
if (it != m_textureMap.end())
22+
return;
2323

24-
auto it = m_textures.find(filename);
25-
if (it != m_textures.end()) {
26-
throw EXCEPTION("Texture already exists in atlas:", filename);
27-
}
24+
SurfacePtr surface{IMG_Load((path + filename).c_str()), &SDL_FreeSurface};
25+
if(!surface)
26+
throw EXCEPTION("Failed to load texture:", path + filename);
2827

29-
if (!m_width && !m_height) {
30-
m_width = surface->w;
31-
m_height = surface->h;
32-
}
33-
else if (m_width != surface->w || m_height != surface->h) {
34-
throw EXCEPTION("Texture size unexpected for", filename + ". Got", surface->w, surface->w, "instead of", m_width, m_height);
35-
}
28+
if (!m_tileSize)
29+
m_tileSize = surface->w;
30+
31+
if (m_tileSize != surface->w || m_tileSize != surface->h)
32+
throw EXCEPTION("Texture size unexpected for", path + filename + ". Got", surface->w, surface->w, "instead of", m_tileSize, m_tileSize);
3633

37-
m_textures.emplace(filename, std::move(surface));
34+
m_textureMap.emplace(filename, m_textures.size());
35+
m_textures.emplace_back(std::move(surface));
3836
}
3937

4038
void TextureAtlas::packTextures() {
41-
if (!m_width && !m_height) {
39+
if (!m_tileSize)
4240
throw EXCEPTION("Cannot pack zero-sized textures!");
43-
}
41+
42+
SurfacePtr atlas{nullptr, &SDL_FreeSurface};
4443

4544
// Max amount of textures on one line
4645
const u16 atlasWidth = 16;
4746

4847
// Max amount of textures on one column
49-
const u16 atlasHeight = m_textures.size() / atlasWidth;
48+
const u16 atlasHeight = std::ceil((float)m_textures.size() / atlasWidth);
5049

5150
Uint32 rmask, gmask, bmask, amask;
5251
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
@@ -61,36 +60,49 @@ void TextureAtlas::packTextures() {
6160
amask = 0xff000000;
6261
#endif
6362

64-
m_atlas.reset(SDL_CreateRGBSurface(0, atlasWidth * m_width, atlasHeight * m_height, 32, rmask, gmask, bmask, amask));
65-
if (!m_atlas) {
63+
atlas.reset(SDL_CreateRGBSurface(0, atlasWidth * m_tileSize, atlasHeight * m_tileSize, 32, rmask, gmask, bmask, amask));
64+
if (!atlas) {
6665
throw EXCEPTION("Failed to create surface:", SDL_GetError());
6766
}
6867

6968
u16 i = 0;
7069
for (auto &it : m_textures) {
7170
SDL_Rect outRect;
72-
outRect.x = (i % atlasWidth) * m_width;
73-
outRect.y = (i / atlasWidth) * m_height;
74-
outRect.w = m_width;
75-
outRect.h = m_height;
76-
77-
SDL_BlitSurface(it.second.get(), nullptr, m_atlas.get(), &outRect);
71+
outRect.x = (i % atlasWidth) * m_tileSize;
72+
outRect.y = (i / atlasWidth) * m_tileSize;
73+
outRect.w = m_tileSize;
74+
outRect.h = m_tileSize;
7875

79-
m_textureMap.emplace(it.first, i);
76+
SDL_BlitSurface(it.get(), nullptr, atlas.get(), &outRect);
8077

8178
++i;
8279
}
8380

8481
m_textures.clear();
82+
83+
m_isReady = true;
84+
85+
if (IMG_SavePNG(atlas.get(), "test_atlas.png") < 0)
86+
throw EXCEPTION("Failed to save texture to: test_altas.png. Reason:", SDL_GetError());
87+
88+
m_texture.loadFromSurface(atlas.get());
8589
}
8690

87-
void TextureAtlas::saveToFile(const std::string &filename) {
88-
if (IMG_SavePNG(m_atlas.get(), filename.c_str()) < 0) {
89-
throw EXCEPTION("Failed to save texture to:", filename + ". Reason:", SDL_GetError());
91+
void TextureAtlas::loadFromRegistry() {
92+
for (auto &block : Registry::getInstance().blocks()) {
93+
if (!block->textureFilename().empty())
94+
addFile("resources/textures/faithful32/blocks/", block->textureFilename());
95+
}
96+
97+
for (auto &item : Registry::getInstance().items()) {
98+
if (!item.textureFilename().empty() && !item.isBlock())
99+
addFile("resources/textures/faithful32/items/", item.textureFilename());
90100
}
101+
102+
packTextures();
91103
}
92104

93-
u16 TextureAtlas::getTextureID(const std::string &filename) {
105+
u16 TextureAtlas::getTextureID(const std::string &filename) const {
94106
auto it = m_textureMap.find(filename);
95107
if (it == m_textureMap.end()) {
96108
throw EXCEPTION("Unable to find texture in atlas:", filename);
@@ -99,3 +111,26 @@ u16 TextureAtlas::getTextureID(const std::string &filename) {
99111
return it->second;
100112
}
101113

114+
gk::FloatRect TextureAtlas::getTexCoords(const std::string &filename, bool normalized) const {
115+
if (filename.empty()) return gk::FloatRect{0, 0, 0, 0};
116+
117+
if (!m_isReady)
118+
throw EXCEPTION("Can't get texture coordinates from empty atlas");
119+
120+
u16 textureID = getTextureID(filename);
121+
122+
float textureX = (textureID % (m_texture.getSize().x / m_tileSize)) * m_tileSize;
123+
float textureY = (textureID / (m_texture.getSize().x / m_tileSize)) * m_tileSize;
124+
125+
if (normalized)
126+
return gk::FloatRect{textureX / m_texture.getSize().x,
127+
textureY / m_texture.getSize().y,
128+
(float)m_tileSize / m_texture.getSize().x,
129+
(float)m_tileSize / m_texture.getSize().y};
130+
else
131+
return gk::FloatRect{textureX,
132+
textureY,
133+
(float)m_tileSize,
134+
(float)m_tileSize};
135+
}
136+

client/source/gui/Cube.cpp

+8-7
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
#include "Block.hpp"
2222
#include "Config.hpp"
2323
#include "Cube.hpp"
24+
#include "TextureAtlas.hpp"
2425

25-
Cube::Cube(float size) : m_texture(gk::ResourceHandler::getInstance().get<gk::Texture>("texture-blocks")) {
26+
Cube::Cube(float size) : m_textureAtlas(gk::ResourceHandler::getInstance().get<TextureAtlas>("atlas-blocks")) {
2627
m_size = size;
2728

2829
// FIXME: Using Transform may be better here
@@ -71,12 +72,12 @@ void Cube::updateVertexBuffer(const Block &block) {
7172
};
7273

7374
for (u8 i = 0 ; i < 6 ; ++i) {
74-
const glm::vec4 &blockTexCoords = block.getTexCoords(i, 0);
75+
const gk::FloatRect &blockTexCoords = m_textureAtlas.getTexCoords(block.textureFilename()); // block.getTexCoords(i, 0);
7576
float faceTexCoords[2 * 4] = {
76-
blockTexCoords.x, blockTexCoords.w,
77-
blockTexCoords.z, blockTexCoords.w,
78-
blockTexCoords.z, blockTexCoords.y,
79-
blockTexCoords.x, blockTexCoords.y
77+
blockTexCoords.x, blockTexCoords.y + blockTexCoords.height,
78+
blockTexCoords.x + blockTexCoords.width, blockTexCoords.y + blockTexCoords.height,
79+
blockTexCoords.x + blockTexCoords.width, blockTexCoords.y,
80+
blockTexCoords.x, blockTexCoords.y
8081
};
8182
for(u8 j = 0 ; j < 4 ; j++) {
8283
vertices[j + i * 4].texCoord[0] = faceTexCoords[j * 2];
@@ -113,7 +114,7 @@ void Cube::draw(gk::RenderTarget &target, gk::RenderStates states) const {
113114

114115
states.projectionMatrix = glm::ortho(0.0f, (float)SCREEN_WIDTH, (float)SCREEN_HEIGHT, 0.0f, -40.0f, DIST_FAR);
115116

116-
states.texture = &m_texture;
117+
states.texture = &m_textureAtlas.texture();
117118
states.vertexAttributes = gk::VertexAttribute::Only2d;
118119

119120
glCheck(glDisable(GL_CULL_FACE));

0 commit comments

Comments
 (0)