starting to separate "material" to "content" and "tile"
[oweals/minetest.git] / src / mapblock.cpp
index 25561008a1796beb9ffafa8fffdde1701762ddce..0f2eba8568bd6d2d5aad466635e4006c148aec67 100644 (file)
@@ -1,5 +1,20 @@
 /*
-(c) 2010 Perttu Ahola <celeron55@gmail.com>
+Minetest-c55
+Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
 #include "mapblock.h"
@@ -96,7 +111,7 @@ FastFace * MapBlock::makeFastFace(u8 material, u8 light, v3f p,
 
        u8 alpha = 255;
 
-       if(material == MATERIAL_WATER)
+       if(material == MATERIAL_WATER || material == MATERIAL_OCEAN)
        {
                alpha = 128;
        }
@@ -158,13 +173,14 @@ u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir)
 
 /*
        Gets node material from any place relative to block.
-       Returns MATERIAL_AIR if doesn't exist.
+       Returns MATERIAL_IGNORE if doesn't exist or should not be drawn.
 */
 u8 MapBlock::getNodeMaterial(v3s16 p)
 {
        try{
                MapNode n = getNodeParent(p);
-               return n.d;
+               
+               return content_cube_material(n.d);
        }
        catch(InvalidPositionException &e)
        {
@@ -283,6 +299,99 @@ void MapBlock::updateFastFaceRow(v3s16 startpos,
        }
 }
 
+/*
+       This is used because CMeshBuffer::append() is very slow
+*/
+struct PreMeshBuffer
+{
+       video::SMaterial material;
+       core::array<u16> indices;
+       core::array<video::S3DVertex> vertices;
+};
+
+class MeshCollector
+{
+public:
+       void append(
+                       video::SMaterial material,
+                       const video::S3DVertex* const vertices,
+                       u32 numVertices,
+                       const u16* const indices,
+                       u32 numIndices
+               )
+       {
+               PreMeshBuffer *p = NULL;
+               for(u32 i=0; i<m_prebuffers.size(); i++)
+               {
+                       PreMeshBuffer &pp = m_prebuffers[i];
+                       if(pp.material != material)
+                               continue;
+
+                       p = &pp;
+                       break;
+               }
+
+               if(p == NULL)
+               {
+                       PreMeshBuffer pp;
+                       pp.material = material;
+                       m_prebuffers.push_back(pp);
+                       p = &m_prebuffers[m_prebuffers.size()-1];
+               }
+
+               u32 vertex_count = p->vertices.size();
+               for(u32 i=0; i<numIndices; i++)
+               {
+                       u32 j = indices[i] + vertex_count;
+                       if(j > 65535)
+                       {
+                               dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
+                               // NOTE: Fix is to just add an another MeshBuffer
+                       }
+                       p->indices.push_back(j);
+               }
+               for(u32 i=0; i<numVertices; i++)
+               {
+                       p->vertices.push_back(vertices[i]);
+               }
+       }
+
+       void fillMesh(scene::SMesh *mesh)
+       {
+               /*dstream<<"Filling mesh with "<<m_prebuffers.size()
+                               <<" meshbuffers"<<std::endl;*/
+               for(u32 i=0; i<m_prebuffers.size(); i++)
+               {
+                       PreMeshBuffer &p = m_prebuffers[i];
+
+                       /*dstream<<"p.vertices.size()="<<p.vertices.size()
+                                       <<", p.indices.size()="<<p.indices.size()
+                                       <<std::endl;*/
+                       
+                       // Create meshbuffer
+                       
+                       // This is a "Standard MeshBuffer",
+                       // it's a typedeffed CMeshBuffer<video::S3DVertex>
+                       scene::SMeshBuffer *buf = new scene::SMeshBuffer();
+                       // Set material
+                       buf->Material = p.material;
+                       //((scene::SMeshBuffer*)buf)->Material = p.material;
+                       // Use VBO
+                       //buf->setHardwareMappingHint(scene::EHM_STATIC);
+                       // Add to mesh
+                       mesh->addMeshBuffer(buf);
+                       // Mesh grabbed it
+                       buf->drop();
+
+                       buf->append(p.vertices.pointer(), p.vertices.size(),
+                                       p.indices.pointer(), p.indices.size());
+               }
+       }
+
+private:
+       core::array<PreMeshBuffer> m_prebuffers;
+};
+
 void MapBlock::updateMesh()
 {
        /*v3s16 p = getPosRelative();
@@ -344,53 +453,36 @@ void MapBlock::updateMesh()
        
        if(fastfaces_new->getSize() > 0)
        {
-               mesh_new = new scene::SMesh();
-               scene::IMeshBuffer *buf = NULL;
+               MeshCollector collector;
 
                core::list<FastFace*>::Iterator i = fastfaces_new->begin();
 
-               // MATERIAL_AIR shouldn't be used by any face
-               u8 material_in_use = MATERIAL_AIR;
-
                for(; i != fastfaces_new->end(); i++)
                {
                        FastFace *f = *i;
-                       
-                       if(f->material != material_in_use || buf == NULL)
-                       {
-                               // Try to get a meshbuffer associated with the material
-                               buf = mesh_new->getMeshBuffer(g_materials[f->material]);
-                               // If not found, create one
-                               if(buf == NULL)
-                               {
-                                       // This is a "Standard MeshBuffer",
-                                       // it's a typedeffed CMeshBuffer<video::S3DVertex>
-                                       buf = new scene::SMeshBuffer();
-                                       // Set material
-                                       ((scene::SMeshBuffer*)buf)->Material = g_materials[f->material];
-                                       // Use VBO
-                                       //buf->setHardwareMappingHint(scene::EHM_STATIC);
-                                       // Add to mesh
-                                       mesh_new->addMeshBuffer(buf);
-                                       // Mesh grabbed it
-                                       buf->drop();
-                               }
-                               material_in_use = f->material;
-                       }
 
-                       u16 indices[] = {0,1,2,2,3,0};
-                       buf->append(f->vertices, 4, indices, 6);
+                       const u16 indices[] = {0,1,2,2,3,0};
+
+                       collector.append(g_materials[f->material], f->vertices, 4,
+                                       indices, 6);
                }
 
+               mesh_new = new scene::SMesh();
+               
+               collector.fillMesh(mesh_new);
+
                // Use VBO for mesh (this just would set this for ever buffer)
                //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
                
                /*std::cout<<"MapBlock has "<<fastfaces_new->getSize()<<" faces "
                                <<"and uses "<<mesh_new->getMeshBufferCount()
-                               <<" materials"<<std::endl;*/
+                               <<" materials (meshbuffers)"<<std::endl;*/
        }
+       
+       /*
+               Clear temporary FastFaces
+       */
 
-       // TODO: Get rid of the FastFace stage
        core::list<FastFace*>::Iterator i;
        i = fastfaces_new->begin();
        for(; i != fastfaces_new->end(); i++)
@@ -400,6 +492,18 @@ void MapBlock::updateMesh()
        fastfaces_new->clear();
        delete fastfaces_new;
 
+       /*
+               Add special graphics:
+               - torches
+       */
+
+       for(s16 z=0; z<MAP_BLOCKSIZE; z++)
+       for(s16 y=0; y<MAP_BLOCKSIZE; y++)
+       for(s16 x=0; x<MAP_BLOCKSIZE; x++)
+       {
+               v3s16 p(x,y,z);
+       }
+
        /*
                Replace the mesh
        */
@@ -568,6 +672,15 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
        return block_below_is_valid;
 }
 
