X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Ftile.cpp;h=89f3451973e078dc8b47fa10916110df8e891e3e;hb=392485aa454e871566a67afc61e11331f9d27397;hp=c8fffffa7ad44fca8a8d16669efd0d0b50e9667d;hpb=c6fd2986d4261cf742d3bc21e8c12be59ab89f95;p=minetest.git diff --git a/src/tile.cpp b/src/tile.cpp index c8fffffa7..89f345197 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "utility.h" #include "settings.h" +#include "mesh.h" #include #include "log.h" #include "mapnode.h" // For texture atlas making @@ -132,7 +133,7 @@ std::string getTexturePath(const std::string &filename) */ if(fullpath == "") { - std::string rel_path = std::string("textures")+DIR_DELIM+filename; + std::string rel_path = std::string("clienttextures")+DIR_DELIM+filename; std::string testpath = porting::path_data + DIR_DELIM + rel_path; // Check all filename extensions. Returns "" if not found. fullpath = getImagePath(testpath); @@ -145,6 +146,108 @@ std::string getTexturePath(const std::string &filename) 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, + bool prefer_local, video::IVideoDriver *driver) + { + assert(img); + // Remove old image + core::map::Node *n; + n = m_images.find(name); + if(n){ + video::IImage *oldimg = n->getValue(); + if(oldimg) + oldimg->drop(); + } + // Try to use local texture instead if asked to + if(prefer_local){ + std::string path = getTexturePath(name.c_str()); + if(path != ""){ + video::IImage *img2 = driver->createImageFromFile(path.c_str()); + if(img2){ + m_images[name] = img2; + return; + } + } + } + img->grab(); + m_images[name] = img; + } + video::IImage* get(const std::string &name) + { + core::map::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::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 \"" + <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 m_images; +}; + /* TextureSource */ @@ -209,9 +312,7 @@ class TextureSource : public IWritableTextureSource */ 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); /* @@ -232,30 +333,29 @@ class TextureSource : public IWritableTextureSource // Gets a separate texture video::ITexture* getTextureRaw(const std::string &name) { - AtlasPointer ap = getTexture(name); + AtlasPointer ap = getTexture(name + "^[forcesingle"); return ap.atlas; } - /* - Update new texture pointer and texture coordinates to an - AtlasPointer based on it's texture id - */ + // Update new texture pointer and texture coordinates to an + // AtlasPointer based on it's texture id void updateAP(AtlasPointer &ap); - /* - Build the main texture atlas which contains most of the - textures. - - This is called by the constructor. - */ - void buildMainAtlas(class IGameDef *gamedef); + // Processes queued texture requests from other threads. + // Shall be called from the main thread. + void processQueue(); - /* - Processes queued texture requests from other threads. + // Insert an image into the cache without touching the filesystem. + // Shall be called from the main thread. + void insertSourceImage(const std::string &name, video::IImage *img); + + // Rebuild images and textures from the current set of source images + // Shall be called from the main thread. + void rebuildImagesAndTextures(); - Shall be called from the main thread. - */ - void processQueue(); + // Build the main texture atlas which contains most of the + // textures. + void buildMainAtlas(class IGameDef *gamedef); private: @@ -264,6 +364,10 @@ class TextureSource : public IWritableTextureSource // The irrlicht 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. // The first position contains a NULL texture. core::array m_atlaspointer_cache; @@ -305,31 +409,6 @@ TextureSource::~TextureSource() { } -void TextureSource::processQueue() -{ - /* - Fetch textures - */ - if(m_get_texture_queue.size() > 0) - { - GetRequest - request = m_get_texture_queue.pop(); - - infostream<<"TextureSource::processQueue(): " - <<"got texture request with " - <<"name=\""< - 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) { //infostream<<"getTextureId(): \""<getValue(); } } - infostream<<"getTextureIdDirect(): \""<= m_atlaspointer_cache.size()) { - infostream<<"TextureSource::getTextureName(): id="<= m_atlaspointer_cache.size()=" < 0) + { + GetRequest + request = m_get_texture_queue.pop(); + + /*infostream<<"TextureSource::processQueue(): " + <<"got texture request with " + <<"name=\""< + result; + result.key = request.key; + result.callers = request.callers; + result.item = getTextureIdDirect(request.key); + + request.dest->push_back(result); + } +} + +void TextureSource::insertSourceImage(const std::string &name, video::IImage *img) +{ + //infostream<<"TextureSource::insertSourceImage(): name="<getVideoDriver()); +} + +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; iatlas_img->drop(); + sap->atlas_img = NULL; + }*/ + + // Recreate textures + for(u32 i=0; iname, 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) { assert(gamedef->tsrc() == this); @@ -708,23 +862,13 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef) { std::string name = i.getNode()->getKey(); - /*video::IImage *img = driver->createImageFromFile( - getTexturePath(name.c_str()).c_str()); - if(img == NULL) - continue; - - core::dimension2d 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, m_device); + video::IImage *img2 = generate_image_from_scratch(name, m_device, + &m_sourcecache); if(img2 == NULL) { - infostream<<"TextureSource::buildMainAtlas(): Couldn't generate texture atlas: Couldn't generate image \""<copyToWithAlpha(atlas_img, + /*img2->copyToWithAlpha(atlas_img, pos_in_atlas + v2s32(j*dim.Width,0), core::rect(v2s32(0,0), dim), video::SColor(255,255,255,255), + NULL);*/ + img2->copyTo(atlas_img, + pos_in_atlas + v2s32(j*dim.Width,0), + core::rect(v2s32(0,0), dim), NULL); } @@ -807,9 +955,9 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef) if(n){ id = n->getValue(); reuse_old_id = true; + /*infostream<<"TextureSource::buildMainAtlas(): " + <<"Replacing old AtlasPointer"<getVideoDriver(); assert(driver); // Stuff starting with [ are special commands - if(part_of_name[0] != '[') + if(part_of_name.size() == 0 || part_of_name[0] != '[') { - // A normal texture; load it from a file - std::string path = getTexturePath(part_of_name.c_str()); - /*infostream<<"generate_image(): Loading path \""<createImageFromFile(path.c_str()); + video::IImage *image = sourcecache->getOrLoad(part_of_name, device); if(image == NULL) { - infostream<<"generate_image(): Could not load image \"" - < dim(2,2); @@ -1015,9 +1157,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, { // A special texture modification - infostream<<"generate_image(): generating special " + /*infostream<<"generate_image(): generating special " <<"modification \""< dim(1,1); + baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); + assert(baseimg); + baseimg->setPixel(0,0, video::SColor(255,myrand()%256, + myrand()%256,myrand()%256)); + } } /* [crackN @@ -1038,7 +1189,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, { if(baseimg == NULL) { - infostream<<"generate_image(): baseimg==NULL " + errorstream<<"generate_image(): baseimg==NULL " <<"for part_of_name=\""<createImageFromFile( - getTexturePath("crack.png").c_str()); + video::IImage *img_crack = sourcecache->getOrLoad("crack.png", device); if(img_crack) { @@ -1143,8 +1293,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, infostream<<"Adding \""<createImageFromFile( - getTexturePath(filename.c_str()).c_str()); + video::IImage *img = sourcecache->getOrLoad(filename, device); if(img) { core::dimension2d dim = img->getDimension(); @@ -1175,7 +1324,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, { if(baseimg == NULL) { - infostream<<"generate_image(): baseimg==NULL " + errorstream<<"generate_image(): baseimg==NULL " <<"for part_of_name=\""<createImageFromFile(path.c_str()); - - if(image == NULL) - { - infostream<<"generate_image(): Loading path \"" - < dim = image->getDimension(); - baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); - - // Set alpha to full - for(u32 y=0; ygetPixel(x,y); - c.setAlpha(255); - image->setPixel(x,y,c); - } - // Blit - image->copyTo(baseimg); - - image->drop(); - } + brighten(baseimg); } /* - "[makealpha:R,G,B:filename.png" - Use an image with converting one color to transparent. + "[noalpha" + Make image completely opaque. + Used for the leaves texture when in old leaves mode, so + that the transparent parts don't look completely black + when simple alpha channel is used for rendering. */ - else if(part_of_name.substr(0,11) == "[makealpha:") + else if(part_of_name.substr(0,8) == "[noalpha") { - if(baseimg != NULL) + if(baseimg == NULL) { - infostream<<"generate_image(): baseimg!=NULL " + errorstream<<"generate_image(): baseimg==NULL " <<"for part_of_name=\""< dim = baseimg->getDimension(); - video::IImage *image = driver->createImageFromFile(path.c_str()); - - if(image == NULL) - { - infostream<<"generate_image(): Loading path \"" - < dim = image->getDimension(); - baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); - - // Blit - image->copyTo(baseimg); - - image->drop(); - - for(u32 y=0; ygetPixel(x,y); - u32 r = c.getRed(); - u32 g = c.getGreen(); - u32 b = c.getBlue(); - if(!(r == r1 && g == g1 && b == b1)) - continue; - c.setAlpha(0); - baseimg->setPixel(x,y,c); - } + video::SColor c = baseimg->getPixel(x,y); + c.setAlpha(255); + baseimg->setPixel(x,y,c); } } /* - "[makealpha2:R,G,B;R2,G2,B2:filename.png" - Use an image with converting two colors to transparent. + "[makealpha:R,G,B" + Convert one color to transparent. */ - else if(part_of_name.substr(0,12) == "[makealpha2:") + else if(part_of_name.substr(0,11) == "[makealpha:") { - if(baseimg != NULL) + if(baseimg == NULL) { - infostream<<"generate_image(): baseimg!=NULL " + errorstream<<"generate_image(): baseimg==NULL " <<"for part_of_name=\""<createImageFromFile(path.c_str()); + core::dimension2d dim = baseimg->getDimension(); - if(image == NULL) - { - infostream<<"generate_image(): Loading path \"" - < dim = image->getDimension(); - baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); - - // Blit - image->copyTo(baseimg); + /*video::IImage *oldbaseimg = baseimg; + baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); + oldbaseimg->copyTo(baseimg); + oldbaseimg->drop();*/ - image->drop(); - - for(u32 y=0; ygetPixel(x,y); - u32 r = c.getRed(); - u32 g = c.getGreen(); - u32 b = c.getBlue(); - if(!(r == r1 && g == g1 && b == b1) && - !(r == r2 && g == g2 && b == b2)) - continue; - c.setAlpha(0); - baseimg->setPixel(x,y,c); - } + // Set alpha to full + for(u32 y=0; ygetPixel(x,y); + u32 r = c.getRed(); + u32 g = c.getGreen(); + u32 b = c.getBlue(); + if(!(r == r1 && g == g1 && b == b1)) + continue; + c.setAlpha(0); + baseimg->setPixel(x,y,c); } } /* @@ -1362,7 +1429,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, { if(baseimg != NULL) { - infostream<<"generate_image(): baseimg!=NULL " + errorstream<<"generate_image(): baseimg!=NULL " <<"for part_of_name=\""<queryFeature(video::EVDF_RENDER_TO_TARGET) == false) { - infostream<<"generate_image(): EVDF_RENDER_TO_TARGET" + errorstream<<"generate_image(): EVDF_RENDER_TO_TARGET" " not supported. Creating fallback image"<addTexture( (imagename_top + "__temp__").c_str(), img_top); - assert(texture_top); - + video::ITexture *texture_left = driver->addTexture( + (imagename_left + "__temp__").c_str(), img_left); + video::ITexture *texture_right = driver->addTexture( + (imagename_right + "__temp__").c_str(), img_right); + assert(texture_top && texture_left && texture_right); + // Drop images img_top->drop(); img_left->drop(); @@ -1432,17 +1503,24 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, Create scene: - An unit cube is centered at 0,0,0 - Camera looks at cube from Y+, Z- towards Y-, Z+ - NOTE: Cube has to be changed to something else because - the textures cannot be set individually (or can they?) */ - scene::ISceneNode* cube = smgr->addCubeSceneNode(1.0, NULL, -1, - v3f(0,0,0), v3f(0, 45, 0)); + scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1)); + setMeshColor(cube, video::SColor(255, 255, 255, 255)); + + scene::IMeshSceneNode* cubenode = smgr->addMeshSceneNode(cube, NULL, -1, v3f(0,0,0), v3f(0,45,0), v3f(1,1,1), true); + cube->drop(); + // Set texture of cube - cube->setMaterialTexture(0, texture_top); - //cube->setMaterialFlag(video::EMF_LIGHTING, false); - cube->setMaterialFlag(video::EMF_ANTI_ALIASING, false); - cube->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); + cubenode->getMaterial(0).setTexture(0, texture_top); + cubenode->getMaterial(1).setTexture(0, texture_top); + cubenode->getMaterial(2).setTexture(0, texture_right); + cubenode->getMaterial(3).setTexture(0, texture_right); + cubenode->getMaterial(4).setTexture(0, texture_left); + cubenode->getMaterial(5).setTexture(0, texture_left); + cubenode->setMaterialFlag(video::EMF_LIGHTING, true); + cubenode->setMaterialFlag(video::EMF_ANTI_ALIASING, true); + cubenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, true); scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0, v3f(0, 1.0, -1.5), v3f(0, 0, 0)); @@ -1452,7 +1530,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, camera->setProjectionMatrix(pm, true); /*scene::ILightSceneNode *light =*/ smgr->addLightSceneNode(0, - v3f(-50, 100, 0), video::SColorf(0.5,0.5,0.5), 1000); + v3f(-50, 100, -75), video::SColorf(0.5,0.5,0.5), 1000); smgr->setAmbientLight(video::SColorf(0.2,0.2,0.2)); @@ -1472,8 +1550,10 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, // Unset render target driver->setRenderTarget(0, true, true, 0); - //TODO: Free textures of images + // Free textures of images driver->removeTexture(texture_top); + driver->removeTexture(texture_left); + driver->removeTexture(texture_right); // Create image of render target video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim); @@ -1491,7 +1571,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, } else { - infostream<<"generate_image(): Invalid " + errorstream<<"generate_image(): Invalid " " modification: \""< dim = image->getDimension(); + + for(u32 y=0; ygetPixel(x,y); + c.setRed(0.5 * 255 + 0.5 * (float)c.getRed()); + c.setGreen(0.5 * 255 + 0.5 * (float)c.getGreen()); + c.setBlue(0.5 * 255 + 0.5 * (float)c.getBlue()); + image->setPixel(x,y,c); + } +} +