Properly update textures in node definitions

This commit is contained in:
Perttu Ahola 2011-11-15 13:13:18 +02:00
parent 45fc45a49e
commit 01ae0daea5
7 changed files with 301 additions and 192 deletions

@ -222,16 +222,14 @@ Client::Client(
// Build main texture atlas, now that the GameDef exists (that is, us) // Build main texture atlas, now that the GameDef exists (that is, us)
if(g_settings->getBool("enable_texture_atlas")) if(g_settings->getBool("enable_texture_atlas"))
tsrc->buildMainAtlas(this); m_tsrc->buildMainAtlas(this);
else else
infostream<<"Not building texture atlas."<<std::endl; infostream<<"Not building texture atlas."<<std::endl;
// Update textures // Update node textures
m_nodedef->updateTextures(tsrc); m_nodedef->updateTextures(m_tsrc);
// NOTE: This should be done only after getting possible dynamic // Start threads after setting up content definitions
// game definitions from the server, or at least shut down and
// restarted when doing so
m_mesh_update_thread.Start(); m_mesh_update_thread.Start();
/* /*
@ -1568,17 +1566,28 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
rfile->drop(); rfile->drop();
continue; continue;
} }
m_tsrc->insertImage(name, img); m_tsrc->insertSourceImage(name, img);
img->drop();
rfile->drop(); rfile->drop();
} }
// Rebuild inherited images and recreate textures
m_tsrc->rebuildImagesAndTextures();
// Update texture atlas // Update texture atlas
if(g_settings->getBool("enable_texture_atlas")) if(g_settings->getBool("enable_texture_atlas"))
m_tsrc->buildMainAtlas(this); m_tsrc->buildMainAtlas(this);
// Update node textures
m_nodedef->updateTextures(m_tsrc);
// Resume threads // Resume threads
m_mesh_update_thread.setRun(true); m_mesh_update_thread.setRun(true);
m_mesh_update_thread.Start(); m_mesh_update_thread.Start();
ClientEvent event;
event.type = CE_TEXTURES_UPDATED;
m_client_event_queue.push_back(event);
} }
else else
{ {

@ -122,6 +122,7 @@ enum ClientEventType
CE_PLAYER_DAMAGE, CE_PLAYER_DAMAGE,
CE_PLAYER_FORCE_MOVE, CE_PLAYER_FORCE_MOVE,
CE_DEATHSCREEN, CE_DEATHSCREEN,
CE_TEXTURES_UPDATED
}; };
struct ClientEvent struct ClientEvent
@ -143,6 +144,8 @@ struct ClientEvent
f32 camera_point_target_y; f32 camera_point_target_y;
f32 camera_point_target_z; f32 camera_point_target_z;
} deathscreen; } deathscreen;
struct{
} textures_updated;
}; };
}; };
@ -302,15 +305,11 @@ public:
ClientEvent getClientEvent(); ClientEvent getClientEvent();
inline bool accessDenied() inline bool accessDenied()
{ { return m_access_denied; }
return m_access_denied;
}
inline std::wstring accessDeniedReason() inline std::wstring accessDeniedReason()
{ { return m_access_denied_reason; }
return m_access_denied_reason;
}
float getRTT(void); float getRTT(void);
// IGameDef interface // IGameDef interface

@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_mapnode.h" // For content_mapnode_init #include "content_mapnode.h" // For content_mapnode_init
#include "tooldef.h" #include "tooldef.h"
#include "content_mapnode.h" // Default nodes #include "content_mapnode.h" // Default nodes
#include "tile.h" // For TextureSource
/* /*
Setting this to 1 enables a special camera mode that forces Setting this to 1 enables a special camera mode that forces
@ -519,7 +520,7 @@ void getPointedNode(Client *client, v3f player_position,
} // for coords } // for coords
} }
void update_skybox(video::IVideoDriver* driver, void update_skybox(video::IVideoDriver* driver, ITextureSource *tsrc,
scene::ISceneManager* smgr, scene::ISceneNode* &skybox, scene::ISceneManager* smgr, scene::ISceneNode* &skybox,
float brightness) float brightness)
{ {
@ -535,32 +536,32 @@ void update_skybox(video::IVideoDriver* driver,
if(brightness >= 0.5) if(brightness >= 0.5)
{ {
skybox = smgr->addSkyBoxSceneNode( skybox = smgr->addSkyBoxSceneNode(
driver->getTexture(getTexturePath("skybox2.png").c_str()), tsrc->getTextureRaw("skybox2.png"),
driver->getTexture(getTexturePath("skybox3.png").c_str()), tsrc->getTextureRaw("skybox3.png"),
driver->getTexture(getTexturePath("skybox1.png").c_str()), tsrc->getTextureRaw("skybox1.png"),
driver->getTexture(getTexturePath("skybox1.png").c_str()), tsrc->getTextureRaw("skybox1.png"),
driver->getTexture(getTexturePath("skybox1.png").c_str()), tsrc->getTextureRaw("skybox1.png"),
driver->getTexture(getTexturePath("skybox1.png").c_str())); tsrc->getTextureRaw("skybox1.png"));
} }
else if(brightness >= 0.2) else if(brightness >= 0.2)
{ {
skybox = smgr->addSkyBoxSceneNode( skybox = smgr->addSkyBoxSceneNode(
driver->getTexture(getTexturePath("skybox2_dawn.png").c_str()), tsrc->getTextureRaw("skybox2_dawn.png"),
driver->getTexture(getTexturePath("skybox3_dawn.png").c_str()), tsrc->getTextureRaw("skybox3_dawn.png"),
driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()), tsrc->getTextureRaw("skybox1_dawn.png"),
driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()), tsrc->getTextureRaw("skybox1_dawn.png"),
driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()), tsrc->getTextureRaw("skybox1_dawn.png"),
driver->getTexture(getTexturePath("skybox1_dawn.png").c_str())); tsrc->getTextureRaw("skybox1_dawn.png"));
} }
else else
{ {
skybox = smgr->addSkyBoxSceneNode( skybox = smgr->addSkyBoxSceneNode(
driver->getTexture(getTexturePath("skybox2_night.png").c_str()), tsrc->getTextureRaw("skybox2_night.png"),
driver->getTexture(getTexturePath("skybox3_night.png").c_str()), tsrc->getTextureRaw("skybox3_night.png"),
driver->getTexture(getTexturePath("skybox1_night.png").c_str()), tsrc->getTextureRaw("skybox1_night.png"),
driver->getTexture(getTexturePath("skybox1_night.png").c_str()), tsrc->getTextureRaw("skybox1_night.png"),
driver->getTexture(getTexturePath("skybox1_night.png").c_str()), tsrc->getTextureRaw("skybox1_night.png"),
driver->getTexture(getTexturePath("skybox1_night.png").c_str())); tsrc->getTextureRaw("skybox1_night.png"));
} }
} }
@ -771,7 +772,7 @@ void the_game(
*/ */
float old_brightness = 1.0; float old_brightness = 1.0;
scene::ISceneNode* skybox = NULL; scene::ISceneNode* skybox = NULL;
update_skybox(driver, smgr, skybox, 1.0); update_skybox(driver, tsrc, smgr, skybox, 1.0);
/* /*
Create the camera node Create the camera node
@ -886,6 +887,8 @@ void the_game(
// A test // A test
//throw con::PeerNotFoundException("lol"); //throw con::PeerNotFoundException("lol");
float brightness = 1.0;
core::list<float> frametime_log; core::list<float> frametime_log;
float nodig_delay_counter = 0.0; float nodig_delay_counter = 0.0;
@ -1537,6 +1540,10 @@ void the_game(
player->setPosition(player->getPosition() + v3f(0,-BS,0)); player->setPosition(player->getPosition() + v3f(0,-BS,0));
camera.update(player, busytime, screensize);*/ camera.update(player, busytime, screensize);*/
} }
else if(event.type == CE_TEXTURES_UPDATED)
{
update_skybox(driver, tsrc, smgr, skybox, brightness);
}
} }
} }
@ -1902,25 +1909,27 @@ void the_game(
/* /*
Calculate stuff for drawing Calculate stuff for drawing
*/ */
/*
Calculate general brightness
*/
u32 daynight_ratio = client.getDayNightRatio(); u32 daynight_ratio = client.getDayNightRatio();
u8 l = decode_light((daynight_ratio * LIGHT_SUN) / 1000); u8 light8 = decode_light((daynight_ratio * LIGHT_SUN) / 1000);
brightness = (float)light8/255.0;
video::SColor bgcolor = video::SColor( video::SColor bgcolor = video::SColor(
255, 255,
bgcolor_bright.getRed() * l / 255, bgcolor_bright.getRed() * brightness,
bgcolor_bright.getGreen() * l / 255, bgcolor_bright.getGreen() * brightness,
bgcolor_bright.getBlue() * l / 255); bgcolor_bright.getBlue() * brightness);
/*skycolor.getRed() * l / 255, /*skycolor.getRed() * brightness,
skycolor.getGreen() * l / 255, skycolor.getGreen() * brightness,
skycolor.getBlue() * l / 255);*/ skycolor.getBlue() * brightness);*/
float brightness = (float)l/255.0;
/* /*
Update skybox Update skybox
*/ */
if(fabs(brightness - old_brightness) > 0.01) if(fabs(brightness - old_brightness) > 0.01)
update_skybox(driver, smgr, skybox, brightness); update_skybox(driver, tsrc, smgr, skybox, brightness);
/* /*
Update clouds Update clouds

@ -174,8 +174,13 @@ public:
ContentFeatures *f = &m_content_features[i]; ContentFeatures *f = &m_content_features[i];
for(u16 j=0; j<6; j++) for(u16 j=0; j<6; j++)
tsrc->updateAP(f->tiles[j].texture); tsrc->updateAP(f->tiles[j].texture);
if(f->special_atlas) if(f->special_atlas){
tsrc->updateAP(*(f->special_atlas)); tsrc->updateAP(*(f->special_atlas));
if(f->special_material)
f->special_material->setTexture(0, f->special_atlas->atlas);
if(f->special_material2)
f->special_material2->setTexture(0, f->special_atlas->atlas);
}
} }
#endif #endif
} }

@ -122,6 +122,9 @@ struct ContentFeatures
// Special irrlicht material, used sometimes // Special irrlicht material, used sometimes
video::SMaterial *special_material; video::SMaterial *special_material;
video::SMaterial *special_material2; video::SMaterial *special_material2;
// Currently used for fetching liquid texture coordinates
// - This is also updated to the above two (if they are non-NULL)
// when textures are updated
AtlasPointer *special_atlas; AtlasPointer *special_atlas;
#endif #endif

@ -145,6 +145,95 @@ std::string getTexturePath(const std::string &filename)
return fullpath; return fullpath;
} }
/*
An internal variant of AtlasPointer with more data.
(well, more like a wrapper)
*/
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_)
{
}
};
/*
SourceImageCache: A cache used for storing source images.
*/
class SourceImageCache
{
public:
void insert(const std::string &name, video::IImage *img)
{
assert(img);
core::map<std::string, video::IImage*>::Node *n;
n = m_images.find(name);
if(n){
video::IImage *oldimg = n->getValue();
if(oldimg)
oldimg->drop();
}
img->grab();
m_images[name] = img;
}
video::IImage* get(const std::string &name)
{
core::map<std::string, video::IImage*>::Node *n;
n = m_images.find(name);
if(n)
return n->getValue();
return NULL;
}
// Primarily fetches from cache, secondarily tries to read from filesystem
video::IImage* getOrLoad(const std::string &name, IrrlichtDevice *device)
{
core::map<std::string, video::IImage*>::Node *n;
n = m_images.find(name);
if(n){
n->getValue()->grab(); // Grab for caller
return n->getValue();
}
video::IVideoDriver* driver = device->getVideoDriver();
std::string path = getTexturePath(name.c_str());
if(path == ""){
infostream<<"SourceImageCache::getOrLoad(): No path found for \""
<<name<<"\""<<std::endl;
return NULL;
}
infostream<<"SourceImageCache::getOrLoad(): Loading path \""<<path
<<"\""<<std::endl;
video::IImage *img = driver->createImageFromFile(path.c_str());
// Even if could not be loaded, put as NULL
//m_images[name] = img;
if(img){
m_images[name] = img;
img->grab(); // Grab for caller
}
return img;
}
private:
core::map<std::string, video::IImage*> m_images;
};
/* /*
TextureSource TextureSource
*/ */
@ -209,9 +298,7 @@ public:
*/ */
u32 getTextureIdDirect(const std::string &name); u32 getTextureIdDirect(const std::string &name);
/* // Finds out the name of a cached texture.
Finds out the name of a cached texture.
*/
std::string getTextureName(u32 id); std::string getTextureName(u32 id);
/* /*
@ -236,29 +323,25 @@ public:
return ap.atlas; return ap.atlas;
} }
/* // Update new texture pointer and texture coordinates to an
Update new texture pointer and texture coordinates to an // AtlasPointer based on it's texture id
AtlasPointer based on it's texture id
*/
void updateAP(AtlasPointer &ap); void updateAP(AtlasPointer &ap);
/* // Processes queued texture requests from other threads.
Processes queued texture requests from other threads. // Shall be called from the main thread.
Shall be called from the main thread.
*/
void processQueue(); void processQueue();
/* // Insert an image into the cache without touching the filesystem.
Build the main texture atlas which contains most of the // Shall be called from the main thread.
textures. void insertSourceImage(const std::string &name, video::IImage *img);
*/
void buildMainAtlas(class IGameDef *gamedef);
/* // Rebuild images and textures from the current set of source images
Insert an image into the cache without touching the filesystem. // Shall be called from the main thread.
*/ void rebuildImagesAndTextures();
void insertImage(const std::string &name, video::IImage *img);
// Build the main texture atlas which contains most of the
// textures.
void buildMainAtlas(class IGameDef *gamedef);
private: private:
@ -267,6 +350,10 @@ private:
// The irrlicht device // The irrlicht device
IrrlichtDevice *m_device; IrrlichtDevice *m_device;
// Cache of source images
// This should be only accessed from the main thread
SourceImageCache m_sourcecache;
// A texture id is index in this array. // A texture id is index in this array.
// The first position contains a NULL texture. // The first position contains a NULL texture.
core::array<SourceAtlasPointer> m_atlaspointer_cache; core::array<SourceAtlasPointer> m_atlaspointer_cache;
@ -376,7 +463,7 @@ void make_progressbar(float value, video::IImage *image);
if baseimg is NULL, it is created. Otherwise stuff is made on it. if baseimg is NULL, it is created. Otherwise stuff is made on it.
*/ */
bool generate_image(std::string part_of_name, video::IImage *& baseimg, bool generate_image(std::string part_of_name, video::IImage *& baseimg,
IrrlichtDevice *device); IrrlichtDevice *device, SourceImageCache *sourcecache);
/* /*
Generates an image from a full string like Generates an image from a full string like
@ -385,7 +472,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
This is used by buildMainAtlas(). This is used by buildMainAtlas().
*/ */
video::IImage* generate_image_from_scratch(std::string name, video::IImage* generate_image_from_scratch(std::string name,
IrrlichtDevice *device); IrrlichtDevice *device, SourceImageCache *sourcecache);
/* /*
This method generates all the textures This method generates all the textures
@ -525,7 +612,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
//infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl; //infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
// Generate image according to part of name // Generate image according to part of name
if(generate_image(last_part_of_name, baseimg, m_device) == false) if(!generate_image(last_part_of_name, baseimg, m_device, &m_sourcecache))
{ {
infostream<<"getTextureIdDirect(): " infostream<<"getTextureIdDirect(): "
"failed to generate \""<<last_part_of_name<<"\"" "failed to generate \""<<last_part_of_name<<"\""
@ -627,6 +714,91 @@ void TextureSource::processQueue()
} }
} }
void TextureSource::insertSourceImage(const std::string &name, video::IImage *img)
{
infostream<<"TextureSource::insertSourceImage(): name="<<name<<std::endl;
assert(get_current_thread_id() == m_main_thread);
m_sourcecache.insert(name, img);
#if 0
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
video::IVideoDriver* driver = m_device->getVideoDriver();
assert(driver);
// Create texture
video::ITexture *t = driver->addTexture(name.c_str(), img);
bool reuse_old_id = false;
u32 id = m_atlaspointer_cache.size();
// Check old id without fetching a texture
core::map<std::string, u32>::Node *n;
n = m_name_to_id.find(name);
// If it exists, we will replace the old definition
if(n){
id = n->getValue();
reuse_old_id = true;
}
// Create AtlasPointer
AtlasPointer ap(id);
ap.atlas = t;
ap.pos = v2f(0,0);
ap.size = v2f(1,1);
ap.tiled = 0;
core::dimension2d<u32> dim = img->getDimension();
// Create SourceAtlasPointer and add to containers
SourceAtlasPointer nap(name, ap, img, v2s32(0,0), dim);
if(reuse_old_id)
m_atlaspointer_cache[id] = nap;
else
m_atlaspointer_cache.push_back(nap);
m_name_to_id[name] = id;
#endif
}
void TextureSource::rebuildImagesAndTextures()
{
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
/*// Oh well... just clear everything, they'll load sometime.
m_atlaspointer_cache.clear();
m_name_to_id.clear();*/
video::IVideoDriver* driver = m_device->getVideoDriver();
// Remove source images from textures to disable inheriting textures
// from existing textures
/*for(u32 i=0; i<m_atlaspointer_cache.size(); i++){
SourceAtlasPointer *sap = &m_atlaspointer_cache[i];
sap->atlas_img->drop();
sap->atlas_img = NULL;
}*/
// Recreate textures
for(u32 i=0; i<m_atlaspointer_cache.size(); i++){
SourceAtlasPointer *sap = &m_atlaspointer_cache[i];
video::IImage *img =
generate_image_from_scratch(sap->name, m_device, &m_sourcecache);
// Create texture from resulting image
video::ITexture *t = NULL;
if(img)
t = driver->addTexture(sap->name.c_str(), img);
// Replace texture
sap->a.atlas = t;
sap->a.pos = v2f(0,0);
sap->a.size = v2f(1,1);
sap->a.tiled = 0;
sap->atlas_img = img;
sap->intpos = v2s32(0,0);
sap->intsize = img->getDimension();
}
}
void TextureSource::buildMainAtlas(class IGameDef *gamedef) void TextureSource::buildMainAtlas(class IGameDef *gamedef)
{ {
assert(gamedef->tsrc() == this); assert(gamedef->tsrc() == this);
@ -711,20 +883,9 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
{ {
std::string name = i.getNode()->getKey(); std::string name = i.getNode()->getKey();
/*video::IImage *img = driver->createImageFromFile(
getTexturePath(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 // Generate image by name
video::IImage *img2 = generate_image_from_scratch(name, m_device); video::IImage *img2 = generate_image_from_scratch(name, m_device,
&m_sourcecache);
if(img2 == NULL) if(img2 == NULL)
{ {
infostream<<"TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl; infostream<<"TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<<name<<"\""<<std::endl;
@ -810,9 +971,9 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
if(n){ if(n){
id = n->getValue(); id = n->getValue();
reuse_old_id = true; reuse_old_id = true;
infostream<<"TextureSource::buildMainAtlas(): "
<<"Replacing old AtlasPointer"<<std::endl;
} }
infostream<<"TextureSource::buildMainAtlas(): "
<<"Replacing old AtlasPointer"<<std::endl;
// Create AtlasPointer // Create AtlasPointer
AtlasPointer ap(id); AtlasPointer ap(id);
@ -867,48 +1028,8 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
driver->writeImageToFile(atlas_img, atlaspath.c_str());*/ driver->writeImageToFile(atlas_img, atlaspath.c_str());*/
} }
void TextureSource::insertImage(const std::string &name, video::IImage *img)
{
infostream<<"TextureSource::insertImage(): name="<<name<<std::endl;
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
video::IVideoDriver* driver = m_device->getVideoDriver();
assert(driver);
// Create texture
video::ITexture *t = driver->addTexture(name.c_str(), img);
bool reuse_old_id = false;
u32 id = m_atlaspointer_cache.size();
// Check old id without fetching a texture
core::map<std::string, u32>::Node *n;
n = m_name_to_id.find(name);
// If it exists, we will replace the old definition
if(n){
id = n->getValue();
reuse_old_id = true;
}
// Create AtlasPointer
AtlasPointer ap(id);
ap.atlas = t;
ap.pos = v2f(0,0);
ap.size = v2f(1,1);
ap.tiled = 0;
core::dimension2d<u32> dim = img->getDimension();
// Create SourceAtlasPointer and add to containers
SourceAtlasPointer nap(name, ap, img, v2s32(0,0), dim);
if(reuse_old_id)
m_atlaspointer_cache[id] = nap;
else
m_atlaspointer_cache.push_back(nap);
m_name_to_id[name] = id;
}
video::IImage* generate_image_from_scratch(std::string name, video::IImage* generate_image_from_scratch(std::string name,
IrrlichtDevice *device) IrrlichtDevice *device, SourceImageCache *sourcecache)
{ {
/*infostream<<"generate_image_from_scratch(): " /*infostream<<"generate_image_from_scratch(): "
"\""<<name<<"\""<<std::endl;*/ "\""<<name<<"\""<<std::endl;*/
@ -951,7 +1072,8 @@ video::IImage* generate_image_from_scratch(std::string name,
/*infostream<<"generate_image_from_scratch(): Calling itself recursively" /*infostream<<"generate_image_from_scratch(): Calling itself recursively"
" to get base image of \""<<name<<"\" = \"" " to get base image of \""<<name<<"\" = \""
<<base_image_name<<"\""<<std::endl;*/ <<base_image_name<<"\""<<std::endl;*/
baseimg = generate_image_from_scratch(base_image_name, device); baseimg = generate_image_from_scratch(base_image_name, device,
sourcecache);
} }
/* /*
@ -963,7 +1085,7 @@ video::IImage* generate_image_from_scratch(std::string name,
//infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl; //infostream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
// Generate image according to part of name // Generate image according to part of name
if(generate_image(last_part_of_name, baseimg, device) == false) if(!generate_image(last_part_of_name, baseimg, device, sourcecache))
{ {
infostream<<"generate_image_from_scratch(): " infostream<<"generate_image_from_scratch(): "
"failed to generate \""<<last_part_of_name<<"\"" "failed to generate \""<<last_part_of_name<<"\""
@ -975,7 +1097,7 @@ video::IImage* generate_image_from_scratch(std::string name,
} }
bool generate_image(std::string part_of_name, video::IImage *& baseimg, bool generate_image(std::string part_of_name, video::IImage *& baseimg,
IrrlichtDevice *device) IrrlichtDevice *device, SourceImageCache *sourcecache)
{ {
video::IVideoDriver* driver = device->getVideoDriver(); video::IVideoDriver* driver = device->getVideoDriver();
assert(driver); assert(driver);
@ -983,18 +1105,12 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
// Stuff starting with [ are special commands // Stuff starting with [ are special commands
if(part_of_name[0] != '[') if(part_of_name[0] != '[')
{ {
// A normal texture; load it from a file video::IImage *image = sourcecache->getOrLoad(part_of_name, device);
std::string path = getTexturePath(part_of_name.c_str());
/*infostream<<"generate_image(): Loading path \""<<path
<<"\""<<std::endl;*/
video::IImage *image = driver->createImageFromFile(path.c_str());
if(image == NULL) if(image == NULL)
{ {
infostream<<"generate_image(): Could not load image \"" infostream<<"generate_image(): Could not load image \""
<<part_of_name<<"\" from path \""<<path<<"\"" <<part_of_name<<"\""<<" while building texture"<<std::endl;
<<" while building texture"<<std::endl;
//return false; //return false;
@ -1099,8 +1215,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
It is an image with a number of cracking stages It is an image with a number of cracking stages
horizontally tiled. horizontally tiled.
*/ */
video::IImage *img_crack = driver->createImageFromFile( video::IImage *img_crack = sourcecache->getOrLoad("crack.png", device);
getTexturePath("crack.png").c_str());
if(img_crack) if(img_crack)
{ {
@ -1186,8 +1301,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
infostream<<"Adding \""<<filename infostream<<"Adding \""<<filename
<<"\" to combined ("<<x<<","<<y<<")" <<"\" to combined ("<<x<<","<<y<<")"
<<std::endl; <<std::endl;
video::IImage *img = driver->createImageFromFile( video::IImage *img = sourcecache->getOrLoad(filename, device);
getTexturePath(filename.c_str()).c_str());
if(img) if(img)
{ {
core::dimension2d<u32> dim = img->getDimension(); core::dimension2d<u32> dim = img->getDimension();
@ -1248,10 +1362,10 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
std::string path = getTexturePath(filename.c_str()); std::string path = getTexturePath(filename.c_str());
infostream<<"generate_image(): Loading path \""<<path infostream<<"generate_image(): Loading file \""<<filename
<<"\""<<std::endl; <<"\""<<std::endl;
video::IImage *image = driver->createImageFromFile(path.c_str()); video::IImage *image = sourcecache->getOrLoad(filename, device);
if(image == NULL) if(image == NULL)
{ {
@ -1297,17 +1411,15 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
u32 b1 = stoi(sf.next(":")); u32 b1 = stoi(sf.next(":"));
std::string filename = sf.next(""); std::string filename = sf.next("");
std::string path = getTexturePath(filename.c_str()); infostream<<"generate_image(): Loading file \""<<filename
infostream<<"generate_image(): Loading path \""<<path
<<"\""<<std::endl; <<"\""<<std::endl;
video::IImage *image = driver->createImageFromFile(path.c_str()); video::IImage *image = sourcecache->getOrLoad(filename, device);
if(image == NULL) if(image == NULL)
{ {
infostream<<"generate_image(): Loading path \"" infostream<<"generate_image(): Loading file \""
<<path<<"\" failed"<<std::endl; <<filename<<"\" failed"<<std::endl;
} }
else else
{ {
@ -1356,17 +1468,15 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
u32 b2 = stoi(sf.next(":")); u32 b2 = stoi(sf.next(":"));
std::string filename = sf.next(""); std::string filename = sf.next("");
std::string path = getTexturePath(filename.c_str()); infostream<<"generate_image(): Loading filename \""<<filename
infostream<<"generate_image(): Loading path \""<<path
<<"\""<<std::endl; <<"\""<<std::endl;
video::IImage *image = driver->createImageFromFile(path.c_str()); video::IImage *image = sourcecache->getOrLoad(filename, device);
if(image == NULL) if(image == NULL)
{ {
infostream<<"generate_image(): Loading path \"" infostream<<"generate_image(): Loading file \""
<<path<<"\" failed"<<std::endl; <<filename<<"\" failed"<<std::endl;
} }
else else
{ {
@ -1419,14 +1529,14 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
std::string imagename_right = sf.next("{"); std::string imagename_right = sf.next("{");
#if 1 #if 1
//TODO // TODO: Create cube with different textures on different sides
if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false) if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
{ {
infostream<<"generate_image(): EVDF_RENDER_TO_TARGET" infostream<<"generate_image(): EVDF_RENDER_TO_TARGET"
" not supported. Creating fallback image"<<std::endl; " not supported. Creating fallback image"<<std::endl;
baseimg = generate_image_from_scratch( baseimg = generate_image_from_scratch(
imagename_top, device); imagename_top, device, sourcecache);
return true; return true;
} }
@ -1437,14 +1547,15 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
// Generate images for the faces of the cube // Generate images for the faces of the cube
video::IImage *img_top = generate_image_from_scratch( video::IImage *img_top = generate_image_from_scratch(
imagename_top, device); imagename_top, device, sourcecache);
video::IImage *img_left = generate_image_from_scratch( video::IImage *img_left = generate_image_from_scratch(
imagename_left, device); imagename_left, device, sourcecache);
video::IImage *img_right = generate_image_from_scratch( video::IImage *img_right = generate_image_from_scratch(
imagename_right, device); imagename_right, device, sourcecache);
assert(img_top && img_left && img_right); assert(img_top && img_left && img_right);
// TODO: Create textures from images // Create textures from images
// TODO: Use them all
video::ITexture *texture_top = driver->addTexture( video::ITexture *texture_top = driver->addTexture(
(imagename_top + "__temp__").c_str(), img_top); (imagename_top + "__temp__").c_str(), img_top);
assert(texture_top); assert(texture_top);
@ -1515,7 +1626,8 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
// Unset render target // Unset render target
driver->setRenderTarget(0, true, true, 0); driver->setRenderTarget(0, true, true, 0);
//TODO: Free textures of images // Free textures of images
// TODO: When all are used, free them all
driver->removeTexture(texture_top); driver->removeTexture(texture_top);
// Create image of render target // Create image of render target

@ -93,34 +93,6 @@ struct AtlasPointer
float y1(){ return pos.Y + size.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_)
{
}
};
/* /*
TextureSource creates and caches textures. TextureSource creates and caches textures.
*/ */
@ -157,9 +129,9 @@ public:
virtual void updateAP(AtlasPointer &ap){}; virtual void updateAP(AtlasPointer &ap){};
virtual void processQueue()=0; virtual void processQueue()=0;
virtual void insertSourceImage(const std::string &name, video::IImage *img)=0;
virtual void rebuildImagesAndTextures()=0;
virtual void buildMainAtlas(class IGameDef *gamedef)=0; virtual void buildMainAtlas(class IGameDef *gamedef)=0;
// img is eaten, do not drop it
virtual void insertImage(const std::string &name, video::IImage *img)=0;
}; };
IWritableTextureSource* createTextureSource(IrrlichtDevice *device); IWritableTextureSource* createTextureSource(IrrlichtDevice *device);