Add different automatic profiler graph drawing style for relative-ish plots
[oweals/minetest.git] / src / tile.cpp
index 29c6b3e671d476238fbd3850ca72052525037e28..4af7a327273d0059ad32aecdff3416836f6d2132 100644 (file)
@@ -23,10 +23,10 @@ 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 <ICameraSceneNode.h>
 #include "log.h"
 #include "mapnode.h" // For texture atlas making
-#include "mineral.h" // For texture atlas making
 #include "nodedef.h" // For texture atlas making
 #include "gamedef.h"
 
@@ -132,8 +132,9 @@ std::string getTexturePath(const std::string &filename)
        */
        if(fullpath == "")
        {
-               std::string rel_path = std::string("clienttextures")+DIR_DELIM+filename;
-               std::string testpath = porting::path_data + DIR_DELIM + rel_path;
+               std::string base_path = porting::path_share + DIR_DELIM + "textures"
+                               + DIR_DELIM + "base" + DIR_DELIM + "pack";
+               std::string testpath = base_path + DIR_DELIM + filename;
                // Check all filename extensions. Returns "" if not found.
                fullpath = getImagePath(testpath);
        }
@@ -278,12 +279,14 @@ public:
                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),
+               - Now getNodeTile() stumbles upon a node which uses
+                 texture id 1, and determines that MATERIAL_FLAG_CRACK
+                 must be applied to the tile
+               - MapBlockMesh::animate() finds the MATERIAL_FLAG_CRACK and
+                 has received the current crack level 0 from the client. 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")
+                 getTextureId("stone.png^mineral1^crack0").
 
        */
        
@@ -298,8 +301,8 @@ public:
                Example names:
                "stone.png"
                "stone.png^crack2"
-               "stone.png^blit:mineral_coal.png"
-               "stone.png^blit:mineral_coal.png^crack1"
+               "stone.png^mineral_coal.png"
+               "stone.png^mineral_coal.png^crack1"
 
                - If texture specified by name is found from cache, return the
                  cached id.
@@ -332,10 +335,22 @@ public:
        // Gets a separate texture
        video::ITexture* getTextureRaw(const std::string &name)
        {
-               AtlasPointer ap = getTexture(name);
+               AtlasPointer ap = getTexture(name + "^[forcesingle");
                return ap.atlas;
        }
 
+       // Gets a separate texture atlas pointer
+       AtlasPointer getTextureRawAP(const AtlasPointer &ap)
+       {
+               return getTexture(getTextureName(ap.id) + "^[forcesingle");
+       }
+
+       // Returns a pointer to the irrlicht device
+       virtual IrrlichtDevice* getDevice()
+       {
+               return m_device;
+       }
+
        // Update new texture pointer and texture coordinates to an
        // AtlasPointer based on it's texture id
        void updateAP(AtlasPointer &ap);
@@ -468,8 +483,9 @@ u32 TextureSource::getTextureId(const std::string &name)
        return 0;
 }
 
-// Draw a progress bar on the image
-void make_progressbar(float value, video::IImage *image);
+// Overlay image on top of another image (used for cracks)
+void overlay(video::IImage *image, video::IImage *overlay);
+
 // Brighten image
 void brighten(video::IImage *image);
 
@@ -815,20 +831,10 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
                if(j == CONTENT_IGNORE || j == CONTENT_AIR)
                        continue;
                const ContentFeatures &f = ndef->get(j);
-               for(std::set<std::string>::const_iterator
-                               i = f.used_texturenames.begin();
-                               i != f.used_texturenames.end(); i++)
+               for(u32 i=0; i<6; i++)
                {
-                       std::string name = *i;
+                       std::string name = f.tname_tiles[i];
                        sourcelist[name] = true;
-
-                       if(f.often_contains_mineral){
-                               for(int k=1; k<MINERAL_COUNT; k++){
-                                       std::string mineraltexture = mineral_block_texture(k);
-                                       std::string fulltexture = name + "^" + mineraltexture;
-                                       sourcelist[fulltexture] = true;
-                               }
-                       }
                }
        }
        
@@ -1003,7 +1009,7 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
        /*
                Write image to file so that it can be inspected
        */
