]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/client/clientmap.cpp
Remove unused ITextSceneNode header (#11476)
[dragonfireclient.git] / src / client / clientmap.cpp
index b9e0cc2ce4320e852790a6c0b27b7d1795762886..8b09eade1400c6ce5eafc1bbbfe7422976392231 100644 (file)
@@ -64,15 +64,23 @@ void MeshBufListList::add(scene::IMeshBuffer *buf, v3s16 position, u8 layer)
 
 ClientMap::ClientMap(
                Client *client,
+               RenderingEngine *rendering_engine,
                MapDrawControl &control,
                s32 id
 ):
        Map(client),
-       scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
-               RenderingEngine::get_scene_manager(), id),
+       scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(),
+               rendering_engine->get_scene_manager(), id),
        m_client(client),
+       m_rendering_engine(rendering_engine),
        m_control(control)
 {
+
+       /*
+        * @Liso: Sadly C++ doesn't have introspection, so the only way we have to know
+        * the class is whith a name ;) Name property cames from ISceneNode base class.
+        */
+       Name = "ClientMap";
        m_box = aabb3f(-BS*1000000,-BS*1000000,-BS*1000000,
                        BS*1000000,BS*1000000,BS*1000000);
 
@@ -114,12 +122,21 @@ void ClientMap::OnRegisterSceneNode()
        }
 
        ISceneNode::OnRegisterSceneNode();
+
+       if (!m_added_to_shadow_renderer) {
+               m_added_to_shadow_renderer = true;
+               if (auto shadows = m_rendering_engine->get_shadow_renderer())
+                       shadows->addNodeToShadowList(this);
+       }
 }
 
 void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
-               v3s16 *p_blocks_min, v3s16 *p_blocks_max)
+               v3s16 *p_blocks_min, v3s16 *p_blocks_max, float range)
 {
-       v3s16 box_nodes_d = m_control.wanted_range * v3s16(1, 1, 1);
+       if (range <= 0.0f)
+               range = m_control.wanted_range;
+
+       v3s16 box_nodes_d = range * v3s16(1, 1, 1);
        // Define p_nodes_min/max as v3s32 because 'cam_pos_nodes -/+ box_nodes_d'
        // can exceed the range of v3s16 when a large view range is used near the
        // world edges.
@@ -165,6 +182,9 @@ void ClientMap::updateDrawList()
        v3s16 p_blocks_max;
        getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
 
+       // Read the vision range, unless unlimited range is enabled.
+       float range = m_control.range_all ? 1e7 : m_control.wanted_range;
+
        // Number of blocks currently loaded by the client
        u32 blocks_loaded = 0;
        // Number of blocks with mesh in rendering range
@@ -182,6 +202,7 @@ void ClientMap::updateDrawList()
                        occlusion_culling_enabled = false;
        }
 
+
        // Uncomment to debug occluded blocks in the wireframe mode
        // TODO: Include this as a flag for an extended debugging setting
        //if (occlusion_culling_enabled && m_control.show_wireframe)
@@ -218,32 +239,34 @@ void ClientMap::updateDrawList()
                                continue;
                        }
 
-                       float range = 100000 * BS;
-                       if (!m_control.range_all)
-                               range = m_control.wanted_range * BS;
+                       v3s16 block_coord = block->getPos();
+                       v3s16 block_position = block->getPosRelative() + MAP_BLOCKSIZE / 2;
 
-                       float d = 0.0;
-                       if (!isBlockInSight(block->getPos(), camera_position,
-                                       camera_direction, camera_fov, range, &d))
-                               continue;
+                       // First, perform a simple distance check, with a padding of one extra block.
+                       if (!m_control.range_all &&
+                                       block_position.getDistanceFrom(cam_pos_nodes) > range + MAP_BLOCKSIZE)
+                               continue; // Out of range, skip.
 
+                       // Keep the block alive as long as it is in range.
+                       block->resetUsageTimer();
                        blocks_in_range_with_mesh++;
 
-                       /*
-                               Occlusion culling
-                       */
+                       // Frustum culling
+                       float d = 0.0;
+                       if (!isBlockInSight(block_coord, camera_position,
+                                       camera_direction, camera_fov, range * BS, &d))
+                               continue;
+
+                       // Occlusion culling
                        if ((!m_control.range_all && d > m_control.wanted_range * BS) ||
                                        (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes))) {
                                blocks_occlusion_culled++;
                                continue;
                        }
 
-                       // This block is in range. Reset usage timer.
-                       block->resetUsageTimer();
-
                        // Add to set
                        block->refGrab();
-                       m_drawlist[block->getPos()] = block;
+                       m_drawlist[block_coord] = block;
 
                        sector_blocks_drawn++;
                } // foreach sectorblocks
@@ -282,8 +305,6 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
        const u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
 
        const v3f camera_position = m_camera_position;
