guiPauseMenu.cpp
irrlichtwrapper.cpp
client.cpp
+ tile.cpp
main.cpp
)
/*
Apply water resistance
*/
- if(player->in_water_stable)
+ if(player->in_water_stable || player->in_water)
{
- f32 max_down = 1.5*BS;
+ f32 max_down = 2.0*BS;
if(speed.Y < -max_down) speed.Y = -max_down;
f32 max = 2.5*BS;
#define IIRRLICHTWRAPPER_HEADER
#include "common_irrlicht.h"
+#include "texture.h"
+
+/*
+ NOTE: This is deprecated and should be removed completely
+*/
/*
IrrlichtWrapper prototype.
{
}
+ // Should be called only from the main thread
+ virtual IrrlichtDevice* getDevice(){ return NULL; }
+
virtual u32 getTime()
{
return 0;
}
- virtual textureid_t getTextureId(const std::string &name){ return 0; }
+ /*virtual textureid_t getTextureId(const std::string &name){ return 0; }
virtual std::string getTextureName(textureid_t id){ return ""; }
virtual video::ITexture* getTexture(const std::string &name){ return NULL; }
- virtual video::ITexture* getTexture(const TextureSpec &spec){ return NULL; }
+ virtual video::ITexture* getTexture(const TextureSpec &spec){ return NULL; }*/
private:
};
#ifndef SERVER
video::ITexture * MapBlockObjectItem::getImage()
{
+ //TODO
+
if(m_inventorystring.substr(0,3) == "Rat")
//return g_device->getVideoDriver()->getTexture(porting::getDataPath("rat.png").c_str());
- return g_irrlicht->getTexture("rat.png");
+ //return g_irrlicht->getTexture("rat.png");
+ return NULL;
if(m_inventorystring.substr(0,4) == "Sign")
//return g_device->getVideoDriver()->getTexture(porting::getDataPath("sign.png").c_str());
- return g_irrlicht->getTexture("sign.png");
+ //return g_irrlicht->getTexture("sign.png");
+ return NULL;
return NULL;
}
#ifndef SERVER
video::ITexture * getImage()
{
- /*if(m_content >= USEFUL_CONTENT_COUNT)
- return NULL;
-
- return g_irrlicht->getTexture(g_content_inventory_texture_paths[m_content]);*/
-
- return g_irrlicht->getTexture(content_features(m_content).inventory_texture);
+ //TODO
+ //return g_irrlicht->getTexture(content_features(m_content).inventory_texture);
+ return NULL;
}
#endif
std::string getText()
name = "cloud.png";
// Get such a texture
- return g_irrlicht->getTexture(name);
+ //return g_irrlicht->getTexture(name);
+ //TODO
+ return NULL;
}
#endif
std::string getText()
std::ostringstream os;
os<<"[progressbar"<<value_f;
- TextureSpec spec;
+ /*TextureSpec spec;
spec.addTid(g_irrlicht->getTextureId(basename));
spec.addTid(g_irrlicht->getTextureId(os.str()));
- return g_irrlicht->getTexture(spec);
+ return g_irrlicht->getTexture(spec);*/
+ //TODO
+ return NULL;
/*// Make texture name for the new texture with a progress bar
float value_f = (float)toolprogress / (float)maxprogress;
m_device = device;
}
+IrrlichtWrapper::~IrrlichtWrapper()
+{
+#if 0
+ // Clear image cache
+ for(core::map<std::string, video::IImage*>::Iterator
+ i = m_imagecache.getIterator();
+ i.atEnd() == false; i++)
+ {
+ i.getNode()->getValue()->drop();
+ }
+#endif
+}
+
void IrrlichtWrapper::Run()
{
+#if 0
/*
Fetch textures
*/
request.dest->push_back(result);
}
+#endif
}
void IrrlichtWrapper::Shutdown(bool shutdown)
m_running = !shutdown;
}
+IrrlichtDevice* IrrlichtWrapper::getDevice()
+{
+ if(get_current_thread_id() != m_main_thread)
+ {
+ dstream<<"WARNING: IrrlichtWrapper::getDevice() called "
+ "not from main thread"<<std::endl;
+ return NULL;
+ }
+ return m_device;
+}
+
+#if 0
textureid_t IrrlichtWrapper::getTextureId(const std::string &name)
{
u32 id = m_namecache.getId(name);
return name;
}
-video::ITexture* IrrlichtWrapper::getTexture(const std::string &name)
+video::ITexture* IrrlichtWrapper::getTexture(const std::string &filename)
{
- TextureSpec spec(getTextureId(name));
+ TextureSpec spec(getTextureId(filename));
return getTexture(spec);
}
texture_name += "[";
texture_name += name;
texture_name += "]";
+
+ /*
+ Try to get image from image cache
+ */
+ {
+ core::map<std::string, video::IImage*>::Node *n;
+ n = m_imagecache.find(texture_name);
+ if(n != NULL)
+ {
+ video::IImage *image = n->getValue();
+
+ core::dimension2d<u32> dim = image->getDimension();
+ baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+ image->copyTo(baseimg);
+ dstream<<"INFO: getTextureDirect(): Loaded \""
+ <<texture_name<<"\" from image cache"
+ <<std::endl;
+
+ // Do not process any further.
+ continue;
+ }
+ }
+
+ // Stuff starting with [ are special commands
if(name[0] != '[')
{
// A normal texture; load it from a file
std::string path = porting::getDataPath(name.c_str());
- dstream<<"getTextureDirect(): Loading path \""<<path
+ dstream<<"INFO: getTextureDirect(): Loading path \""<<path
<<"\""<<std::endl;
// DEBUG
// If base image is NULL, load as base.
if(baseimg == NULL)
{
- dstream<<"Setting "<<name<<" as base"<<std::endl;
+ dstream<<"INFO: Setting "<<name<<" as base"<<std::endl;
/*
Copy it this way to get an alpha channel.
Otherwise images with alpha cannot be blitted on
// Else blit on base.
else
{
- dstream<<"Blitting "<<name<<" on base"<<std::endl;
+ dstream<<"INFO: Blitting "<<name<<" on base"<<std::endl;
// Size of the copied area
core::dimension2d<u32> dim = image->getDimension();
//core::dimension2d<u32> dim(16,16);
else
{
// A special texture modification
- dstream<<"getTextureDirect(): generating \""<<name<<"\""
+ dstream<<"INFO: getTextureDirect(): generating \""<<name<<"\""
<<std::endl;
if(name.substr(0,6) == "[crack")
{
u16 progression = stoi(name.substr(6));
// Size of the base image
- core::dimension2d<u32> dim(16, 16);
+ core::dimension2d<u32> dim_base = baseimg->getDimension();
+ // Crack will be drawn at this size
+ u32 cracksize = 16;
// Size of the crack image
- //core::dimension2d<u32> dim_crack(16, 16 * CRACK_ANIMATION_LENGTH);
- // Position to copy the crack to in the base image
- core::position2d<s32> pos_base(0, 0);
+ core::dimension2d<u32> dim_crack(cracksize,cracksize);
// Position to copy the crack from in the crack image
core::position2d<s32> pos_other(0, 16 * progression);
video::IImage *crackimage = driver->createImageFromFile(
porting::getDataPath("crack.png").c_str());
- crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
- core::rect<s32>(pos_other, dim),
- video::SColor(255,255,255,255),
- NULL);
- crackimage->drop();
+
+ if(crackimage)
+ {
+ /*crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
+ core::rect<s32>(pos_other, dim_base),
+ video::SColor(255,255,255,255),
+ NULL);*/
+
+ for(u32 y0=0; y0<dim_base.Height/dim_crack.Height; y0++)
+ for(u32 x0=0; x0<dim_base.Width/dim_crack.Width; x0++)
+ {
+ // Position to copy the crack to in the base image
+ core::position2d<s32> pos_base(x0*cracksize, y0*cracksize);
+ crackimage->copyToWithAlpha(baseimg, pos_base,
+ core::rect<s32>(pos_other, dim_crack),
+ video::SColor(255,255,255,255),
+ NULL);
+ }
+
+ crackimage->drop();
+ }
+ }
+ else if(name.substr(0,8) == "[combine")
+ {
+ // "[combine:16x128:0,0=stone.png:0,16=grass.png"
+ Strfnd sf(name);
+ sf.next(":");
+ u32 w0 = stoi(sf.next("x"));
+ u32 h0 = stoi(sf.next(":"));
+ dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
+ core::dimension2d<u32> dim(w0,h0);
+ baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+ while(sf.atend() == false)
+ {
+ u32 x = stoi(sf.next(","));
+ u32 y = stoi(sf.next("="));
+ std::string filename = sf.next(":");
+ dstream<<"INFO: Adding \""<<filename
+ <<"\" to combined ("<<x<<","<<y<<")"
+ <<std::endl;
+ video::IImage *img = driver->createImageFromFile(
+ porting::getDataPath(filename.c_str()).c_str());
+ if(img)
+ {
+ core::dimension2d<u32> dim = img->getDimension();
+ dstream<<"INFO: Size "<<dim.Width
+ <<"x"<<dim.Height<<std::endl;
+ core::position2d<s32> pos_base(x, y);
+ video::IImage *img2 =
+ driver->createImage(video::ECF_A8R8G8B8, dim);
+ img->copyTo(img2);
+ img->drop();
+ img2->copyToWithAlpha(baseimg, pos_base,
+ core::rect<s32>(v2s32(0,0), dim),
+ video::SColor(255,255,255,255),
+ NULL);
+ img2->drop();
+ }
+ else
+ {
+ dstream<<"WARNING: img==NULL"<<std::endl;
+ }
+ }
}
else if(name.substr(0,12) == "[progressbar")
{
" texture: \""<<name<<"\""<<std::endl;
}
}
+
+ /*
+ Add to image cache
+ */
+ if(baseimg != NULL)
+ {
+ core::map<std::string, video::IImage*>::Node *n;
+ n = m_imagecache.find(texture_name);
+ if(n != NULL)
+ {
+ video::IImage *img = n->getValue();
+ if(img != baseimg)
+ {
+ img->drop();
+ }
+ }
+
+ m_imagecache[texture_name] = baseimg;
+ }
}
// If no resulting image, return NULL
if(baseimg == NULL)
{
- dstream<<"getTextureDirect(): baseimg is NULL (attempted to"
+ dstream<<"WARNING: getTextureDirect(): baseimg is NULL (attempted to"
" create texture \""<<texture_name<<"\""<<std::endl;
return NULL;
}
// Create texture from resulting image
t = driver->addTexture(texture_name.c_str(), baseimg);
- baseimg->drop();
- dstream<<"getTextureDirect(): created texture \""<<texture_name
+ dstream<<"INFO: getTextureDirect(): created texture \""<<texture_name
<<"\""<<std::endl;
return t;
}
}
}
-
+#endif
#include <jmutexautolock.h>
#include <string>
+/*
+ NOTE: This is deprecated and should be removed completely
+*/
+
/*
A thread-safe texture pointer cache.
threads, because texture pointers have to be handled in
background threads.
*/
-#if 0
-class TextureCache
-{
-public:
- TextureCache()
- {
- m_mutex.Init();
- assert(m_mutex.IsInitialized());
- }
-
- void set(std::string name, video::ITexture *texture)
- {
- if(texture == NULL)
- return;
-
- JMutexAutoLock lock(m_mutex);
-
- m_textures[name] = texture;
- }
-
- video::ITexture* get(const std::string &name)
- {
- JMutexAutoLock lock(m_mutex);
-
- core::map<std::string, video::ITexture*>::Node *n;
- n = m_textures.find(name);
-
- if(n != NULL)
- return n->getValue();
-
- return NULL;
- }
-
-private:
- core::map<std::string, video::ITexture*> m_textures;
- JMutex m_mutex;
-};
-#endif
+#if 0
/*
A thread-safe texture pointer cache
*/
core::map<TextureSpec, video::ITexture*> m_textures;
JMutex m_mutex;
};
+#endif
/*
A thread-safe wrapper for irrlicht, to be accessed from
Queues tasks to be done in the main thread.
Also caches texture specification strings to ids and textures.
+
+ TODO: Remove this and move all texture functionality to TextureSource
*/
class IrrlichtWrapper : public IIrrlichtWrapper
*/
IrrlichtWrapper(IrrlichtDevice *device);
+
+ ~IrrlichtWrapper();
// Run queued tasks
void Run();
// Shutdown wrapper; this disables queued texture fetching
void Shutdown(bool shutdown);
+ IrrlichtDevice* getDevice();
+
/*
These are called from other threads
*/
{
return m_device->getTimer()->getRealTime();
}
-
+
+#if 0
/*
Format of a texture name:
"stone.png" (filename in image data directory)
// The reverse of the above
std::string getTextureName(textureid_t id);
// Gets a texture based on a filename
- video::ITexture* getTexture(const std::string &name);
+ video::ITexture* getTexture(const std::string &filename);
// Gets a texture based on a TextureSpec (a textureid_t is fine too)
video::ITexture* getTexture(const TextureSpec &spec);
+#endif
private:
/*
Non-thread-safe variants of stuff, for internal use
*/
- // DEPRECATED NO-OP
- //video::ITexture* getTextureDirect(const std::string &spec);
-
// Constructs a texture according to spec
- video::ITexture* getTextureDirect(const TextureSpec &spec);
+ //video::ITexture* getTextureDirect(const TextureSpec &spec);
/*
Members
JMutex m_device_mutex;
IrrlichtDevice *m_device;
+#if 0
// Queued texture fetches (to be processed by the main thread)
RequestQueue<TextureSpec, video::ITexture*, u8, u8> m_get_texture_queue;
// Cache of textures by spec
TextureCache m_texturecache;
+ // Cached or generated source images by texture name
+ core::map<std::string, video::IImage*> m_imagecache;
+
// A mapping from texture id to string spec
MutexedIdGenerator<std::string> m_namecache;
+#endif
};
#endif
different directions and then only those drawn that need to be\r
- Also an 1-dimensional tile map would be nice probably\r
\r
+SUGG: Calculate lighting per vertex to get a lighting effect like in\r
+ bartwe's game\r
+\r
Gaming ideas:\r
-------------\r
\r
#include "guiMainMenu.h"\r
#include "mineral.h"\r
#include "noise.h"\r
+#include "tile.h"\r
+\r
+// TODO: Remove this\r
+IrrlichtWrapper *g_irrlicht = NULL;\r
\r
-IrrlichtWrapper *g_irrlicht;\r
+// This makes textures\r
+TextureSource *g_texturesource = NULL;\r
\r
MapDrawControl draw_control;\r
\r
\r
g_device = device;\r
g_irrlicht = new IrrlichtWrapper(device);\r
+ g_texturesource = new TextureSource(device);\r
\r
/*\r
Speed tests (done after irrlicht is loaded to get timer)\r
video::IVideoDriver* driver = device->getVideoDriver();\r
\r
/*\r
- This changes the minimum allowed number of vertices in a VBO\r
+ This changes the minimum allowed number of vertices in a VBO.\r
+ Default is 500.\r
*/\r
//driver->setMinHardwareBufferVertexCount(50);\r
\r
*/\r
g_irrlicht->Run();\r
\r
+ /*\r
+ Process TextureSource's queue\r
+ */\r
+ g_texturesource->processQueue();\r
+\r
/*\r
Random calculations\r
*/\r
#ifndef MAIN_HEADER
#define MAIN_HEADER
-#include "irrlichtwrapper.h"
-
// Settings
+#include "utility.h"
extern Settings g_settings;
// A thread safe wrapper to irrlicht
// On a server build, this is always NULL.
+// TODO: Remove this
+#include "irrlichtwrapper.h"
extern IrrlichtWrapper *g_irrlicht;
+// This makes and maps textures
+#include "tile.h"
+extern TextureSource *g_texturesource;
+
// Debug streams
#include <fstream>
{
double noise = noise2d_perlin(
0.5+(float)p.X/250, 0.5+(float)p.Y/250,
- seed+2, 5, 0.6);
+ seed+2, 5, 0.66);
double zeroval = -0.3;
if(noise < zeroval)
return 0;
base = base2;*/
#if 1
// Higher ground level
- double higher = (double)WATER_LEVEL + 13. + 50. * noise2d_perlin(
- 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
- seed+85039, 6, 0.69);
+ double higher = (double)WATER_LEVEL + 25. + 45. * noise2d_perlin(
+ 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
+ seed+85039, 5, 0.69);
//higher = 30; // For debugging
// Limit higher to at least base
//double b = 20;
// Offset to more low
- double a_off = -0.3;
+ double a_off = -0.15;
// High/low selector
/*double a = 0.5 + b * (a_off + noise2d_perlin(
0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
/*
Make dungeons
*/
- //u32 dungeons_count = relative_volume / 600000;
- /*u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
+ u32 dungeons_count = relative_volume / 600000;
+ u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
if(stone_surface_max_y < WATER_LEVEL)
- bruises_count = 0;*/
- u32 dungeons_count = 0;
- u32 bruises_count = 0;
+ bruises_count = 0;
+ /*u32 dungeons_count = 0;
+ u32 bruises_count = 0;*/
for(u32 jj=0; jj<dungeons_count+bruises_count; jj++)
{
s16 min_tunnel_diameter = 2;
timecheck_counter++;
if(timecheck_counter > 50)
{
+ timecheck_counter = 0;
int time2 = time(0);
if(time2 > time1 + 4)
{
continue;
}
-#if 0
- v3s16 blockpos_nodes = block->getPosRelative();
-
- // Block center position
- v3f blockpos(
- ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
- ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
- ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
- );
-
- // Block position relative to camera
- v3f blockpos_relative = blockpos - camera_position;
-
- // Distance in camera direction (+=front, -=back)
- f32 dforward = blockpos_relative.dotProduct(camera_direction);
-
- // Total distance
- f32 d = blockpos_relative.getLength();
-
- if(m_control.range_all == false)
- {
- // If block is far away, don't draw it
- if(d > m_control.wanted_range * BS)
- continue;
- }
-
- // Maximum radius of a block
- f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
-
- // If block is (nearly) touching the camera, don't
- // bother validating further (that is, render it anyway)
- if(d > block_max_radius * 1.5)
- {
- // Cosine of the angle between the camera direction
- // and the block direction (camera_direction is an unit vector)
- f32 cosangle = dforward / d;
-
- // Compensate for the size of the block
- // (as the block has to be shown even if it's a bit off FOV)
- // This is an estimate.
- cosangle += block_max_radius / dforward;
-
- // If block is not in the field of view, skip it
- //if(cosangle < cos(FOV_ANGLE/2))
- if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
- continue;
- }
-#endif
-#if 0
- v3s16 blockpos_nodes = block->getPosRelative();
-
- // Block center position
- v3f blockpos(
- ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
- ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
- ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
- );
-
- // Block position relative to camera
- v3f blockpos_relative = blockpos - camera_position;
-
- // Total distance
- f32 d = blockpos_relative.getLength();
-#endif
-
#if 1
/*
Update expired mesh
// Render transparent on transparent pass and likewise.
if(transparent == is_transparent_pass)
{
+ /*
+ This *shouldn't* hurt too much because Irrlicht
+ doesn't change opengl textures if the old
+ material is set again.
+ */
driver->setMaterial(buf->getMaterial());
driver->drawMeshBuffer(buf);
vertex_count += buf->getVertexCount();
// For debug printing
virtual void PrintInfo(std::ostream &out);
+ bool isSavingEnabled(){ return m_map_saving_enabled; }
+
private:
// Seed used for all kinds of randomness
u64 m_seed;
video::SColor c = video::SColor(alpha,li,li,li);
face.vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c,
- core::vector2d<f32>(0,1));
- face.vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c,
core::vector2d<f32>(abs_scale,1));
+ face.vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c,
+ core::vector2d<f32>(0,1));
face.vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c,
+ core::vector2d<f32>(0,0));
+ face.vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c,
core::vector2d<f32>(abs_scale,0));
+
+ /*float x0 = (float)tile.tx/256.0;
+ float y0 = (float)tile.ty/256.0;
+ float w = ((float)tile.tw + 1.0)/256.0;
+ float h = ((float)tile.th + 1.0)/256.0;*/
+
+ float x0 = tile.texture.pos.X;
+ float y0 = tile.texture.pos.Y;
+ float w = tile.texture.size.X;
+ float h = tile.texture.size.Y;
+
+ face.vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c,
+ core::vector2d<f32>(x0+w*abs_scale, y0+h));
+ face.vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c,
+ core::vector2d<f32>(x0, y0+h));
+ face.vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c,
+ core::vector2d<f32>(x0, y0));
face.vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c,
- core::vector2d<f32>(0,0));
+ core::vector2d<f32>(x0+w*abs_scale, y0));
face.tile = tile;
//DEBUG
}
if(mod.type == NODEMOD_CRACK)
{
+ /*
+ Get texture id, translate it to name, append stuff to
+ name, get texture id
+ */
+ // Get original texture name
+ u32 orig_id = spec.texture.id;
+ std::string orig_name = g_texturesource->getTextureName(orig_id);
+ // Create new texture name
std::ostringstream os;
- os<<"[crack"<<mod.param;
-
- textureid_t tid = g_irrlicht->getTextureId(os.str());
- spec.spec.addTid(tid);
+ os<<orig_name<<"^[crack"<<mod.param;
+ //os<<orig_name<<"^[progressbar0.5";
+ //os<<"mese.png";
+ // Get new texture
+ u32 new_id = g_texturesource->getTextureId(os.str());
+
+ dstream<<"MapBlock::getNodeTile(): Switching from "
+ <<orig_name<<" to "<<os.str()<<" ("
+ <<orig_id<<" to "<<new_id<<")"<<std::endl;
+
+ spec.texture = g_texturesource->getTexture(new_id);
}
}
TileSpec tile0_next;
TileSpec tile1_next;
u8 light_next = 0;
-
+
+ // If at last position, there is nothing to compare to and
+ // the face must be drawn anyway
if(j != length - 1)
{
p_next = p + translate_dir;
continuous_tiles_count++;
- if(next_is_different)
+ // This is set to true if the texture doesn't allow more tiling
+ bool end_of_texture = false;
+ /*
+ If there is no texture, it can be tiled infinitely.
+ If tiled==0, it means the texture can be tiled infinitely.
+ Otherwise check tiled agains continuous_tiles_count.
+
+ This check has to be made for both tiles, because this is
+ a bit hackish and we know which one we're using only when
+ the decision to make the faces is made.
+ */
+ if(tile0.texture.atlas != NULL && tile0.texture.tiled != 0)
+ {
+ if(tile0.texture.tiled <= continuous_tiles_count)
+ end_of_texture = true;
+ }
+ if(tile1.texture.atlas != NULL && tile1.texture.tiled != 0)
+ {
+ if(tile1.texture.tiled <= continuous_tiles_count)
+ end_of_texture = true;
+ }
+
+ //end_of_texture = true; //DEBUG
+
+ if(next_is_different || end_of_texture)
{
/*
Create a face if there should be one
Convert FastFaces to SMesh
*/
- scene::SMesh *mesh_new = NULL;
-
- mesh_new = new scene::SMesh();
-
MeshCollector collector;
if(fastfaces_new.size() > 0)
FastFace &f = fastfaces_new[i];
const u16 indices[] = {0,1,2,2,3,0};
-
- video::ITexture *texture = g_irrlicht->getTexture(f.tile.spec);
+
+ //video::ITexture *texture = g_irrlicht->getTexture(f.tile.spec);
+ video::ITexture *texture = f.tile.texture.atlas;
if(texture == NULL)
continue;
f.tile.applyMaterialOptions(material);
- /*if(f.tile.alpha != 255)
- material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
- else
- material.MaterialType = video::EMT_SOLID;*/
-
collector.append(material, f.vertices, 4, indices, 6);
}
}
material_water1.setFlag(video::EMF_BILINEAR_FILTER, false);
material_water1.setFlag(video::EMF_FOG_ENABLE, true);
material_water1.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
- material_water1.setTexture(0, g_irrlicht->getTexture("water.png"));
+ //TODO
+ //material_water1.setTexture(0, g_irrlicht->getTexture("water.png"));
+ AtlasPointer pa_water1 = g_texturesource->getTexture(
+ g_texturesource->getTextureId("water.png"));
+ material_water1.setTexture(0, pa_water1.atlas);
// New-style leaves material
video::SMaterial material_leaves1;
material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
- material_leaves1.setTexture(0, g_irrlicht->getTexture("leaves.png"));
+ //TODO
+ //material_leaves1.setTexture(0, g_irrlicht->getTexture("leaves.png"));
+ AtlasPointer pa_leaves1 = g_texturesource->getTexture(
+ g_texturesource->getTextureId("leaves.png"));
+ material_leaves1.setTexture(0, pa_leaves1.atlas);
for(s16 z=0; z<MAP_BLOCKSIZE; z++)
for(s16 y=0; y<MAP_BLOCKSIZE; y++)
//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
- if(dir == v3s16(0,-1,0))
+ //TODO
+ /*if(dir == v3s16(0,-1,0))
material.setTexture(0,
g_irrlicht->getTexture("torch_on_floor.png"));
else if(dir == v3s16(0,1,0))
g_irrlicht->getTexture("torch_on_floor.png"));
else
material.setTexture(0,
- g_irrlicht->getTexture("torch.png"));
+ g_irrlicht->getTexture("torch.png"));*/
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
video::S3DVertex vertices[4] =
{
- /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
- video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
- video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
- video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
- video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
+ /*video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
- video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
+ video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
+ pa_water1.x0(), pa_water1.y1()),
+ video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
+ pa_water1.x1(), pa_water1.y1()),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
+ pa_water1.x1(), pa_water1.y0()),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
+ pa_water1.x0(), pa_water1.y0()),
};
/*
{
video::S3DVertex vertices[4] =
{
- video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
+ /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
- video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
+ video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
+ pa_water1.x0(), pa_water1.y1()),
+ video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
+ pa_water1.x1(), pa_water1.y1()),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
+ pa_water1.x1(), pa_water1.y0()),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
+ pa_water1.x0(), pa_water1.y0()),
};
for(s32 i=0; i<4; i++)
video::S3DVertex vertices[4] =
{
- video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
+ /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
- video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
+ video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
+ pa_water1.x0(), pa_water1.y1()),
+ video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
+ pa_water1.x1(), pa_water1.y1()),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
+ pa_water1.x1(), pa_water1.y0()),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
+ pa_water1.x0(), pa_water1.y0()),
};
for(s32 i=0; i<4; i++)
{
video::S3DVertex vertices[4] =
{
- video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
+ /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
- video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),
+ video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
+ video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
+ pa_leaves1.x0(), pa_leaves1.y1()),
+ video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
+ pa_leaves1.x1(), pa_leaves1.y1()),
+ video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
+ pa_leaves1.x1(), pa_leaves1.y0()),
+ video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
+ pa_leaves1.x0(), pa_leaves1.y0()),
};
if(j == 0)
Add stuff from collector to mesh
*/
+ scene::SMesh *mesh_new = NULL;
+ mesh_new = new scene::SMesh();
+
collector.fillMesh(mesh_new);
/*
mesh_new = NULL;
}
- // Use VBO for mesh (this just would set this for ever buffer)
- // This will lead to infinite memory usage because or irrlicht.
- //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
-
- /*std::cout<<"MapBlock has "<<fastfaces_new.size()<<" faces "
- <<"and uses "<<mesh_new->getMeshBufferCount()
- <<" materials (meshbuffers)"<<std::endl;*/
+ if(mesh_new)
+ {
+#if 0
+ // Usually 1-700 faces and 1-7 materials
+ std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
+ <<"and uses "<<mesh_new->getMeshBufferCount()
+ <<" materials (meshbuffers)"<<std::endl;
+#endif
+
+ // Use VBO for mesh (this just would set this for ever buffer)
+ // This will lead to infinite memory usage because or irrlicht.
+ //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
+
+ /*
+ NOTE: If that is enabled, some kind of a queue to the main
+ thread should be made which would call irrlicht to delete
+ the hardware buffer and then delete the mesh
+ */
+ }
/*
Replace the mesh
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "common_irrlicht.h"
#include "mapnode.h"
#include "tile.h"
#include "porting.h"
delete translate_to;
}
+void ContentFeatures::setTexture(u16 i, std::string name, u8 alpha)
+{
+ if(g_texturesource)
+ {
+ tiles[i].texture = g_texturesource->getTexture(name);
+ }
+
+ if(alpha != 255)
+ {
+ tiles[i].alpha = alpha;
+ tiles[i].material_type = MATERIAL_ALPHA_VERTEX;
+ }
+}
+
struct ContentFeatures g_content_features[256];
ContentFeatures & content_features(u8 i)
void init_mapnode(IIrrlichtWrapper *irrlicht)
{
+ // Read some settings
bool new_style_water = g_settings.getBool("new_style_water");
bool new_style_leaves = g_settings.getBool("new_style_leaves");
+
+ /*
+ Initialize content feature table
+ */
+
+ /*
+ Set initial material type to same in all tiles, so that the
+ same material can be used in more stuff.
+ This is set according to the leaves because they are the only
+ differing material to which all materials can be changed to
+ get this optimization.
+ */
+ u8 initial_material_type = MATERIAL_ALPHA_SIMPLE;
+ /*if(new_style_leaves)
+ initial_material_type = MATERIAL_ALPHA_SIMPLE;
+ else
+ initial_material_type = MATERIAL_ALPHA_NONE;*/
+ for(u16 i=0; i<256; i++)
+ {
+ ContentFeatures *f = &g_content_features[i];
+ for(u16 j=0; j<6; j++)
+ f->tiles[j].material_type = initial_material_type;
+ }
u8 i;
ContentFeatures *f = NULL;
i = CONTENT_STONE;
f = &g_content_features[i];
- f->setAllTextures(irrlicht->getTextureId("stone.png"));
+ f->setAllTextures("stone.png");
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_GRASS;
f = &g_content_features[i];
- f->setAllTextures(TextureSpec(irrlicht->getTextureId("mud.png"),
- irrlicht->getTextureId("grass_side.png")));
- f->setTexture(0, irrlicht->getTextureId("grass.png"));
- f->setTexture(1, irrlicht->getTextureId("mud.png"));
- f->setInventoryTexture(irrlicht->getTextureId("grass.png"));
+ f->setAllTextures("mud.png^grass_side.png");
+ f->setTexture(0, "grass.png");
+ f->setTexture(1, "mud.png");
+ //f->setInventoryTexture(irrlicht->getTextureId("grass.png"));
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_GRASS_FOOTSTEPS;
f = &g_content_features[i];
- f->setAllTextures(TextureSpec(irrlicht->getTextureId("mud.png"),
- irrlicht->getTextureId("grass_side.png")));
- f->setTexture(0, irrlicht->getTextureId("grass_footsteps.png"));
- f->setTexture(1, irrlicht->getTextureId("mud.png"));
- f->setInventoryTexture(irrlicht->getTextureId("grass_footsteps.png"));
+ //f->setInventoryTexture(irrlicht->getTextureId("grass_footsteps.png"));
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_MUD;
f = &g_content_features[i];
- f->setAllTextures(irrlicht->getTextureId("mud.png"));
+ f->setAllTextures("mud.png");
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_SAND;
f = &g_content_features[i];
- f->setAllTextures(irrlicht->getTextureId("sand.png"));
+ f->setAllTextures("sand.png");
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_TREE;
f = &g_content_features[i];
- f->setAllTextures(irrlicht->getTextureId("tree.png"));
- f->setTexture(0, irrlicht->getTextureId("tree_top.png"));
- f->setTexture(1, irrlicht->getTextureId("tree_top.png"));
- f->setInventoryTexture(irrlicht->getTextureId("tree_top.png"));
+ f->setAllTextures("tree.png");
+ f->setTexture(0, "tree_top.png");
+ f->setTexture(1, "tree_top.png");
+ //f->setInventoryTexture(irrlicht->getTextureId("tree_top.png"));
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
}
else
{
- f->setAllTextures(irrlicht->getTextureId("leaves.png"));
+ f->setAllTextures("[noalpha:leaves.png");
}
- /*{
- TileSpec t;
- t.spec = TextureSpec(irrlicht->getTextureId("leaves.png"));
- //t.material_type = MATERIAL_ALPHA_SIMPLE;
- //t.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
- f->setAllTiles(t);
- }*/
i = CONTENT_COALSTONE;
f = &g_content_features[i];
//f->translate_to = new MapNode(CONTENT_STONE, MINERAL_COAL);
- f->setAllTextures(TextureSpec(irrlicht->getTextureId("coal.png"),
- irrlicht->getTextureId("mineral_coal.png")));
+ /*f->setAllTextures(TextureSpec(irrlicht->getTextureId("coal.png"),
+ irrlicht->getTextureId("mineral_coal.png")));*/
+ f->setAllTextures("stone.png^mineral_coal.png");
f->is_ground_content = true;
i = CONTENT_WOOD;
f = &g_content_features[i];
- f->setAllTextures(irrlicht->getTextureId("wood.png"));
+ //f->setAllTextures(irrlicht->getTextureId("wood.png"));
+ f->setAllTextures("wood.png");
f->is_ground_content = true;
i = CONTENT_MESE;
f = &g_content_features[i];
- f->setAllTextures(irrlicht->getTextureId("mese.png"));
+ //f->setAllTextures(irrlicht->getTextureId("mese.png"));
+ f->setAllTextures("mese.png");
f->is_ground_content = true;
i = CONTENT_CLOUD;
f = &g_content_features[i];
- f->setAllTextures(irrlicht->getTextureId("cloud.png"));
+ //f->setAllTextures(irrlicht->getTextureId("cloud.png"));
+ f->setAllTextures("cloud.png");
f->is_ground_content = true;
i = CONTENT_AIR;
i = CONTENT_WATER;
f = &g_content_features[i];
- f->setInventoryTexture(irrlicht->getTextureId("water.png"));
+ //f->setInventoryTexture(irrlicht->getTextureId("water.png"));
f->param_type = CPT_LIGHT;
f->light_propagates = true;
f->solidness = 0; // Drawn separately, makes no faces
i = CONTENT_WATERSOURCE;
f = &g_content_features[i];
- f->setInventoryTexture(irrlicht->getTextureId("water.png"));
+ //f->setInventoryTexture(irrlicht->getTextureId("water.png"));
if(new_style_water)
{
f->solidness = 0; // drawn separately, makes no faces
}
else // old style
{
- f->setAllTextures(irrlicht->getTextureId("water.png"), WATER_ALPHA);
+ f->solidness = 1;
+
TileSpec t;
- t.spec = TextureSpec(irrlicht->getTextureId("water.png"));
+ if(g_texturesource)
+ t.texture = g_texturesource->getTexture("water.png");
+
t.alpha = WATER_ALPHA;
t.material_type = MATERIAL_ALPHA_VERTEX;
t.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
f->setAllTiles(t);
- f->solidness = 1;
}
f->param_type = CPT_LIGHT;
f->light_propagates = true;
i = CONTENT_TORCH;
f = &g_content_features[i];
- f->setInventoryTexture(irrlicht->getTextureId("torch_on_floor.png"));
f->param_type = CPT_LIGHT;
f->light_propagates = true;
f->solidness = 0; // drawn separately, makes no faces
else
spec = content_features(d).tiles[dir_i];
- if(content_features(d).param_type == CPT_MINERAL)
+ /*
+ If it contains some mineral, change texture id
+ */
+ if(content_features(d).param_type == CPT_MINERAL && g_texturesource)
{
u8 mineral = param & 0x1f;
- // Add mineral block texture
- textureid_t tid = mineral_block_texture(mineral);
- if(tid != 0)
- spec.spec.addTid(tid);
+ std::string mineral_texture_name = mineral_block_texture(mineral);
+ if(mineral_texture_name != "")
+ {
+ u32 orig_id = spec.texture.id;
+ std::string texture_name = g_texturesource->getTextureName(orig_id);
+ //texture_name += "^blit:";
+ texture_name += "^";
+ texture_name += mineral_texture_name;
+ u32 new_id = g_texturesource->getTextureId(texture_name);
+ spec.texture = g_texturesource->getTexture(new_id);
+ }
}
return spec;
5: front
*/
TileSpec tiles[6];
-
+
+ // TODO: Somehow specify inventory image
//std::string inventory_image_path;
- TextureSpec inventory_texture;
+ //TextureSpec inventory_texture;
+ //u32 inventory_texture_id;
bool is_ground_content; //TODO: Remove, use walkable instead
bool light_propagates;
~ContentFeatures();
- // Quickhands for simple materials
- void setTexture(u16 i, const TextureSpec &spec, u8 alpha=255)
+ /*
+ Quickhands for simple materials
+ */
+
+ void setTexture(u16 i, std::string name, u8 alpha=255);
+
+ void setAllTextures(std::string name, u8 alpha=255)
{
- tiles[i].spec = spec;
+ for(u16 i=0; i<6; i++)
+ {
+ setTexture(i, name, alpha);
+ }
+ }
+
+ /*void setTexture(u16 i, AtlasPointer p, u8 alpha=255)
+ {
+ tiles[i].texture = p;
if(alpha != 255)
{
tiles[i].alpha = alpha;
tiles[i].material_type = MATERIAL_ALPHA_VERTEX;
}
}
- void setAllTextures(const TextureSpec &spec, u8 alpha=255)
+ void setAllTextures(AtlasPointer p, u8 alpha=255)
{
for(u16 i=0; i<6; i++)
{
- setTexture(i, spec, alpha);
+ setTexture(i, p, alpha);
}
-
- // Set this too so it can be left as is most times
- if(inventory_texture.empty())
- inventory_texture = spec;
- }
+ }*/
void setTile(u16 i, const TileSpec &tile)
{
}
}
- void setInventoryTexture(const TextureSpec &spec)
+ /*void setInventoryTexture(const TextureSpec &spec)
{
inventory_texture = spec;
- }
+ }*/
/*void setInventoryImage(std::string imgname)
{
"mineral_iron.png"
};
-textureid_t mineral_textures[MINERAL_COUNT] = {0};
+//textureid_t mineral_textures[MINERAL_COUNT] = {0};
+std::string mineral_textures[MINERAL_COUNT];
void init_mineral(IIrrlichtWrapper *irrlicht)
{
{
if(mineral_filenames[i] == NULL)
continue;
- mineral_textures[i] = irrlicht->getTextureId(mineral_filenames[i]);
+ //mineral_textures[i] = irrlicht->getTextureId(mineral_filenames[i]);
+ //mineral_textures[i] = 0;
+ mineral_textures[i] = mineral_filenames[i];
}
}
-textureid_t mineral_block_texture(u8 mineral)
+//textureid_t mineral_block_texture(u8 mineral)
+std::string mineral_block_texture(u8 mineral)
{
if(mineral >= MINERAL_COUNT)
- return 0;
+ return "";
return mineral_textures[mineral];
}
#define MINERAL_COUNT 3
-textureid_t mineral_block_texture(u8 mineral);
+//textureid_t mineral_block_texture(u8 mineral);
+std::string mineral_block_texture(u8 mineral);
inline CraftItem * getDiggedMineralItem(u8 mineral)
{
os<<name<<L",";
}
os<<L"}";
+ if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
+ os<<" WARNING: Map saving is disabled."<<std::endl;
// Send message
SendChatMessage(peer_id, os.str());
}
#ifndef TEXTURE_HEADER
#define TEXTURE_HEADER
+// This file now contains all that was here
+#include "tile.h"
+
+// TODO: Remove this
+typedef u16 textureid_t;
+
+#if 0
+
#include "common_irrlicht.h"
//#include "utility.h"
#include "debug.h"
};
#endif
+
+#endif
*/
#include "tile.h"
-//#include "porting.h"
-// For IrrlichtWrapper
-//#include "main.h"
-//#include <string>
+#include "debug.h"
-// Nothing here
+TextureSource::TextureSource(IrrlichtDevice *device):
+ m_device(device),
+ m_main_atlas_image(NULL),
+ m_main_atlas_texture(NULL)
+{
+ assert(m_device);
+
+ m_atlaspointer_cache_mutex.Init();
+
+ m_main_thread = get_current_thread_id();
+
+ // Add a NULL AtlasPointer as the first index, named ""
+ m_atlaspointer_cache.push_back(SourceAtlasPointer(""));
+ m_name_to_id[""] = 0;
+
+ // Build main texture atlas
+ buildMainAtlas();
+}
+
+TextureSource::~TextureSource()
+{
+}
+
+void TextureSource::processQueue()
+{
+ /*
+ Fetch textures
+ */
+ if(m_get_texture_queue.size() > 0)
+ {
+ GetRequest<std::string, u32, u8, u8>
+ request = m_get_texture_queue.pop();
+
+ dstream<<"INFO: TextureSource::processQueue(): "
+ <<"got texture request with "
+ <<"name="<<request.key
+ <<std::endl;
+
+ GetResult<std::string, u32, u8, u8>
+ result;
+ result.key = request.key;
+ result.callers = request.callers;
+ result.item = getTextureIdDirect(request.key);
+
+ request.dest->push_back(result);
+ }
+}
+
+u32 TextureSource::getTextureId(const std::string &name)
+{
+ //dstream<<"INFO: getTextureId(): name="<<name<<std::endl;
+
+ {
+ /*
+ See if texture already exists
+ */
+ JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+ core::map<std::string, u32>::Node *n;
+ n = m_name_to_id.find(name);
+ if(n != NULL)
+ {
+ return n->getValue();
+ }
+ }
+
+ /*
+ Get texture
+ */
+ if(get_current_thread_id() == m_main_thread)
+ {
+ return getTextureIdDirect(name);
+ }
+ else
+ {
+ dstream<<"INFO: getTextureId(): Queued: name="<<name<<std::endl;
+
+ // We're gonna ask the result to be put into here
+ ResultQueue<std::string, u32, u8, u8> result_queue;
+
+ // Throw a request in
+ m_get_texture_queue.add(name, 0, 0, &result_queue);
+
+ dstream<<"INFO: Waiting for texture from main thread, name="
+ <<name<<std::endl;
+
+ try
+ {
+ // Wait result for a second
+ GetResult<std::string, u32, u8, u8>
+ result = result_queue.pop_front(1000);
+
+ // Check that at least something worked OK
+ assert(result.key == name);
+
+ return result.item;
+ }
+ catch(ItemNotFoundException &e)
+ {
+ dstream<<"WARNING: Waiting for texture timed out."<<std::endl;
+ return 0;
+ }
+ }
+
+ dstream<<"WARNING: getTextureId(): Failed"<<std::endl;
+
+ return 0;
+}
+
+// Draw a progress bar on the image
+void make_progressbar(float value, video::IImage *image);
+
+/*
+ Generate image based on a string like "stone.png" or "[crack0".
+ if baseimg is NULL, it is created. Otherwise stuff is made on it.
+*/
+bool generate_image(std::string part_of_name, video::IImage *& baseimg,
+ video::IVideoDriver* driver);
+
+/*
+ Generates an image from a full string like
+ "stone.png^mineral_coal.png^[crack0".
+
+ This is used by buildMainAtlas().
+*/
+video::IImage* generate_image_from_scratch(std::string name,
+ video::IVideoDriver* driver);
+
+/*
+ This method generates all the textures
+*/
+u32 TextureSource::getTextureIdDirect(const std::string &name)
+{
+ dstream<<"INFO: getTextureIdDirect(): name="<<name<<std::endl;
+
+ // Empty name means texture 0
+ if(name == "")
+ {
+ dstream<<"INFO: getTextureIdDirect(): name is empty"<<std::endl;
+ return 0;
+ }
+
+ /*
+ Calling only allowed from main thread
+ */
+ if(get_current_thread_id() != m_main_thread)
+ {
+ dstream<<"ERROR: TextureSource::getTextureIdDirect() "
+ "called not from main thread"<<std::endl;
+ return 0;
+ }
+
+ /*
+ See if texture already exists
+ */
+ {
+ JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+
+ core::map<std::string, u32>::Node *n;
+ n = m_name_to_id.find(name);
+ if(n != NULL)
+ {
+ dstream<<"INFO: getTextureIdDirect(): name="<<name
+ <<" found in cache"<<std::endl;
+ return n->getValue();
+ }
+ }
+
+ dstream<<"INFO: getTextureIdDirect(): name="<<name
+ <<" NOT found in cache. Creating it."<<std::endl;
+
+ /*
+ Get the base image
+ */
+
+ char separator = '^';
+
+ /*
+ This is set to the id of the base image.
+ If left 0, there is no base image and a completely new image
+ is made.
+ */
+ u32 base_image_id = 0;
+
+ // Find last meta separator in name
+ s32 last_separator_position = -1;
+ for(s32 i=name.size()-1; i>=0; i--)
+ {
+ if(name[i] == separator)
+ {
+ last_separator_position = i;
+ break;
+ }
+ }
+ /*
+ If separator was found, construct the base name and make the
+ base image using a recursive call
+ */
+ std::string base_image_name;
+ if(last_separator_position != -1)
+ {
+ // Construct base name
+ base_image_name = name.substr(0, last_separator_position);
+ dstream<<"INFO: getTextureIdDirect(): Calling itself recursively"
+ " to get base image, name="<<base_image_name<<std::endl;
+ base_image_id = getTextureIdDirect(base_image_name);
+ }
+
+ dstream<<"base_image_id="<<base_image_id<<std::endl;
+
+ video::IVideoDriver* driver = m_device->getVideoDriver();
+ assert(driver);
+
+ video::ITexture *t = NULL;
+
+ /*
+ An image will be built from files and then converted into a texture.
+ */
+ video::IImage *baseimg = NULL;
+
+ // If a base image was found, copy it to baseimg
+ if(base_image_id != 0)
+ {
+ JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+
+ SourceAtlasPointer ap = m_atlaspointer_cache[base_image_id];
+
+ video::IImage *image = ap.atlas_img;
+
+ core::dimension2d<u32> dim = ap.intsize;
+
+ baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+
+ core::position2d<s32> pos_to(0,0);
+ core::position2d<s32> pos_from = ap.intpos;
+
+ image->copyTo(
+ baseimg, // target
+ v2s32(0,0), // position in target
+ core::rect<s32>(pos_from, dim) // from
+ );
+
+ dstream<<"INFO: getTextureIdDirect(): Loaded \""
+ <<base_image_name<<"\" from image cache"
+ <<std::endl;
+ }
+
+ /*
+ Parse out the last part of the name of the image and act
+ according to it
+ */
+
+ std::string last_part_of_name = name.substr(last_separator_position+1);
+ dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
+
+ // Generate image according to part of name
+ if(generate_image(last_part_of_name, baseimg, driver) == false)
+ {
+ dstream<<"INFO: getTextureIdDirect(): "
+ "failed to generate \""<<last_part_of_name<<"\""
+ <<std::endl;
+ return 0;
+ }
+
+ // If no resulting image, return NULL
+ if(baseimg == NULL)
+ {
+ dstream<<"WARNING: getTextureIdDirect(): baseimg is NULL (attempted to"
+ " create texture \""<<name<<"\""<<std::endl;
+ return 0;
+ }
+
+ // Create texture from resulting image
+ t = driver->addTexture(name.c_str(), baseimg);
+
+ // If no texture
+ if(t == NULL)
+ return 0;
+
+ /*
+ Add texture to caches
+ */
+
+ JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+
+ u32 id = m_atlaspointer_cache.size();
+ AtlasPointer ap(id);
+ ap.atlas = t;
+ ap.pos = v2f(0,0);
+ ap.size = v2f(1,1);
+ ap.tiled = 0;
+ SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg->getDimension());
+ m_atlaspointer_cache.push_back(nap);
+ m_name_to_id.insert(name, id);
+
+ dstream<<"INFO: getTextureIdDirect(): name="<<name
+ <<": succesfully returning id="<<id<<std::endl;
+
+ return id;
+}
+
+std::string TextureSource::getTextureName(u32 id)
+{
+ JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+
+ if(id >= m_atlaspointer_cache.size())
+ {
+ dstream<<"WARNING: TextureSource::getTextureName(): id="<<id
+ <<" >= m_atlaspointer_cache.size()="
+ <<m_atlaspointer_cache.size()<<std::endl;
+ return "";
+ }
+
+ return m_atlaspointer_cache[id].name;
+}
+
+
+AtlasPointer TextureSource::getTexture(u32 id)
+{
+ JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+
+ if(id >= m_atlaspointer_cache.size())
+ return AtlasPointer(0, NULL);
+
+ return m_atlaspointer_cache[id].a;
+}
+
+void TextureSource::buildMainAtlas()
+{
+ dstream<<"TextureSource::buildMainAtlas()"<<std::endl;
+
+ //return; // Disable (for testing)
+
+ video::IVideoDriver* driver = m_device->getVideoDriver();
+ assert(driver);
+
+ JMutexAutoLock lock(m_atlaspointer_cache_mutex);
+
+ // Create an image of the right size
+ core::dimension2d<u32> atlas_dim(1024,1024);
+ video::IImage *atlas_img =
+ driver->createImage(video::ECF_A8R8G8B8, atlas_dim);
+
+ /*
+ A list of stuff to add. This should contain as much of the
+ stuff shown in game as possible, to minimize texture changes.
+ */
+
+ core::array<std::string> sourcelist;
+
+ sourcelist.push_back("stone.png");
+ sourcelist.push_back("mud.png");
+ sourcelist.push_back("sand.png");
+ sourcelist.push_back("grass.png");
+ sourcelist.push_back("mud.png");
+ sourcelist.push_back("tree.png");
+ sourcelist.push_back("tree_top.png");
+ sourcelist.push_back("water.png");
+ sourcelist.push_back("leaves.png");
+ sourcelist.push_back("mud.png^grass_side.png");
+
+ sourcelist.push_back("stone.png^mineral_coal.png");
+ sourcelist.push_back("stone.png^mineral_iron.png");
+ sourcelist.push_back("mud.png^mineral_coal.png");
+ sourcelist.push_back("mud.png^mineral_iron.png");
+ sourcelist.push_back("sand.png^mineral_coal.png");
+ sourcelist.push_back("sand.png^mineral_iron.png");
+
+ /*
+ First pass: generate almost everything
+ */
+ core::position2d<s32> pos_in_atlas(0,0);
+ for(u32 i=0; i<sourcelist.size(); i++)
+ {
+ std::string name = sourcelist[i];
+
+ /*video::IImage *img = driver->createImageFromFile(
+ porting::getDataPath(name.c_str()).c_str());
+ if(img == NULL)
+ continue;
+
+ core::dimension2d<u32> dim = img->getDimension();
+ // Make a copy with the right color format
+ video::IImage *img2 =
+ driver->createImage(video::ECF_A8R8G8B8, dim);
+ img->copyTo(img2);
+ img->drop();*/
+
+ // Generate image by name
+ video::IImage *img2 = generate_image_from_scratch(name, driver);
+ core::dimension2d<u32> dim = img2->getDimension();
+
+ // Tile it a few times in the X direction
+ u16 xwise_tiling = 16;
+ for(u32 j=0; j<xwise_tiling; j++)
+ {
+ // Copy the copy to the atlas
+ img2->copyToWithAlpha(atlas_img,
+ pos_in_atlas + v2s32(j*dim.Width,0),
+ core::rect<s32>(v2s32(0,0), dim),
+ video::SColor(255,255,255,255),
+ NULL);
+ }
+
+ img2->drop();
+
+ /*
+ Add texture to caches
+ */
+
+ // Get next id
+ u32 id = m_atlaspointer_cache.size();
+
+ // Create AtlasPointer
+ AtlasPointer ap(id);
+ ap.atlas = NULL; // Set on the second pass
+ ap.pos = v2f((float)pos_in_atlas.X/(float)atlas_dim.Width,
+ (float)pos_in_atlas.Y/(float)atlas_dim.Height);
+ ap.size = v2f((float)dim.Width/(float)atlas_dim.Width,
+ (float)dim.Width/(float)atlas_dim.Height);
+ ap.tiled = xwise_tiling;
+
+ // Create SourceAtlasPointer and add to containers
+ SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
+ m_atlaspointer_cache.push_back(nap);
+ m_name_to_id.insert(name, id);
+
+ // Increment position
+ pos_in_atlas.Y += dim.Height;
+ }
+
+ /*
+ Make texture
+ */
+ video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
+ assert(t);
+
+ /*
+ Second pass: set texture pointer in generated AtlasPointers
+ */
+ for(u32 i=0; i<sourcelist.size(); i++)
+ {
+ std::string name = sourcelist[i];
+ u32 id = m_name_to_id[name];
+ m_atlaspointer_cache[id].a.atlas = t;
+ }
+
+ /*
+ Write image to file so that it can be inspected
+ */
+ driver->writeImageToFile(atlas_img,
+ porting::getDataPath("main_atlas.png").c_str());
+}
+
+video::IImage* generate_image_from_scratch(std::string name,
+ video::IVideoDriver* driver)
+{
+ dstream<<"INFO: generate_image_from_scratch(): "
+ "name="<<name<<std::endl;
+
+ /*
+ Get the base image
+ */
+
+ video::IImage *baseimg = NULL;
+
+ char separator = '^';
+
+ // Find last meta separator in name
+ s32 last_separator_position = -1;
+ for(s32 i=name.size()-1; i>=0; i--)
+ {
+ if(name[i] == separator)
+ {
+ last_separator_position = i;
+ break;
+ }
+ }
+
+ /*dstream<<"INFO: generate_image_from_scratch(): "
+ <<"last_separator_position="<<last_separator_position
+ <<std::endl;*/
+
+ /*
+ If separator was found, construct the base name and make the
+ base image using a recursive call
+ */
+ std::string base_image_name;
+ if(last_separator_position != -1)
+ {
+ // Construct base name
+ base_image_name = name.substr(0, last_separator_position);
+ dstream<<"INFO: generate_image_from_scratch(): Calling itself recursively"
+ " to get base image, name="<<base_image_name<<std::endl;
+ baseimg = generate_image_from_scratch(base_image_name, driver);
+ }
+
+ /*
+ Parse out the last part of the name of the image and act
+ according to it
+ */
+
+ std::string last_part_of_name = name.substr(last_separator_position+1);
+ dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
+
+ // Generate image according to part of name
+ if(generate_image(last_part_of_name, baseimg, driver) == false)
+ {
+ dstream<<"INFO: generate_image_from_scratch(): "
+ "failed to generate \""<<last_part_of_name<<"\""
+ <<std::endl;
+ return NULL;
+ }
+
+ return baseimg;
+}
+
+bool generate_image(std::string part_of_name, video::IImage *& baseimg,
+ video::IVideoDriver* driver)
+{
+ // Stuff starting with [ are special commands
+ if(part_of_name[0] != '[')
+ {
+ // A normal texture; load it from a file
+ std::string path = porting::getDataPath(part_of_name.c_str());
+ dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
+ <<"\""<<std::endl;
+
+ video::IImage *image = driver->createImageFromFile(path.c_str());
+
+ if(image == NULL)
+ {
+ dstream<<"WARNING: Could not load image \""<<part_of_name
+ <<"\" from path \""<<path<<"\""
+ <<" while building texture"<<std::endl;
+ return false;
+ }
+
+ // If base image is NULL, load as base.
+ if(baseimg == NULL)
+ {
+ dstream<<"INFO: Setting "<<part_of_name<<" as base"<<std::endl;
+ /*
+ Copy it this way to get an alpha channel.
+ Otherwise images with alpha cannot be blitted on
+ images that don't have alpha in the original file.
+ */
+ core::dimension2d<u32> dim = image->getDimension();
+ baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+ image->copyTo(baseimg);
+ image->drop();
+ }
+ // Else blit on base.
+ else
+ {
+ dstream<<"INFO: Blitting "<<part_of_name<<" on base"<<std::endl;
+ // Size of the copied area
+ core::dimension2d<u32> dim = image->getDimension();
+ //core::dimension2d<u32> dim(16,16);
+ // Position to copy the blitted to in the base image
+ core::position2d<s32> pos_to(0,0);
+ // Position to copy the blitted from in the blitted image
+ core::position2d<s32> pos_from(0,0);
+ // Blit
+ image->copyToWithAlpha(baseimg, pos_to,
+ core::rect<s32>(pos_from, dim),
+ video::SColor(255,255,255,255),
+ NULL);
+ // Drop image
+ image->drop();
+ }
+ }
+ else
+ {
+ // A special texture modification
+
+ dstream<<"INFO: getTextureIdDirect(): generating special "
+ <<"modification \""<<part_of_name<<"\""
+ <<std::endl;
+
+ if(part_of_name.substr(0,6) == "[crack")
+ {
+ if(baseimg == NULL)
+ {
+ dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
+ <<"for part_of_name="<<part_of_name
+ <<", cancelling."<<std::endl;
+ return false;
+ }
+
+ u16 progression = stoi(part_of_name.substr(6));
+ // Size of the base image
+ core::dimension2d<u32> dim_base = baseimg->getDimension();
+ // Crack will be drawn at this size
+ u32 cracksize = 16;
+ // Size of the crack image
+ core::dimension2d<u32> dim_crack(cracksize,cracksize);
+ // Position to copy the crack from in the crack image
+ core::position2d<s32> pos_other(0, 16 * progression);
+
+ video::IImage *crackimage = driver->createImageFromFile(
+ porting::getDataPath("crack.png").c_str());
+
+ if(crackimage)
+ {
+ /*crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
+ core::rect<s32>(pos_other, dim_base),
+ video::SColor(255,255,255,255),
+ NULL);*/
+
+ for(u32 y0=0; y0<dim_base.Height/dim_crack.Height; y0++)
+ for(u32 x0=0; x0<dim_base.Width/dim_crack.Width; x0++)
+ {
+ // Position to copy the crack to in the base image
+ core::position2d<s32> pos_base(x0*cracksize, y0*cracksize);
+ crackimage->copyToWithAlpha(baseimg, pos_base,
+ core::rect<s32>(pos_other, dim_crack),
+ video::SColor(255,255,255,255),
+ NULL);
+ }
+
+ crackimage->drop();
+ }
+ }
+ else if(part_of_name.substr(0,8) == "[combine")
+ {
+ // "[combine:16x128:0,0=stone.png:0,16=grass.png"
+ Strfnd sf(part_of_name);
+ sf.next(":");
+ u32 w0 = stoi(sf.next("x"));
+ u32 h0 = stoi(sf.next(":"));
+ dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
+ core::dimension2d<u32> dim(w0,h0);
+ baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+ while(sf.atend() == false)
+ {
+ u32 x = stoi(sf.next(","));
+ u32 y = stoi(sf.next("="));
+ std::string filename = sf.next(":");
+ dstream<<"INFO: Adding \""<<filename
+ <<"\" to combined ("<<x<<","<<y<<")"
+ <<std::endl;
+ video::IImage *img = driver->createImageFromFile(
+ porting::getDataPath(filename.c_str()).c_str());
+ if(img)
+ {
+ core::dimension2d<u32> dim = img->getDimension();
+ dstream<<"INFO: Size "<<dim.Width
+ <<"x"<<dim.Height<<std::endl;
+ core::position2d<s32> pos_base(x, y);
+ video::IImage *img2 =
+ driver->createImage(video::ECF_A8R8G8B8, dim);
+ img->copyTo(img2);
+ img->drop();
+ img2->copyToWithAlpha(baseimg, pos_base,
+ core::rect<s32>(v2s32(0,0), dim),
+ video::SColor(255,255,255,255),
+ NULL);
+ img2->drop();
+ }
+ else
+ {
+ dstream<<"WARNING: img==NULL"<<std::endl;
+ }
+ }
+ }
+ else if(part_of_name.substr(0,12) == "[progressbar")
+ {
+ if(baseimg == NULL)
+ {
+ dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
+ <<"for part_of_name="<<part_of_name
+ <<", cancelling."<<std::endl;
+ return false;
+ }
+
+ float value = stof(part_of_name.substr(12));
+ make_progressbar(value, baseimg);
+ }
+ // "[noalpha:filename.png"
+ // Use an image without it's alpha channel
+ else if(part_of_name.substr(0,8) == "[noalpha")
+ {
+ if(baseimg != NULL)
+ {
+ dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
+ <<"for part_of_name="<<part_of_name
+ <<", cancelling."<<std::endl;
+ return false;
+ }
+
+ std::string filename = part_of_name.substr(9);
+
+ std::string path = porting::getDataPath(filename.c_str());
+
+ dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
+ <<"\""<<std::endl;
+
+ video::IImage *image = driver->createImageFromFile(path.c_str());
+
+ if(image == NULL)
+ {
+ dstream<<"WARNING: getTextureIdDirect(): Loading path \""
+ <<path<<"\" failed"<<std::endl;
+ }
+ else
+ {
+ core::dimension2d<u32> dim = image->getDimension();
+ baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+
+ // Set alpha to full
+ for(u32 y=0; y<dim.Height; y++)
+ for(u32 x=0; x<dim.Width; x++)
+ {
+ video::SColor c = image->getPixel(x,y);
+ c.setAlpha(255);
+ image->setPixel(x,y,c);
+ }
+ // Blit
+ image->copyTo(baseimg);
+
+ image->drop();
+ }
+ }
+ else
+ {
+ dstream<<"WARNING: getTextureIdDirect(): Invalid "
+ " modification: \""<<part_of_name<<"\""<<std::endl;
+ }
+ }
+
+ return true;
+}
+
+void make_progressbar(float value, video::IImage *image)
+{
+ if(image == NULL)
+ return;
+
+ core::dimension2d<u32> size = image->getDimension();
+
+ u32 barheight = 1;
+ u32 barpad_x = 1;
+ u32 barpad_y = 1;
+ u32 barwidth = size.Width - barpad_x*2;
+ v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
+
+ u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
+
+ video::SColor active(255,255,0,0);
+ video::SColor inactive(255,0,0,0);
+ for(u32 x0=0; x0<barwidth; x0++)
+ {
+ video::SColor *c;
+ if(x0 < barvalue_i)
+ c = &active;
+ else
+ c = &inactive;
+ u32 x = x0 + barpos.X;
+ for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
+ {
+ image->setPixel(x,y, *c);
+ }
+ }
+}
#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,
/*
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
)
bool operator==(TileSpec &other)
{
return (
- spec == other.spec &&
+ texture == other.texture &&
alpha == other.alpha &&
material_type == other.material_type &&
material_flags == other.material_flags
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