+void MapBlock::copyTo(VoxelManipulator &dst)
+{
+       v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
+       VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
+       
+       dst.copyFrom(data, data_area, v3s16(0,0,0),
+                       getPosRelative(), data_size);
+}
+
 /*
        Serialization
 */
@@ -627,6 +740,17 @@ void MapBlock::serialize(std::ostream &os, u8 version)
                        paramdata[i] = data[i].param;
                }
                compress(paramdata, os, version);
+               
+               if(version >= 10)
+               {
+                       // Get and compress pressure
+                       SharedBuffer<u8> pressuredata(nodecount);
+                       for(u32 i=0; i<nodecount; i++)
+                       {
+                               pressuredata[i] = data[i].pressure;
+                       }
+                       compress(pressuredata, os, version);
+               }
        }
 }
 
@@ -691,6 +815,21 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
                                data[i].param = s[i];
                        }
                }
+       
+               if(version >= 10)
+               {
+                       // Uncompress and set pressure data
+                       std::ostringstream os(std::ios_base::binary);
+                       decompress(is, os, version);
+                       std::string s = os.str();
+                       if(s.size() != nodecount)
+                               throw SerializationError
+                                               ("MapBlock::deSerialize: invalid format");
+                       for(u32 i=0; i<s.size(); i++)
+                       {
+                               data[i].pressure = s[i];
+                       }
+               }
        }
 }