-       const v3f camera_direction = m_camera_direction;
-       const f32 camera_fov = m_camera_fov;
 
        /*
                Get all blocks and draw all visible ones
@@ -310,14 +331,12 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                if (!block->mesh)
                        continue;
 
-               float d = 0.0;
-               if (!isBlockInSight(block->getPos(), camera_position,
-                               camera_direction, camera_fov, 100000 * BS, &d))
-                       continue;
+               v3f block_pos_r = intToFloat(block->getPosRelative() + MAP_BLOCKSIZE / 2, BS);
+               float d = camera_position.getDistanceFrom(block_pos_r);
+               d = MYMAX(0,d - BLOCK_MAX_RADIUS);
 
                // Mesh animation
                if (pass == scene::ESNRP_SOLID) {
-                       //MutexAutoLock lock(block->mesh_mutex);
                        MapBlockMesh *mapBlockMesh = block->mesh;
                        assert(mapBlockMesh);
                        // Pretty random but this should work somewhat nicely
@@ -338,8 +357,6 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                        Get the meshbuffers of the block
                */
                {
-                       //MutexAutoLock lock(block->mesh_mutex);
-
                        MapBlockMesh *mapBlockMesh = block->mesh;
                        assert(mapBlockMesh);
 
@@ -390,6 +407,17 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                                                "returning." << std::endl;
                                return;
                        }
+
+                       // pass the shadow map texture to the buffer texture
+                       ShadowRenderer *shadow = m_rendering_engine->get_shadow_renderer();
+                       if (shadow && shadow->is_active()) {
+                               auto &layer = list.m.TextureLayer[3];
+                               layer.Texture = shadow->get_texture();
+                               layer.TextureWrapU = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE;
+                               layer.TextureWrapV = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE;
+                               layer.TrilinearFilter = true;
+                       }
+
                        driver->setMaterial(list.m);
 
                        drawcall_count += list.bufs.size();
@@ -496,12 +524,12 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
        static v3f z_directions[50] = {
                v3f(-100, 0, 0)
        };
