+#include "client/tile.h"
+#include "mesh.h"
+#include <IMeshManipulator.h>
+#include "client.h"
+#include "log.h"
+#include "noise.h"
+
+// Distance of light extrapolation (for oversized nodes)
+// After this distance, it gives up and considers light level constant
+#define SMOOTH_LIGHTING_OVERSIZE 1.0
+
+struct LightFrame
+{
+ f32 lightsA[8];
+ f32 lightsB[8];
+ u8 light_source;
+};
+
+static const v3s16 light_dirs[8] = {
+ v3s16(-1, -1, -1),
+ v3s16(-1, -1, 1),
+ v3s16(-1, 1, -1),
+ v3s16(-1, 1, 1),
+ v3s16( 1, -1, -1),
+ v3s16( 1, -1, 1),
+ v3s16( 1, 1, -1),
+ v3s16( 1, 1, 1),
+};
+
+// Create a cuboid.
+// collector - the MeshCollector for the resulting polygons
+// box - the position and size of the box
+// tiles - the tiles (materials) to use (for all 6 faces)
+// tilecount - number of entries in tiles, 1<=tilecount<=6
+// c - colors of the cuboid's six sides
+// txc - texture coordinates - this is a list of texture coordinates
+// for the opposite corners of each face - therefore, there
+// should be (2+2)*6=24 values in the list. Alternatively,
+// pass NULL to use the entire texture for each face. The
+// order of the faces in the list is up-down-right-left-back-
+// front (compatible with ContentFeatures). If you specified
+// 0,0,1,1 for each face, that would be the same as
+// passing NULL.
+// light source - if greater than zero, the box's faces will not be shaded
+void makeCuboid(MeshCollector *collector, const aabb3f &box,
+ TileSpec *tiles, int tilecount, const video::SColor *c,
+ const f32* txc, const u8 light_source)
+{
+ assert(tilecount >= 1 && tilecount <= 6); // pre-condition
+
+ v3f min = box.MinEdge;
+ v3f max = box.MaxEdge;
+
+ if(txc == NULL) {
+ static const f32 txc_default[24] = {
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1,
+ 0,0,1,1
+ };
+ txc = txc_default;
+ }
+
+ video::SColor c1 = c[0];
+ video::SColor c2 = c[1];
+ video::SColor c3 = c[2];
+ video::SColor c4 = c[3];
+ video::SColor c5 = c[4];
+ video::SColor c6 = c[5];
+ if (!light_source) {
+ applyFacesShading(c1, v3f(0, 1, 0));
+ applyFacesShading(c2, v3f(0, -1, 0));
+ applyFacesShading(c3, v3f(1, 0, 0));
+ applyFacesShading(c4, v3f(-1, 0, 0));
+ applyFacesShading(c5, v3f(0, 0, 1));
+ applyFacesShading(c6, v3f(0, 0, -1));
+ }
+
+ video::S3DVertex vertices[24] =
+ {
+ // up
+ video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c1, txc[0],txc[1]),
+ video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c1, txc[2],txc[1]),
+ video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c1, txc[2],txc[3]),
+ video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c1, txc[0],txc[3]),
+ // down
+ video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c2, txc[4],txc[5]),
+ video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c2, txc[6],txc[5]),
+ video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c2, txc[6],txc[7]),
+ video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c2, txc[4],txc[7]),
+ // right
+ video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c3, txc[ 8],txc[9]),
+ video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c3, txc[10],txc[9]),
+ video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c3, txc[10],txc[11]),
+ video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c3, txc[ 8],txc[11]),
+ // left
+ video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c4, txc[12],txc[13]),
+ video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c4, txc[14],txc[13]),
+ video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c4, txc[14],txc[15]),
+ video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c4, txc[12],txc[15]),
+ // back
+ video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c5, txc[16],txc[17]),
+ video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c5, txc[18],txc[17]),
+ video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c5, txc[18],txc[19]),
+ video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c5, txc[16],txc[19]),
+ // front
+ video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c6, txc[20],txc[21]),
+ video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c6, txc[22],txc[21]),
+ video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c6, txc[22],txc[23]),
+ video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c6, txc[20],txc[23]),
+ };
+
+ for(int i = 0; i < 6; i++)
+ {
+ switch (tiles[MYMIN(i, tilecount-1)].rotation)
+ {
+ case 0:
+ break;
+ case 1: //R90
+ for (int x = 0; x < 4; x++)
+ vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
+ break;
+ case 2: //R180
+ for (int x = 0; x < 4; x++)
+ vertices[i*4+x].TCoords.rotateBy(180,irr::core::vector2df(0, 0));
+ break;
+ case 3: //R270
+ for (int x = 0; x < 4; x++)
+ vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
+ break;
+ case 4: //FXR90
+ for (int x = 0; x < 4; x++){
+ vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
+ vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
+ }
+ break;
+ case 5: //FXR270
+ for (int x = 0; x < 4; x++){
+ vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
+ vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
+ }
+ break;
+ case 6: //FYR90
+ for (int x = 0; x < 4; x++){
+ vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
+ vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
+ }
+ break;
+ case 7: //FYR270
+ for (int x = 0; x < 4; x++){
+ vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
+ vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
+ }
+ break;
+ case 8: //FX
+ for (int x = 0; x < 4; x++){
+ vertices[i*4+x].TCoords.X = 1.0 - vertices[i*4+x].TCoords.X;
+ }
+ break;
+ case 9: //FY
+ for (int x = 0; x < 4; x++){
+ vertices[i*4+x].TCoords.Y = 1.0 - vertices[i*4+x].TCoords.Y;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ u16 indices[] = {0,1,2,2,3,0};
+ // Add to mesh collector
+ for (s32 j = 0; j < 24; j += 4) {
+ int tileindex = MYMIN(j / 4, tilecount - 1);
+ collector->append(tiles[tileindex], vertices + j, 4, indices, 6);
+ }
+}