-       /*std::string atlaspath = porting::path_userdata
+       /*std::string atlaspath = porting::path_user
                        + DIR_DELIM + "generated_texture_atlas.png";
        infostream<<"Removing and writing texture atlas for inspection to "
                        <<atlaspath<<std::endl;
@@ -1029,15 +1035,9 @@ video::IImage* generate_image_from_scratch(std::string name,
        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;
-               }
-       }
+       s32 last_separator_position = name.find_last_of(separator);
+       //if(last_separator_position == std::npos)
+       //      last_separator_position = -1;
 
        /*infostream<<"generate_image_from_scratch(): "
                        <<"last_separator_position="<<last_separator_position
@@ -1170,6 +1170,15 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                */
                if(part_of_name == "[forcesingle")
                {
+                       // If base image is NULL, create a random color
+                       if(baseimg == NULL)
+                       {
+                               core::dimension2d<u32> 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
@@ -1185,8 +1194,19 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                                return false;
                        }
                        
-                       // Crack image number
-                       u16 progression = stoi(part_of_name.substr(6));
+                       // Crack image number and overlay option
+                       s32 progression = 0;
+                       bool use_overlay = false;
+                       if(part_of_name.substr(6,1) == "o")
+                       {
+                               progression = stoi(part_of_name.substr(7));
+                               use_overlay = true;
+                       }
+                       else
+                       {
+                               progression = stoi(part_of_name.substr(6));
+                               use_overlay = false;
+                       }
 
                        // Size of the base image
                        core::dimension2d<u32> dim_base = baseimg->getDimension();
@@ -1199,65 +1219,56 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        */
                        video::IImage *img_crack = sourcecache->getOrLoad("crack.png", device);
                
-                       if(img_crack)
+                       if(img_crack && progression >= 0)
                        {
                                // Dimension of original image
                                core::dimension2d<u32> dim_crack
                                                = img_crack->getDimension();
                                // Count of crack stages
-                               u32 crack_count = dim_crack.Height / dim_crack.Width;
+                               s32 crack_count = dim_crack.Height / dim_crack.Width;
                                // Limit progression
                                if(progression > crack_count-1)
                                        progression = crack_count-1;
-                               // Dimension of a single scaled crack stage
-                               core::dimension2d<u32> dim_crack_scaled_single(
-                                       dim_base.Width,
-                                       dim_base.Height
-                               );
-                               // Dimension of scaled size
-                               core::dimension2d<u32> dim_crack_scaled(
-                                       dim_crack_scaled_single.Width,
-                                       dim_crack_scaled_single.Height * crack_count
+                               // Dimension of a single crack stage
+                               core::dimension2d<u32> dim_crack_cropped(
+                                       dim_crack.Width,
+                                       dim_crack.Width
                                );
-                               // Create scaled crack image
+                               // Create cropped and scaled crack images
+                               video::IImage *img_crack_cropped = driver->createImage(
+                                               video::ECF_A8R8G8B8, dim_crack_cropped);
                                video::IImage *img_crack_scaled = driver->createImage(
-                                               video::ECF_A8R8G8B8, dim_crack_scaled);
-                               if(img_crack_scaled)
+                                               video::ECF_A8R8G8B8, dim_base);
+
+                               if(img_crack_cropped && img_crack_scaled)
                                {
+                                       // Crop crack image
+                                       v2s32 pos_crack(0, progression*dim_crack.Width);
+                                       img_crack->copyTo(img_crack_cropped,
+                                                       v2s32(0,0),
+                                                       core::rect<s32>(pos_crack, dim_crack_cropped));
                                        // Scale crack image by copying
-                                       img_crack->copyToScaling(img_crack_scaled);
-                                       
-                                       // Position to copy the crack from
-                                       core::position2d<s32> pos_crack_scaled(
-                                               0,
-                                               dim_crack_scaled_single.Height * progression
-                                       );
-                                       
-                                       // This tiling does nothing currently but is useful
-                                       for(u32 y0=0; y0<dim_base.Height
-                                                       / dim_crack_scaled_single.Height; y0++)
-                                       for(u32 x0=0; x0<dim_base.Width
-                                                       / dim_crack_scaled_single.Width; x0++)
+                                       img_crack_cropped->copyToScaling(img_crack_scaled);
+                                       // Copy or overlay crack image
+                                       if(use_overlay)
                                        {
-                                               // Position to copy the crack to in the base image
-                                               core::position2d<s32> pos_base(
-                                                       x0*dim_crack_scaled_single.Width,
-                                                       y0*dim_crack_scaled_single.Height
-                                               );
-                                               // Rectangle to copy the crack from on the scaled image
-                                               core::rect<s32> rect_crack_scaled(
-                                                       pos_crack_scaled,
-                                                       dim_crack_scaled_single
-                                               );
-                                               // Copy it
-                                               img_crack_scaled->copyToWithAlpha(baseimg, pos_base,
-                                                               rect_crack_scaled,
-                                                               video::SColor(255,255,255,255),
-                                                               NULL);
+                                               overlay(baseimg, img_crack_scaled);
                                        }
+                                       else
+                                       {
+                                               img_crack_scaled->copyToWithAlpha(
+                                                               baseimg,
+                                                               v2s32(0,0),
+                                                               core::rect<s32>(v2s32(0,0), dim_base),
+                                                               video::SColor(255,255,255,255));
+                                       }
+                               }
 
+                               if(img_crack_scaled)
                                        img_crack_scaled->drop();
-                               }
+
+                               if(img_crack_cropped)
+                                       img_crack_cropped->drop();
                                
                                img_crack->drop();
                        }
