mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
work-in-progress texture atlas optimization
This commit is contained in:
parent
949383a2f7
commit
1704badc30
21 changed files with 1496 additions and 271 deletions
219
src/tile.h
219
src/tile.h
|
@ -21,10 +21,208 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#define TILE_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
//#include "utility.h"
|
||||
#include "texture.h"
|
||||
#include "threads.h"
|
||||
#include "utility.h"
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
Specifies a texture in an atlas.
|
||||
|
||||
This is used to specify single textures also.
|
||||
|
||||
This has been designed to be small enough to be thrown around a lot.
|
||||
*/
|
||||
struct AtlasPointer
|
||||
{
|
||||
u32 id; // Texture id
|
||||
video::ITexture *atlas; // Atlas in where the texture is
|
||||
v2f pos; // Position in atlas
|
||||
v2f size; // Size in atlas
|
||||
u16 tiled; // X-wise tiling count. If 0, width of atlas is width of image.
|
||||
|
||||
AtlasPointer(
|
||||
u16 id_,
|
||||
video::ITexture *atlas_=NULL,
|
||||
v2f pos_=v2f(0,0),
|
||||
v2f size_=v2f(1,1),
|
||||
u16 tiled_=1
|
||||
):
|
||||
id(id_),
|
||||
atlas(atlas_),
|
||||
pos(pos_),
|
||||
size(size_),
|
||||
tiled(tiled_)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const AtlasPointer &other)
|
||||
{
|
||||
return (
|
||||
id == other.id
|
||||
);
|
||||
/*return (
|
||||
id == other.id &&
|
||||
atlas == other.atlas &&
|
||||
pos == other.pos &&
|
||||
size == other.size &&
|
||||
tiled == other.tiled
|
||||
);*/
|
||||
}
|
||||
|
||||
float x0(){ return pos.X; }
|
||||
float x1(){ return pos.X + size.X; }
|
||||
float y0(){ return pos.Y; }
|
||||
float y1(){ return pos.Y + size.Y; }
|
||||
};
|
||||
|
||||
/*
|
||||
An internal variant of the former with more data.
|
||||
*/
|
||||
struct SourceAtlasPointer
|
||||
{
|
||||
std::string name;
|
||||
AtlasPointer a;
|
||||
video::IImage *atlas_img; // The source image of the atlas
|
||||
// Integer variants of position and size
|
||||
v2s32 intpos;
|
||||
v2u32 intsize;
|
||||
|
||||
SourceAtlasPointer(
|
||||
const std::string &name_,
|
||||
AtlasPointer a_=AtlasPointer(0, NULL),
|
||||
video::IImage *atlas_img_=NULL,
|
||||
v2s32 intpos_=v2s32(0,0),
|
||||
v2u32 intsize_=v2u32(0,0)
|
||||
):
|
||||
name(name_),
|
||||
a(a_),
|
||||
atlas_img(atlas_img_),
|
||||
intpos(intpos_),
|
||||
intsize(intsize_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Creates and caches textures.
|
||||
*/
|
||||
class TextureSource
|
||||
{
|
||||
public:
|
||||
TextureSource(IrrlichtDevice *device);
|
||||
~TextureSource();
|
||||
|
||||
/*
|
||||
Processes queued texture requests from other threads.
|
||||
|
||||
Shall be called from the main thread.
|
||||
*/
|
||||
void processQueue();
|
||||
|
||||
/*
|
||||
Example case:
|
||||
Now, assume a texture with the id 1 exists, and has the name
|
||||
"stone.png^mineral1".
|
||||
Then a random thread calls getTextureId for a texture called
|
||||
"stone.png^mineral1^crack0".
|
||||
...Now, WTF should happen? Well:
|
||||
- getTextureId strips off stuff recursively from the end until
|
||||
the remaining part is found, or nothing is left when
|
||||
something is stripped out
|
||||
|
||||
But it is slow to search for textures by names and modify them
|
||||
like that?
|
||||
- ContentFeatures is made to contain ids for the basic plain
|
||||
textures
|
||||
- Crack textures can be slow by themselves, but the framework
|
||||
must be fast.
|
||||
|
||||
Example case #2:
|
||||
- Assume a texture with the id 1 exists, and has the name
|
||||
"stone.png^mineral1" and is specified as a part of some atlas.
|
||||
- Now MapBlock::getNodeTile() stumbles upon a node which uses
|
||||
texture id 1, and finds out that NODEMOD_CRACK must be applied
|
||||
with progression=0
|
||||
- It finds out the name of the texture with getTextureName(1),
|
||||
appends "^crack0" to it and gets a new texture id with
|
||||
getTextureId("stone.png^mineral1^crack0")
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Gets a texture id from cache or
|
||||
- if main thread, from getTextureIdDirect
|
||||
- if other thread, adds to request queue and waits for main thread
|
||||
*/
|
||||
u32 getTextureId(const std::string &name);
|
||||
|
||||
/*
|
||||
Example names:
|
||||
"stone.png"
|
||||
"stone.png^crack2"
|
||||
"stone.png^blit:mineral_coal.png"
|
||||
"stone.png^blit:mineral_coal.png^crack1"
|
||||
|
||||
- If texture specified by name is found from cache, return the
|
||||
cached id.
|
||||
- Otherwise generate the texture, add to cache and return id.
|
||||
Recursion is used to find out the largest found part of the
|
||||
texture and continue based on it.
|
||||
|
||||
The id 0 points to a NULL texture. It is returned in case of error.
|
||||
*/
|
||||
u32 getTextureIdDirect(const std::string &name);
|
||||
|
||||
/*
|
||||
Finds out the name of a cached texture.
|
||||
*/
|
||||
std::string getTextureName(u32 id);
|
||||
|
||||
/*
|
||||
If texture specified by the name pointed by the id doesn't
|
||||
exist, create it, then return the cached texture.
|
||||
|
||||
Can be called from any thread. If called from some other thread
|
||||
and not found in cache, the call is queued to the main thread
|
||||
for processing.
|
||||
*/
|
||||
AtlasPointer getTexture(u32 id);
|
||||
|
||||
AtlasPointer getTexture(const std::string &name)
|
||||
{
|
||||
return getTexture(getTextureId(name));
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
Build the main texture atlas which contains most of the
|
||||
textures.
|
||||
|
||||
This is called by the constructor.
|
||||
*/
|
||||
void buildMainAtlas();
|
||||
|
||||
// The id of the thread that is allowed to use irrlicht directly
|
||||
threadid_t m_main_thread;
|
||||
// The irrlicht device
|
||||
IrrlichtDevice *m_device;
|
||||
|
||||
// A texture id is index in this array.
|
||||
// The first position contains a NULL texture.
|
||||
core::array<SourceAtlasPointer> m_atlaspointer_cache;
|
||||
// Maps a texture name to an index in the former.
|
||||
core::map<std::string, u32> m_name_to_id;
|
||||
// The two former containers are behind this mutex
|
||||
JMutex m_atlaspointer_cache_mutex;
|
||||
|
||||
// Main texture atlas. This is filled at startup and is then not touched.
|
||||
video::IImage *m_main_atlas_image;
|
||||
video::ITexture *m_main_atlas_texture;
|
||||
|
||||
// Queued texture fetches (to be processed by the main thread)
|
||||
RequestQueue<std::string, u32, u8, u8> m_get_texture_queue;
|
||||
};
|
||||
|
||||
enum MaterialType{
|
||||
MATERIAL_ALPHA_NONE,
|
||||
MATERIAL_ALPHA_VERTEX,
|
||||
|
@ -38,12 +236,17 @@ enum MaterialType{
|
|||
/*
|
||||
This fully defines the looks of a tile.
|
||||
The SMaterial of a tile is constructed according to this.
|
||||
|
||||
TODO: Change this to use an AtlasPointer
|
||||
*/
|
||||
struct TileSpec
|
||||
{
|
||||
TileSpec():
|
||||
texture(0),
|
||||
alpha(255),
|
||||
material_type(MATERIAL_ALPHA_NONE),
|
||||
// Use this so that leaves don't need a separate material
|
||||
//material_type(MATERIAL_ALPHA_SIMPLE),
|
||||
material_flags(
|
||||
MATERIAL_FLAG_BACKFACE_CULLING
|
||||
)
|
||||
|
@ -53,7 +256,7 @@ struct TileSpec
|
|||
bool operator==(TileSpec &other)
|
||||
{
|
||||
return (
|
||||
spec == other.spec &&
|
||||
texture == other.texture &&
|
||||
alpha == other.alpha &&
|
||||
material_type == other.material_type &&
|
||||
material_flags == other.material_flags
|
||||
|
@ -80,8 +283,14 @@ struct TileSpec
|
|||
material.BackfaceCulling = (material_flags & MATERIAL_FLAG_BACKFACE_CULLING) ? true : false;
|
||||
}
|
||||
|
||||
// Specification of texture
|
||||
TextureSpec spec;
|
||||
// NOTE: Deprecated, i guess?
|
||||
void setTexturePos(u8 tx_, u8 ty_, u8 tw_, u8 th_)
|
||||
{
|
||||
texture.pos = v2f((float)tx_/256.0, (float)ty_/256.0);
|
||||
texture.size = v2f(((float)tw_ + 1.0)/256.0, ((float)th_ + 1.0)/256.0);
|
||||
}
|
||||
|
||||
AtlasPointer texture;
|
||||
// Vertex alpha
|
||||
u8 alpha;
|
||||
// Material type
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue