]> git.lizzy.rs Git - minetest.git/blobdiff - src/mapblock_mesh.cpp
Conf.example generation: Remove quotation marks from noise flags (#7844)
[minetest.git] / src / mapblock_mesh.cpp
index 7708fb43878e60779130bd0c187374cea16ddc21..ed8a073de5792bbc92464b8f2ff820c3327f6773 100644 (file)
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "minimap.h"
 #include "content_mapblock.h"
 #include "util/directiontables.h"
+#include "client/meshgen/collector.h"
 #include "client/renderingengine.h"
 #include <array>
 
@@ -127,21 +128,11 @@ void MeshMakeData::setSmoothLighting(bool smooth_lighting)
        Single light bank.
 */
 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
-               INodeDefManager *ndef)
+       const NodeDefManager *ndef)
 {
        u8 light = n.getLight(bank, ndef);
-
-       while(increment > 0)
-       {
-               light = undiminish_light(light);
-               --increment;
-       }
-       while(increment < 0)
-       {
-               light = diminish_light(light);
-               ++increment;
-       }
-
+       if (light > 0)
+               light = rangelim(light + increment, 0, LIGHT_SUN);
        return decode_light(light);
 }
 
@@ -149,7 +140,7 @@ static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
        Calculate non-smooth lighting at interior of node.
        Both light banks.
 */