@@ -1306,23 +1317,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                                }
                        }
                }
-               /*
-                       [progressbarN
-                       Adds a progress bar, 0.0 <= N <= 1.0
-               */
-               else if(part_of_name.substr(0,12) == "[progressbar")
-               {
-                       if(baseimg == NULL)
-                       {
-                               errorstream<<"generate_image(): 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);
-               }
                /*
                        "[brighten"
                */
@@ -1432,23 +1426,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        std::string imagename_left = sf.next("{");
                        std::string imagename_right = sf.next("{");
 
-#if 1
-                       // TODO: Create cube with different textures on different sides
-
-                       if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
-                       {
-                               errorstream<<"generate_image(): EVDF_RENDER_TO_TARGET"
-                                               " not supported. Creating fallback image"<<std::endl;
-                               baseimg = generate_image_from_scratch(
-                                               imagename_top, device, sourcecache);
-                               return true;
-                       }
-                       
-                       u32 w0 = 64;
-                       u32 h0 = 64;
-                       //infostream<<"inventorycube w="<<w0<<" h="<<h0<<std::endl;
-                       core::dimension2d<u32> dim(w0,h0);
-                       
                        // Generate images for the faces of the cube
                        video::IImage *img_top = generate_image_from_scratch(
                                        imagename_top, device, sourcecache);
@@ -1459,86 +1436,76 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        assert(img_top && img_left && img_right);
 
                        // Create textures from images
-                       // TODO: Use them all
                        video::ITexture *texture_top = driver->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();
                        img_right->drop();
                        
-                       // Create render target texture
-                       video::ITexture *rtt = NULL;
-                       std::string rtt_name = part_of_name + "_RTT";
-                       rtt = driver->addRenderTargetTexture(dim, rtt_name.c_str(),
-                                       video::ECF_A8R8G8B8);
-                       assert(rtt);
-                       
-                       // Set render target
-                       driver->setRenderTarget(rtt, true, true,
-                                       video::SColor(0,0,0,0));
-                       
-                       // Get a scene manager
-                       scene::ISceneManager *smgr_main = device->getSceneManager();
-                       assert(smgr_main);
-                       scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
-                       assert(smgr);
-                       
                        /*
-                               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?)
+                               Draw a cube mesh into a render target texture
                        */
-
-                       scene::ISceneNode* cube = smgr->addCubeSceneNode(1.0, NULL, -1,
-                                       v3f(0,0,0), v3f(0, 45, 0));
-                       // 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);
-
-                       scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
-                                       v3f(0, 1.0, -1.5), v3f(0, 0, 0));
+                       scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1));
+                       setMeshColor(cube, video::SColor(255, 255, 255, 255));
+                       cube->getMeshBuffer(0)->getMaterial().setTexture(0, texture_top);
+                       cube->getMeshBuffer(1)->getMaterial().setTexture(0, texture_top);
+                       cube->getMeshBuffer(2)->getMaterial().setTexture(0, texture_right);
+                       cube->getMeshBuffer(3)->getMaterial().setTexture(0, texture_right);
+                       cube->getMeshBuffer(4)->getMaterial().setTexture(0, texture_left);
+                       cube->getMeshBuffer(5)->getMaterial().setTexture(0, texture_left);
+
+                       core::dimension2d<u32> dim(64,64);
+                       std::string rtt_texture_name = part_of_name + "_RTT";
+
+                       v3f camera_position(0, 1.0, -1.5);
+                       camera_position.rotateXZBy(45);
+                       v3f camera_lookat(0, 0, 0);
+                       core::CMatrix4<f32> camera_projection_matrix;
                        // Set orthogonal projection
