+#ifndef SERVER
+void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileLayer *tile,
+ TileDef *tiledef, u32 shader_id, bool use_normal_texture,
+ bool backface_culling, u8 material_type)
+{
+ tile->shader_id = shader_id;
+ tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
+ tile->material_type = material_type;
+
+ // Normal texture and shader flags texture
+ if (use_normal_texture) {
+ tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
+ }
+ tile->flags_texture = tsrc->getShaderFlagsTexture(tile->normal_texture ? true : false);
+
+ // Material flags
+ tile->material_flags = 0;
+ if (backface_culling)
+ tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
+ if (tiledef->animation.type != TAT_NONE)
+ tile->material_flags |= MATERIAL_FLAG_ANIMATION;
+ if (tiledef->tileable_horizontal)
+ tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
+ if (tiledef->tileable_vertical)
+ tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
+
+ // Color
+ tile->has_color = tiledef->has_color;
+ if (tiledef->has_color)
+ tile->color = tiledef->color;
+ else
+ tile->color = color;
+
+ // Animation parameters
+ int frame_count = 1;
+ if (tile->material_flags & MATERIAL_FLAG_ANIMATION) {
+ int frame_length_ms;
+ tiledef->animation.determineParams(tile->texture->getOriginalSize(),
+ &frame_count, &frame_length_ms, NULL);
+ tile->animation_frame_count = frame_count;
+ tile->animation_frame_length_ms = frame_length_ms;
+ }
+
+ if (frame_count == 1) {
+ tile->material_flags &= ~MATERIAL_FLAG_ANIMATION;
+ } else {
+ std::ostringstream os(std::ios::binary);
+ if (!tile->frames) {
+ tile->frames = std::make_shared<std::vector<FrameSpec>>();
+ }
+ tile->frames->resize(frame_count);
+
+ for (int i = 0; i < frame_count; i++) {
+
+ FrameSpec frame;
+
+ os.str("");
+ os << tiledef->name;
+ tiledef->animation.getTextureModifer(os,
+ tile->texture->getOriginalSize(), i);
+
+ frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
+ if (tile->normal_texture)
+ frame.normal_texture = tsrc->getNormalTexture(os.str());
+ frame.flags_texture = tile->flags_texture;
+ (*tile->frames)[i] = frame;
+ }
+ }
+}
+#endif
+
+#ifndef SERVER
+void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
+ scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings)
+{
+ // minimap pixel color - the average color of a texture
+ if (tsettings.enable_minimap && tiledef[0].name != "")
+ minimap_color = tsrc->getTextureAverageColor(tiledef[0].name);
+
+ // Figure out the actual tiles to use
+ TileDef tdef[6];
+ for (u32 j = 0; j < 6; j++) {
+ tdef[j] = tiledef[j];
+ if (tdef[j].name == "")
+ tdef[j].name = "unknown_node.png";
+ }
+ // also the overlay tiles
+ TileDef tdef_overlay[6];
+ for (u32 j = 0; j < 6; j++)
+ tdef_overlay[j] = tiledef_overlay[j];
+ // also the special tiles
+ TileDef tdef_spec[6];
+ for (u32 j = 0; j < CF_SPECIAL_COUNT; j++)
+ tdef_spec[j] = tiledef_special[j];
+
+ bool is_liquid = false;
+
+ u8 material_type = (alpha == 255) ?
+ TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
+
+ switch (drawtype) {
+ default:
+ case NDT_NORMAL:
+ material_type = (alpha == 255) ?
+ TILE_MATERIAL_OPAQUE : TILE_MATERIAL_ALPHA;
+ solidness = 2;
+ break;
+ case NDT_AIRLIKE:
+ solidness = 0;
+ break;
+ case NDT_LIQUID:
+ assert(liquid_type == LIQUID_SOURCE);
+ if (tsettings.opaque_water)
+ alpha = 255;
+ solidness = 1;
+ is_liquid = true;
+ break;
+ case NDT_FLOWINGLIQUID:
+ assert(liquid_type == LIQUID_FLOWING);
+ solidness = 0;
+ if (tsettings.opaque_water)
+ alpha = 255;
+ is_liquid = true;
+ break;
+ case NDT_GLASSLIKE:
+ solidness = 0;
+ visual_solidness = 1;
+ break;
+ case NDT_GLASSLIKE_FRAMED:
+ solidness = 0;
+ visual_solidness = 1;
+ break;
+ case NDT_GLASSLIKE_FRAMED_OPTIONAL:
+ solidness = 0;
+ visual_solidness = 1;
+ drawtype = tsettings.connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
+ break;
+ case NDT_ALLFACES:
+ solidness = 0;
+ visual_solidness = 1;
+ break;
+ case NDT_ALLFACES_OPTIONAL:
+ if (tsettings.leaves_style == LEAVES_FANCY) {
+ drawtype = NDT_ALLFACES;
+ solidness = 0;
+ visual_solidness = 1;
+ } else if (tsettings.leaves_style == LEAVES_SIMPLE) {
+ for (u32 j = 0; j < 6; j++) {
+ if (tdef_spec[j].name != "")
+ tdef[j].name = tdef_spec[j].name;
+ }
+ drawtype = NDT_GLASSLIKE;
+ solidness = 0;
+ visual_solidness = 1;
+ } else {
+ drawtype = NDT_NORMAL;
+ solidness = 2;
+ for (u32 i = 0; i < 6; i++)
+ tdef[i].name += std::string("^[noalpha");
+ }
+ if (waving >= 1)
+ material_type = TILE_MATERIAL_WAVING_LEAVES;
+ break;
+ case NDT_PLANTLIKE:
+ solidness = 0;
+ if (waving >= 1)
+ material_type = TILE_MATERIAL_WAVING_PLANTS;
+ break;
+ case NDT_FIRELIKE:
+ solidness = 0;
+ break;
+ case NDT_MESH:
+ case NDT_NODEBOX:
+ solidness = 0;
+ if (waving == 1)
+ material_type = TILE_MATERIAL_WAVING_PLANTS;
+ else if (waving == 2)
+ material_type = TILE_MATERIAL_WAVING_LEAVES;
+ break;
+ case NDT_TORCHLIKE:
+ case NDT_SIGNLIKE:
+ case NDT_FENCELIKE:
+ case NDT_RAILLIKE:
+ solidness = 0;
+ break;
+ case NDT_PLANTLIKE_ROOTED:
+ solidness = 2;
+ break;
+ }
+
+ if (is_liquid) {
+ // Vertex alpha is no longer supported, correct if necessary.
+ correctAlpha(tdef, 6);
+ correctAlpha(tdef_overlay, 6);
+ correctAlpha(tdef_spec, CF_SPECIAL_COUNT);
+ material_type = (alpha == 255) ?
+ TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
+ }
+
+ u32 tile_shader = shdsrc->getShader("nodes_shader", material_type, drawtype);
+
+ u8 overlay_material = material_type;
+ if (overlay_material == TILE_MATERIAL_OPAQUE)
+ overlay_material = TILE_MATERIAL_BASIC;
+ else if (overlay_material == TILE_MATERIAL_LIQUID_OPAQUE)
+ overlay_material = TILE_MATERIAL_LIQUID_TRANSPARENT;
+
+ u32 overlay_shader = shdsrc->getShader("nodes_shader", overlay_material, drawtype);
+
+ // Tiles (fill in f->tiles[])
+ for (u16 j = 0; j < 6; j++) {
+ fillTileAttribs(tsrc, &tiles[j].layers[0], &tdef[j], tile_shader,
+ tsettings.use_normal_texture,
+ tdef[j].backface_culling, material_type);
+ if (tdef_overlay[j].name != "")
+ fillTileAttribs(tsrc, &tiles[j].layers[1], &tdef_overlay[j],
+ overlay_shader, tsettings.use_normal_texture,
+ tdef[j].backface_culling, overlay_material);
+ }
+
+ u8 special_material = material_type;
+ if (drawtype == NDT_PLANTLIKE_ROOTED) {
+ if (waving == 1)
+ special_material = TILE_MATERIAL_WAVING_PLANTS;
+ else if (waving == 2)
+ special_material = TILE_MATERIAL_WAVING_LEAVES;
+ }
+ u32 special_shader = shdsrc->getShader("nodes_shader", special_material, drawtype);
+
+ // Special tiles (fill in f->special_tiles[])
+ for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
+ fillTileAttribs(tsrc, &special_tiles[j].layers[0], &tdef_spec[j],
+ special_shader, tsettings.use_normal_texture,
+ tdef_spec[j].backface_culling, special_material);
+ }
+
+ if (param_type_2 == CPT2_COLOR ||
+ param_type_2 == CPT2_COLORED_FACEDIR ||
+ param_type_2 == CPT2_COLORED_WALLMOUNTED)
+ palette = tsrc->getPalette(palette_name);
+
+ if ((drawtype == NDT_MESH) && (mesh != "")) {
+ // Meshnode drawtype
+ // Read the mesh and apply scale
+ mesh_ptr[0] = client->getMesh(mesh);
+ if (mesh_ptr[0]){
+ v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale;
+ scaleMesh(mesh_ptr[0], scale);
+ recalculateBoundingBox(mesh_ptr[0]);
+ meshmanip->recalculateNormals(mesh_ptr[0], true, false);
+ }
+ } else if ((drawtype == NDT_NODEBOX) &&
+ ((node_box.type == NODEBOX_REGULAR) ||
+ (node_box.type == NODEBOX_FIXED)) &&
+ (!node_box.fixed.empty())) {
+ //Convert regular nodebox nodes to meshnodes
+ //Change the drawtype and apply scale
+ drawtype = NDT_MESH;
+ mesh_ptr[0] = convertNodeboxesToMesh(node_box.fixed);
+ v3f scale = v3f(1.0, 1.0, 1.0) * visual_scale;
+ scaleMesh(mesh_ptr[0], scale);
+ recalculateBoundingBox(mesh_ptr[0]);
+ meshmanip->recalculateNormals(mesh_ptr[0], true, false);
+ }
+
+ //Cache 6dfacedir and wallmounted rotated clones of meshes
+ if (tsettings.enable_mesh_cache && mesh_ptr[0] &&
+ (param_type_2 == CPT2_FACEDIR
+ || param_type_2 == CPT2_COLORED_FACEDIR)) {
+ for (u16 j = 1; j < 24; j++) {
+ mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
+ rotateMeshBy6dFacedir(mesh_ptr[j], j);
+ recalculateBoundingBox(mesh_ptr[j]);
+ meshmanip->recalculateNormals(mesh_ptr[j], true, false);
+ }
+ } else if (tsettings.enable_mesh_cache && mesh_ptr[0]
+ && (param_type_2 == CPT2_WALLMOUNTED ||
+ param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
+ static const u8 wm_to_6d[6] = { 20, 0, 16 + 1, 12 + 3, 8, 4 + 2 };
+ for (u16 j = 1; j < 6; j++) {
+ mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
+ rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]);
+ recalculateBoundingBox(mesh_ptr[j]);
+ meshmanip->recalculateNormals(mesh_ptr[j], true, false);
+ }
+ rotateMeshBy6dFacedir(mesh_ptr[0], wm_to_6d[0]);
+ recalculateBoundingBox(mesh_ptr[0]);
+ meshmanip->recalculateNormals(mesh_ptr[0], true, false);
+ }
+}
+#endif
+