-       static f32 z_offsets[sizeof(z_directions)/sizeof(*z_directions)] = {
+       static f32 z_offsets[50] = {
                -1000,
        };
 
-       if(z_directions[0].X < -99){
-               for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){
+       if (z_directions[0].X < -99) {
+               for (u32 i = 0; i < ARRLEN(z_directions); i++) {
                        // Assumes FOV of 72 and 16/9 aspect ratio
                        z_directions[i] = v3f(
                                0.02 * myrand_range(-100, 100),
@@ -517,7 +545,8 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
        if(sunlight_min_d > 35*BS)
                sunlight_min_d = 35*BS;
        std::vector<int> values;
-       for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){
+       values.reserve(ARRLEN(z_directions));
+       for (u32 i = 0; i < ARRLEN(z_directions); i++) {
                v3f z_dir = z_directions[i];
                core::CMatrix4<f32> a;
                a.buildRotateFromTo(v3f(0,1,0), z_dir);
@@ -605,3 +634,187 @@ void ClientMap::PrintInfo(std::ostream &out)
 {
        out<<"ClientMap: ";
 }
+
+void ClientMap::renderMapShadows(video::IVideoDriver *driver,
+               const video::SMaterial &material, s32 pass)
+{
+       bool is_transparent_pass = pass != scene::ESNRP_SOLID;
+       std::string prefix;
+       if (is_transparent_pass)
+               prefix = "renderMap(SHADOW TRANS): ";
+       else
+               prefix = "renderMap(SHADOW SOLID): ";
+
+       u32 drawcall_count = 0;
+       u32 vertex_count = 0;
+
+       MeshBufListList drawbufs;
+
+       for (auto &i : m_drawlist_shadow) {
+               v3s16 block_pos = i.first;
+               MapBlock *block = i.second;
+
+               // If the mesh of the block happened to get deleted, ignore it
+               if (!block->mesh)
+                       continue;
+
+               /*
+                       Get the meshbuffers of the block
+               */
+               {
+                       MapBlockMesh *mapBlockMesh = block->mesh;
+                       assert(mapBlockMesh);
+
+                       for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
+                               scene::IMesh *mesh = mapBlockMesh->getMesh(layer);
+                               assert(mesh);
+
+                               u32 c = mesh->getMeshBufferCount();
+                               for (u32 i = 0; i < c; i++) {
+                                       scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
+
+                                       video::SMaterial &mat = buf->getMaterial();
+                                       auto rnd = driver->getMaterialRenderer(mat.MaterialType);
+                                       bool transparent = rnd && rnd->isTransparent();
+                                       if (transparent == is_transparent_pass)
+                                               drawbufs.add(buf, block_pos, layer);
+                               }
+                       }
+               }
+       }
+
+       TimeTaker draw("Drawing shadow mesh buffers");
+
+       core::matrix4 m; // Model matrix
+       v3f offset = intToFloat(m_camera_offset, BS);
+
+       // Render all layers in order
+       for (auto &lists : drawbufs.lists) {
+               for (MeshBufList &list : lists) {
+                       // Check and abort if the machine is swapping a lot
+                       if (draw.getTimerTime() > 1000) {
+                               infostream << "ClientMap::renderMapShadows(): Rendering "
+                                               "took >1s, returning." << std::endl;
+                               break;
+                       }
+                       for (auto &pair : list.bufs) {
+                               scene::IMeshBuffer *buf = pair.second;
+
+                               // override some material properties
+                               video::SMaterial local_material = buf->getMaterial();
+                               local_material.MaterialType = material.MaterialType;
+                               local_material.BackfaceCulling = material.BackfaceCulling;
+                               local_material.FrontfaceCulling = material.FrontfaceCulling;
+                               local_material.Lighting = false;
+                               driver->setMaterial(local_material);
+
+                               v3f block_wpos = intToFloat(pair.first * MAP_BLOCKSIZE, BS);
+                               m.setTranslation(block_wpos - offset);
+
+                               driver->setTransform(video::ETS_WORLD, m);
+                               driver->drawMeshBuffer(buf);
+                               vertex_count += buf->getVertexCount();
+                       }
+
+                       drawcall_count += list.bufs.size();
+               }
+       }
+
+       g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
+       g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
+       g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
+}
+
+/*
+       Custom update draw list for the pov of shadow light.
+*/
+void ClientMap::updateDrawListShadow(const v3f &shadow_light_pos, const v3f &shadow_light_dir, float shadow_range)
+{
+       ScopeProfiler sp(g_profiler, "CM::updateDrawListShadow()", SPT_AVG);
+
+       const v3f camera_position = shadow_light_pos;
+       const v3f camera_direction = shadow_light_dir;
+       // I "fake" fov just to avoid creating a new function to handle orthographic
+       // projection.
+       const f32 camera_fov = m_camera_fov * 1.9f;
+
+       v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
+       v3s16 p_blocks_min;
+       v3s16 p_blocks_max;
+       getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max, shadow_range);
+
+       std::vector<v2s16> blocks_in_range;
+
+       for (auto &i : m_drawlist_shadow) {
+               MapBlock *block = i.second;
+               block->refDrop();
+       }
+       m_drawlist_shadow.clear();
+
+       // We need to append the blocks from the camera POV because sometimes
+       // they are not inside the light frustum and it creates glitches.
+       // FIXME: This could be removed if we figure out why they are missing
+       // from the light frustum.
+       for (auto &i : m_drawlist) {
+               i.second->refGrab();
+               m_drawlist_shadow[i.first] = i.second;
+       }
+
+       // Number of blocks currently loaded by the client
+       u32 blocks_loaded = 0;
+       // Number of blocks with mesh in rendering range
+       u32 blocks_in_range_with_mesh = 0;
+       // Number of blocks occlusion culled
+       u32 blocks_occlusion_culled = 0;
+
+       for (auto &sector_it : m_sectors) {
+               MapSector *sector = sector_it.second;
+               if (!sector)
+                       continue;
+               blocks_loaded += sector->size();
+
+               MapBlockVect sectorblocks;
+               sector->getBlocks(sectorblocks);
+
+               /*
+                       Loop through blocks in sector
+               */
+               for (MapBlock *block : sectorblocks) {
+                       if (!block->mesh) {
+                               // Ignore if mesh doesn't exist
+                               continue;
+                       }
+
+                       float range = shadow_range;
+
+                       float d = 0.0;
+                       if (!isBlockInSight(block->getPos(), camera_position,
+                                           camera_direction, camera_fov, range, &d))
+                               continue;
+
+                       blocks_in_range_with_mesh++;
+
+                       /*
+                               Occlusion culling
+                       */
+                       if (isBlockOccluded(block, cam_pos_nodes)) {
+                               blocks_occlusion_culled++;
+                               continue;
+                       }
+
+                       // This block is in range. Reset usage timer.
+                       block->resetUsageTimer();
+
+                       // Add to set
+                       if (m_drawlist_shadow.find(block->getPos()) == m_drawlist_shadow.end()) {
+                               block->refGrab();
+                               m_drawlist_shadow[block->getPos()] = block;
+                       }
+               }
+       }
+
+       g_profiler->avg("SHADOW MapBlock meshes in range [#]", blocks_in_range_with_mesh);
+       g_profiler->avg("SHADOW MapBlocks occlusion culled [#]", blocks_occlusion_culled);
+       g_profiler->avg("SHADOW MapBlocks drawn [#]", m_drawlist_shadow.size());
+       g_profiler->avg("SHADOW MapBlocks loaded [#]", blocks_loaded);
+}