-                       core::CMatrix4<f32> pm;
-                       pm.buildProjectionMatrixOrthoLH(1.65, 1.65, 0, 100);
-                       camera->setProjectionMatrix(pm, true);
-
-                       /*scene::ILightSceneNode *light =*/ smgr->addLightSceneNode(0,
-                                       v3f(-50, 100, 0), video::SColorf(0.5,0.5,0.5), 1000);
-
-                       smgr->setAmbientLight(video::SColorf(0.2,0.2,0.2));
-
-                       // Render scene
-                       driver->beginScene(true, true, video::SColor(0,0,0,0));
-                       smgr->drawAll();
-                       driver->endScene();
-                       
-                       // NOTE: The scene nodes should not be dropped, otherwise
-                       //       smgr->drop() segfaults
-                       /*cube->drop();
-                       camera->drop();
-                       light->drop();*/
-                       // Drop scene manager
-                       smgr->drop();
+                       camera_projection_matrix.buildProjectionMatrixOrthoLH(
+                                       1.65, 1.65, 0, 100);
+
+                       video::SColorf ambient_light(0.2,0.2,0.2);
+                       v3f light_position(10, 100, -50);
+                       video::SColorf light_color(0.5,0.5,0.5);
+                       f32 light_radius = 1000;
+
+                       video::ITexture *rtt = generateTextureFromMesh(
+                                       cube, device, dim, rtt_texture_name,
+                                       camera_position,
+                                       camera_lookat,
+                                       camera_projection_matrix,
+                                       ambient_light,
+                                       light_position,
+                                       light_color,
+                                       light_radius);
                        
-                       // Unset render target
-                       driver->setRenderTarget(0, true, true, 0);
+                       // Drop mesh
+                       cube->drop();
 
                        // Free textures of images
-                       // TODO: When all are used, free them all
                        driver->removeTexture(texture_top);
+                       driver->removeTexture(texture_left);
+                       driver->removeTexture(texture_right);
                        
+                       if(rtt == NULL)
+                       {
+                               baseimg = generate_image_from_scratch(
+                                               imagename_top, device, sourcecache);
+                               return true;
+                       }
+
                        // Create image of render target
                        video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
-
                        assert(image);
-                       
+
                        baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
 
                        if(image)
@@ -1546,7 +1513,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                                image->copyTo(baseimg);
                                image->drop();
                        }
-#endif
                }
                else
                {
@@ -1558,35 +1524,34 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
        return true;
 }
 
-void make_progressbar(float value, video::IImage *image)
+void overlay(video::IImage *image, video::IImage *overlay)
 {
-       if(image == NULL)
+       /*
+               Copy overlay to image, taking alpha into account.
+               Where image is transparent, don't copy from overlay.
+               Images sizes must be identical.
+       */
+       if(image == NULL || overlay == NULL)
                return;
        
-       core::dimension2d<u32> size = image->getDimension();
-
-       u32 barheight = size.Height/16;
-       u32 barpad_x = size.Width/16;
-       u32 barpad_y = size.Height/16;
-       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);
+       core::dimension2d<u32> dim = image->getDimension();
+       core::dimension2d<u32> dim_overlay = overlay->getDimension();
+       assert(dim == dim_overlay);
 
-       video::SColor active(255,255,0,0);
-       video::SColor inactive(255,0,0,0);
-       for(u32 x0=0; x0<barwidth; x0++)
+       for(u32 y=0; y<dim.Height; y++)
+       for(u32 x=0; x<dim.Width; x++)
        {
-               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++)
+               video::SColor c1 = image->getPixel(x,y);
+               video::SColor c2 = overlay->getPixel(x,y);
+               u32 a1 = c1.getAlpha();
+               u32 a2 = c2.getAlpha();
+               if(a1 == 255 && a2 != 0)
                {
-                       image->setPixel(x,y, *c);
+                       c1.setRed((c1.getRed()*(255-a2) + c2.getRed()*a2)/255);
+                       c1.setGreen((c1.getGreen()*(255-a2) + c2.getGreen()*a2)/255);
+                       c1.setBlue((c1.getBlue()*(255-a2) + c2.getBlue()*a2)/255);
                }
+               image->setPixel(x,y,c1);
        }
 }