-u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
+u16 getInteriorLight(MapNode n, s32 increment, const NodeDefManager *ndef)
 {
        u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
        u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
@@ -161,7 +152,7 @@ u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
        Single light bank.
 */
 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
-               v3s16 face_dir, INodeDefManager *ndef)
+       v3s16 face_dir, const NodeDefManager *ndef)
 {
        u8 light;
        u8 l1 = n.getLight(bank, ndef);
@@ -184,7 +175,8 @@ static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
        Calculate non-smooth lighting at face of node.
        Both light banks.
 */
-u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
+u16 getFaceLight(MapNode n, MapNode n2, const v3s16 &face_dir,
+       const NodeDefManager *ndef)
 {
        u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
        u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
@@ -196,60 +188,58 @@ u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
        Both light banks
 */
 static u16 getSmoothLightCombined(const v3s16 &p,
-       const std::array<v3s16,8> &dirs, MeshMakeData *data, bool node_solid)
+       const std::array<v3s16,8> &dirs, MeshMakeData *data)
 {
-       INodeDefManager *ndef = data->m_client->ndef();
+       const NodeDefManager *ndef = data->m_client->ndef();
 
        u16 ambient_occlusion = 0;
        u16 light_count = 0;
        u8 light_source_max = 0;
        u16 light_day = 0;
        u16 light_night = 0;
+       bool direct_sunlight = false;
 
-       auto add_node = [&] (int i) -> const ContentFeatures& {
+       auto add_node = [&] (u8 i, bool obstructed = false) -> bool {
+               if (obstructed) {
+                       ambient_occlusion++;
+                       return false;
+               }
                MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
+               if (n.getContent() == CONTENT_IGNORE)
+                       return true;
                const ContentFeatures &f = ndef->get(n);
                if (f.light_source > light_source_max)
                        light_source_max = f.light_source;
                // Check f.solidness because fast-style leaves look better this way
                if (f.param_type == CPT_LIGHT && f.solidness != 2) {
-                       light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
-                       light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
+                       u8 light_level_day = n.getLightNoChecks(LIGHTBANK_DAY, &f);
+                       u8 light_level_night = n.getLightNoChecks(LIGHTBANK_NIGHT, &f);
+                       if (light_level_day == LIGHT_SUN)
+                               direct_sunlight = true;
+                       light_day += decode_light(light_level_day);
+                       light_night += decode_light(light_level_night);
                        light_count++;
                } else {
                        ambient_occlusion++;
                }
-               return f;
+               return f.light_propagates;
        };
 
-       if (node_solid) {
-               ambient_occlusion = 3;
-               bool corner_obstructed = true;
-               for (int i = 0; i < 2; ++i) {
-                       if (add_node(i).light_propagates)
-                               corner_obstructed = false;
-               }
-               add_node(2);
-               add_node(3);
-               if (corner_obstructed)
-                       ambient_occlusion++;
-               else
-                       add_node(4);
-       } else {
-               std::array<bool, 4> obstructed = {{ 1, 1, 1, 1 }};
-               add_node(0);
-               bool opaque1 = !add_node(1).light_propagates;
-               bool opaque2 = !add_node(2).light_propagates;
-               bool opaque3 = !add_node(3).light_propagates;
-               obstructed[0] = opaque1 && opaque2;
-               obstructed[1] = opaque1 && opaque3;
-               obstructed[2] = opaque2 && opaque3;
-               for (int k = 0; k < 4; ++k) {
-                       if (obstructed[k])
-                               ambient_occlusion++;
-                       else if (add_node(k + 4).light_propagates)
-                               obstructed[3] = false;
-               }
+       std::array<bool, 4> obstructed = {{ 1, 1, 1, 1 }};
+       add_node(0);
+       bool opaque1 = !add_node(1);
+       bool opaque2 = !add_node(2);
+       bool opaque3 = !add_node(3);
+       obstructed[0] = opaque1 && opaque2;
+       obstructed[1] = opaque1 && opaque3;
+       obstructed[2] = opaque2 && opaque3;
+       for (u8 k = 0; k < 3; ++k)
+               if (add_node(k + 4, obstructed[k]))
+                       obstructed[3] = false;
+       if (add_node(7, obstructed[3])) { // wrap light around nodes
+               ambient_occlusion -= 3;
+               for (u8 k = 0; k < 3; ++k)
+                       add_node(k + 4, !obstructed[k]);
        }
 
        if (light_count == 0) {
@@ -259,6 +249,10 @@ static u16 getSmoothLightCombined(const v3s16 &p,
                light_night /= light_count;
        }
 
+       // boost direct sunlight, if any
+       if (direct_sunlight)
+               light_day = 0xFF;
+
        // Boost brightness around light sources
        bool skip_ambient_occlusion_day = false;
        if (decode_light(light_source_max) >= light_day) {
@@ -277,7 +271,7 @@ static u16 getSmoothLightCombined(const v3s16 &p,
                        g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
 
                // Table of gamma space multiply factors.
-               static const float light_amount[3] = {
+               static thread_local const float light_amount[3] = {
                        powf(0.75, 1.0 / ao_gamma),
                        powf(0.5,  1.0 / ao_gamma),
                        powf(0.25, 1.0 / ao_gamma)
@@ -304,43 +298,7 @@ static u16 getSmoothLightCombined(const v3s16 &p,
 */
 u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data)
 {
-       v3s16 neighbor_offset1, neighbor_offset2;
-
-       /*
-        * face_dir, neighbor_offset1 and neighbor_offset2 define an
-        * orthonormal basis which is used to define the offsets of the 8
-        * surrounding nodes and to differentiate the "distance" (by going only
-        * along directly neighboring nodes) relative to the node at p.
-        * Apart from the node at p, only the 4 nodes which contain face_dir
-        * can contribute light.
-        */
-       if (face_dir.X != 0) {
-               neighbor_offset1 = v3s16(0, corner.Y, 0);
-               neighbor_offset2 = v3s16(0, 0, corner.Z);
-       } else if (face_dir.Y != 0) {
-               neighbor_offset1 = v3s16(0, 0, corner.Z);
-               neighbor_offset2 = v3s16(corner.X, 0, 0);
-       } else if (face_dir.Z != 0) {
-               neighbor_offset1 = v3s16(corner.X,0,0);
-               neighbor_offset2 = v3s16(0,corner.Y,0);
-       }
-
-       const std::array<v3s16,8> dirs = {{
-               // Always shine light
-               neighbor_offset1 + face_dir,
-               neighbor_offset2 + face_dir,
-               v3s16(0,0,0),
-               face_dir,
-
-               // Can be obstructed
-               neighbor_offset1 + neighbor_offset2 + face_dir,
-
-               // Do not shine light, only for ambient occlusion
-               neighbor_offset1,
-               neighbor_offset2,
-               neighbor_offset1 + neighbor_offset2
-       }};
-       return getSmoothLightCombined(p, dirs, data, true);
+       return getSmoothLightTransparent(p + face_dir, corner - 2 * face_dir, data);
 }
 
 /*
@@ -363,7 +321,7 @@ u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData
                v3s16(0,corner.Y,corner.Z),
                v3s16(corner.X,corner.Y,corner.Z)
        }};
-       return getSmoothLightCombined(p, dirs, data, false);
+       return getSmoothLightCombined(p, dirs, data);
 }
 
 void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
@@ -417,7 +375,7 @@ void final_color_blend(video::SColor *result,
 /*
        vertex_dirs: v3s16[4]
 */
-static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
+static void getNodeVertexDirs(const v3s16 &dir, v3s16 *vertex_dirs)
 {
        /*
                If looked from outside the node towards the face, the corners are:
@@ -466,9 +424,34 @@ static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
        }
 }
 
+static void getNodeTextureCoords(v3f base, const v3f &scale, const v3s16 &dir, float *u, float *v)
+{
+       if (dir.X > 0 || dir.Y > 0 || dir.Z < 0)
+               base -= scale;
+       if (dir == v3s16(0,0,1)) {
+               *u = -base.X - 1;
+               *v = -base.Y - 1;
+       } else if (dir == v3s16(0,0,-1)) {
+               *u = base.X + 1;
+               *v = -base.Y - 2;
+       } else if (dir == v3s16(1,0,0)) {
+               *u = base.Z + 1;
+               *v = -base.Y - 2;
+       } else if (dir == v3s16(-1,0,0)) {
+               *u = -base.Z - 1;
+               *v = -base.Y - 1;
+       } else if (dir == v3s16(0,1,0)) {
+               *u = base.X + 1;
+               *v = -base.Z - 2;
+       } else if (dir == v3s16(0,-1,0)) {
+               *u = base.X;
+               *v = base.Z;
+       }
+}
+
 struct FastFace
 {
-       TileLayer layer;
+       TileSpec tile;
        video::S3DVertex vertices[4]; // Precalculated vertices
        /*!
         * The face is divided into two triangles. If this is true,
@@ -476,11 +459,10 @@ struct FastFace
         * are connected.
         */
        bool vertex_0_2_connected;
-       u8 layernum;
 };
 
 static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li3,
-       const v3f &p, v3s16 dir, v3f scale, std::vector<FastFace> &dest)
+       const v3f &tp, const v3f &p, const v3s16 &dir, const v3f &scale, std::vector<FastFace> &dest)
 {
        // Position is at the center of the cube.
        v3f pos = p * BS;
@@ -493,6 +475,8 @@ static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li
        v3f vertex_pos[4];
        v3s16 vertex_dirs[4];
        getNodeVertexDirs(dir, vertex_dirs);
+       if (tile.world_aligned)
+               getNodeTextureCoords(tp, scale, dir, &x0, &y0);
 
        v3s16 t;
        u16 t1;
@@ -645,33 +629,25 @@ static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li
                core::vector2d<f32>(x0, y0),
                core::vector2d<f32>(x0 + w * abs_scale, y0) };
 
-       for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
-               const TileLayer *layer = &tile.layers[layernum];
-               if (layer->texture_id == 0)
-                       continue;
-
-               // equivalent to dest.push_back(FastFace()) but faster
-               dest.emplace_back();
-               FastFace& face = *dest.rbegin();
-
-               for (u8 i = 0; i < 4; i++) {
-                       video::SColor c = encode_light(li[i], tile.emissive_light);
-                       if (!tile.emissive_light)
-                               applyFacesShading(c, normal);
+       // equivalent to dest.push_back(FastFace()) but faster
+       dest.emplace_back();
+       FastFace& face = *dest.rbegin();
 
-                       face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
-               }
+       for (u8 i = 0; i < 4; i++) {
+               video::SColor c = encode_light(li[i], tile.emissive_light);
+               if (!tile.emissive_light)
+                       applyFacesShading(c, normal);
 
-               /*
-                Revert triangles for nicer looking gradient if the
-                brightness of vertices 1 and 3 differ less than
-                the brightness of vertices 0 and 2.
-                */
-               face.vertex_0_2_connected = vertex_0_2_connected;
-
-               face.layer = *layer;
-               face.layernum = layernum;
+               face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
        }
+
+       /*
+               Revert triangles for nicer looking gradient if the
+               brightness of vertices 1 and 3 differ less than
+               the brightness of vertices 0 and 2.
+               */
+       face.vertex_0_2_connected = vertex_0_2_connected;
+       face.tile = tile;
 }
 
 /*
@@ -685,7 +661,7 @@ static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li
        TODO: Add 3: Both faces drawn with backface culling, remove equivalent
 */
 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
-               INodeDefManager *ndef)
+       const NodeDefManager *ndef)
 {
        *equivalent = false;
 
@@ -728,9 +704,9 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
 /*
        Gets nth node tile (0 <= n <= 5).
 */
-void getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
+void getNodeTileN(MapNode mn, const v3s16 &p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
 {
-       INodeDefManager *ndef = data->m_client->ndef();
+       const NodeDefManager *ndef = data->m_client->ndef();
        const ContentFeatures &f = ndef->get(mn);
        tile = f.tiles[tileindex];
        bool has_crack = p == data->m_crack_pos_relative;
@@ -748,9 +724,9 @@ void getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data, TileSpe
 /*
        Gets node tile given a face direction.
 */
-void getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data, TileSpec &tile)
+void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *data, TileSpec &tile)
 {
-       INodeDefManager *ndef = data->m_client->ndef();
+       const NodeDefManager *ndef = data->m_client->ndef();
 
        // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
        // (0,0,1), (0,0,-1) or (0,0,0)
@@ -806,7 +782,7 @@ void getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data, TileSpec &t
        };
        u16 tile_index = facedir * 16 + dir_i;
        getNodeTileN(mn, p, dir_to_tile[tile_index], data, tile);
-       tile.rotation = dir_to_tile[tile_index + 1];
+       tile.rotation = tile.world_aligned ? 0 : dir_to_tile[tile_index + 1];
 }
 
 static void getTileInfo(
@@ -823,7 +799,7 @@ static void getTileInfo(
        )
 {
        VoxelManipulator &vmanip = data->m_vmanip;
-       INodeDefManager *ndef = data->m_client->ndef();
+       const NodeDefManager *ndef = data->m_client->ndef();
        v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
 
        const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
@@ -965,7 +941,7 @@ static void updateFastFaceRow(
                                        scale.Z = continuous_tiles_count;
 
                                makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
-                                               sp, face_dir_corrected, scale, dest);
+                                               pf, sp, face_dir_corrected, scale, dest);
 
                                g_profiler->avg("Meshgen: faces drawn by tiling", 0);
                                for (int i = 1; i < continuous_tiles_count; i++)
@@ -1025,6 +1001,20 @@ static void updateAllFastFaceRows(MeshMakeData *data,
                                dest);
 }
 
+static void applyTileColor(PreMeshBuffer &pmb)
+{
+       video::SColor tc = pmb.layer.color;
+       if (tc == video::SColor(0xFFFFFFFF))
+               return;
+       for (video::S3DVertex &vertex : pmb.vertices) {
+               video::SColor *c = &vertex.Color;
+               c->set(c->getAlpha(),
+                       c->getRed() * tc.getRed() / 255,
+                       c->getGreen() * tc.getGreen() / 255,
+                       c->getBlue() * tc.getBlue() / 255);
+       }
+}
+
 /*
        MapBlockMesh
 */
@@ -1074,7 +1064,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
                Convert FastFaces to MeshCollector
        */
 
-       MeshCollector collector(m_use_tangent_vertices);
+       MeshCollector collector;
 
        {
                // avg 0ms (100ms spikes when loading textures the first time)
@@ -1084,15 +1074,9 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
                for (const FastFace &f : fastfaces_new) {
                        static const u16 indices[] = {0, 1, 2, 2, 3, 0};
                        static const u16 indices_alternate[] = {0, 1, 3, 2, 3, 1};
-
-                       if (!f.layer.texture)
-                               continue;
-
                        const u16 *indices_p =
                                f.vertex_0_2_connected ? indices : indices_alternate;
-
-                       collector.append(f.layer, f.vertices, 4, indices_p, 6,
-                               f.layernum);
+                       collector.append(f.tile, f.vertices, 4, indices_p, 6);
                }
        }
 
@@ -1109,8 +1093,6 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
                generator.generate();
        }
 
-       collector.applyTileColors();
-
        /*
                Convert MeshCollector to SMesh
        */
@@ -1120,6 +1102,8 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
                {
                        PreMeshBuffer &p = collector.prebuffers[layer][i];
 
+                       applyTileColor(p);
+
                        // Generate animation data
                        // - Cracks
                        if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
@@ -1128,6 +1112,9 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
                                os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
                                if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
                                        os << "o";  // use ^[cracko
+                               u8 tiles = p.layer.scale;
+                               if (tiles > 1)
+                                       os << ":" << (u32)tiles;
                                os << ":" << (u32)p.layer.animation_frame_count << ":";
                                m_crack_materials.insert(std::make_pair(
                                                std::pair<u8, u32>(layer, i), os.str()));
@@ -1161,16 +1148,10 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
                                // Dummy sunlight to handle non-sunlit areas
                                video::SColorf sunlight;
                                get_sunlight_color(&sunlight, 0);
-                               u32 vertex_count = m_use_tangent_vertices ?
-                                               p.tangent_vertices.size() : p.vertices.size();
+                               u32 vertex_count = p.vertices.size();
                                for (u32 j = 0; j < vertex_count; j++) {
-                                       video::SColor *vc;
-                                       if (m_use_tangent_vertices) {
-                                               vc = &p.tangent_vertices[j].Color;
-                                       } else {
-                                               vc = &p.vertices[j].Color;
-                                       }
-                                       video::SColor copy(*vc);
+                                       video::SColor *vc = &p.vertices[j].Color;
+                                       video::SColor copy = *vc;
                                        if (vc->getAlpha() == 0) // No sunlight - no need to animate
                                                final_color_blend(vc, copy, sunlight); // Finalize color
                                        else // Record color to animate
@@ -1207,24 +1188,23 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
                        if (m_use_tangent_vertices) {
                                scene::SMeshBufferTangents *buf =
                                                new scene::SMeshBufferTangents();
-                               // Set material
                                buf->Material = material;
-                               // Add to mesh
+                               buf->Vertices.reallocate(p.vertices.size());
+                               buf->Indices.reallocate(p.indices.size());
+                               for (const video::S3DVertex &v: p.vertices)
+                                       buf->Vertices.push_back(video::S3DVertexTangents(v.Pos, v.Color, v.TCoords));
+                               for (u16 i: p.indices)
+                                       buf->Indices.push_back(i);
+                               buf->recalculateBoundingBox();
                                mesh->addMeshBuffer(buf);
-                               // Mesh grabbed it
                                buf->drop();
-                               buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
-                                       &p.indices[0], p.indices.size());
                        } else {
                                scene::SMeshBuffer *buf = new scene::SMeshBuffer();
-                               // Set material
                                buf->Material = material;
-                               // Add to mesh
-                               mesh->addMeshBuffer(buf);
-                               // Mesh grabbed it
-                               buf->drop();
                                buf->append(&p.vertices[0], p.vertices.size(),
                                        &p.indices[0], p.indices.size());
+                               mesh->addMeshBuffer(buf);
+                               buf->drop();
                        }
                }
 
@@ -1380,182 +1360,6 @@ void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
        }
 }
 
-/*
-       MeshCollector
-*/
-
-void MeshCollector::append(const TileSpec &tile,
-               const video::S3DVertex *vertices, u32 numVertices,
-               const u16 *indices, u32 numIndices)
-{
-       for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
-               const TileLayer *layer = &tile.layers[layernum];
-               if (layer->texture_id == 0)
-                       continue;
-               append(*layer, vertices, numVertices, indices, numIndices, layernum);
-       }
-}
-
-void MeshCollector::append(const TileLayer &layer,
-               const video::S3DVertex *vertices, u32 numVertices,
-               const u16 *indices, u32 numIndices, u8 layernum)
-{
-       if (numIndices > 65535) {
-               dstream << "FIXME: MeshCollector::append() called with numIndices="
-                               << numIndices << " (limit 65535)" << std::endl;
-               return;
-       }
-       std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
-
-       PreMeshBuffer *p = NULL;
-       for (PreMeshBuffer &pp : *buffers) {
-               if (pp.layer == layer && pp.indices.size() + numIndices <= 65535) {
-                       p = &pp;
-                       break;
-               }
-       }
-
-       if (p == NULL) {
-               PreMeshBuffer pp;
-               pp.layer = layer;
-               buffers->push_back(pp);
-               p = &(*buffers)[buffers->size() - 1];
-       }
-
-       u32 vertex_count;
-       if (m_use_tangent_vertices) {
-               vertex_count = p->tangent_vertices.size();
-               for (u32 i = 0; i < numVertices; i++) {
-
-                       video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
-                                       vertices[i].Color, vertices[i].TCoords);
-                       p->tangent_vertices.push_back(vert);
-               }
-       } else {
-               vertex_count = p->vertices.size();
-               for (u32 i = 0; i < numVertices; i++) {
-                       video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
-                                       vertices[i].Color, vertices[i].TCoords);
-
-                       p->vertices.push_back(vert);
-               }
-       }
-
-       for (u32 i = 0; i < numIndices; i++) {
-               u32 j = indices[i] + vertex_count;
-               p->indices.push_back(j);
-       }
-}
-
-/*
-       MeshCollector - for meshnodes and converted drawtypes.
-*/
-
-void MeshCollector::append(const TileSpec &tile,
-               const video::S3DVertex *vertices, u32 numVertices,
-               const u16 *indices, u32 numIndices,
-               v3f pos, video::SColor c, u8 light_source)
-{
-       for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
-               const TileLayer *layer = &tile.layers[layernum];
-               if (layer->texture_id == 0)
-                       continue;
-               append(*layer, vertices, numVertices, indices, numIndices, pos,
-                               c, light_source, layernum);
-       }
-}
-
-void MeshCollector::append(const TileLayer &layer,
-               const video::S3DVertex *vertices, u32 numVertices,
-               const u16 *indices, u32 numIndices,
-               v3f pos, video::SColor c, u8 light_source, u8 layernum)
-{
-       if (numIndices > 65535) {
-               dstream << "FIXME: MeshCollector::append() called with numIndices="
-                               << numIndices << " (limit 65535)" << std::endl;
-               return;
-       }
-       std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
-
-       PreMeshBuffer *p = NULL;
-       for (PreMeshBuffer &pp : *buffers) {
-               if (pp.layer == layer && pp.indices.size() + numIndices <= 65535) {
-                       p = &pp;
-                       break;
-               }
-       }
-
-       if (p == NULL) {
-               PreMeshBuffer pp;
-               pp.layer = layer;
-               buffers->push_back(pp);
-               p = &(*buffers)[buffers->size() - 1];
-       }
-
-       video::SColor original_c = c;
-       u32 vertex_count;
-       if (m_use_tangent_vertices) {
-               vertex_count = p->tangent_vertices.size();
-               for (u32 i = 0; i < numVertices; i++) {
-                       if (!light_source) {
-                               c = original_c;
-                               applyFacesShading(c, vertices[i].Normal);
-                       }
-                       video::S3DVertexTangents vert(vertices[i].Pos + pos,
-                                       vertices[i].Normal, c, vertices[i].TCoords);
-                       p->tangent_vertices.push_back(vert);
-               }
-       } else {
-               vertex_count = p->vertices.size();
-               for (u32 i = 0; i < numVertices; i++) {
-                       if (!light_source) {
-                               c = original_c;
-                               applyFacesShading(c, vertices[i].Normal);
-                       }
-                       video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
-                               vertices[i].TCoords);
-                       p->vertices.push_back(vert);
-               }
-       }
-
-       for (u32 i = 0; i < numIndices; i++) {
-               u32 j = indices[i] + vertex_count;
-               p->indices.push_back(j);
-       }
-}
-
-void MeshCollector::applyTileColors()
-{
-       if (m_use_tangent_vertices)
-               for (auto &prebuffer : prebuffers) {
-                       for (PreMeshBuffer &pmb : prebuffer) {
-                               video::SColor tc = pmb.layer.color;
-                               if (tc == video::SColor(0xFFFFFFFF))
-                                       continue;
-                               for (video::S3DVertexTangents &tangent_vertex : pmb.tangent_vertices) {
-                                       video::SColor *c = &tangent_vertex.Color;
-                                       c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
-                                               c->getGreen() * tc.getGreen() / 255,
-                                               c->getBlue() * tc.getBlue() / 255);
-                               }
-                       }
-               }
-       else
-               for (auto &prebuffer : prebuffers) {
-                       for (PreMeshBuffer &pmb : prebuffer) {
-                               video::SColor tc = pmb.layer.color;
-                               if (tc == video::SColor(0xFFFFFFFF))
-                                       continue;
-                               for (video::S3DVertex &vertex : pmb.vertices) {
-                                       video::SColor *c = &vertex.Color;
-                                       c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
-                                               c->getGreen() * tc.getGreen() / 255,
-                                               c->getBlue() * tc.getBlue() / 255);
-                               }
-                       }
-               }
-}
-
 video::SColor encode_light(u16 light, u8 emissive_light)
 {
        // Get components