Ejemplo n.º 1
0
void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
{
    DSTACK(__FUNCTION_NAME);

    bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;

    std::string prefix;
    if(pass == scene::ESNRP_SOLID)
        prefix = "CM: solid: ";
    else
        prefix = "CM: transparent: ";

    //ScopeProfiler sp(g_profiler, "CM::renderMap() " + prefix, SPT_AVG);

    /*
    	Get time for measuring timeout.

    	Measuring time is very useful for long delays when the
    	machine is swapping a lot.
    */
    //int time1 = time(0);

    /*
    	Get animation parameters
    */
    float animation_time = m_client->getAnimationTime();
    int crack = m_client->getCrackLevel();
    u32 daynight_ratio = m_client->getEnv().getDayNightRatio();

    m_camera_mutex.Lock();
    v3f camera_position = m_camera_position;
    f32 camera_fov = m_camera_fov * 1.1;
    m_camera_mutex.Unlock();

    /*
    	Get all blocks and draw all visible ones
    */

    v3s16 cam_pos_nodes = floatToInt(camera_position, BS);

    u32 vertex_count = 0;
    u32 meshbuffer_count = 0;

    // For limiting number of mesh animations per frame
    u32 mesh_animate_count = 0;
    u32 mesh_animate_count_far = 0;

    // Blocks that were drawn and had a mesh
    u32 blocks_drawn = 0;
    // Blocks which had a corresponding meshbuffer for this pass
    u32 blocks_had_pass_meshbuf = 0;
    // Blocks from which stuff was actually drawn
    u32 blocks_without_stuff = 0;

    /*
    	Draw the selected MapBlocks
    */

    {
        //ScopeProfiler sp(g_profiler, prefix+"drawing blocks", SPT_AVG);

        MeshBufListList drawbufs;
        std::vector<MapBlock::mesh_type> used_meshes; //keep shared_ptr
        auto drawlist = m_drawlist.load();
        auto lock = drawlist->lock_shared_rec();
        used_meshes.reserve(drawlist->size());
        //g_profiler->add("CM::renderMap()cnt"+ prefix, drawlist->size());
        for(auto & ir : *drawlist) {
            auto block = ir.second;

            int mesh_step = getFarmeshStep(m_control, getNodeBlockPos(cam_pos_nodes), block->getPos());
            // If the mesh of the block happened to get deleted, ignore it
            auto mapBlockMesh = block->getMesh(mesh_step);
            if (!mapBlockMesh)
                continue;

            float d = 0.0;
            if(isBlockInSight(block->getPos(), camera_position,
                              m_camera_direction, camera_fov,
                              100000*BS, &d) == false)
            {
                continue;
            }

            used_meshes.emplace_back(mapBlockMesh);

            // Mesh animation
            {
                //JMutexAutoLock lock(block->mesh_mutex);

                mapBlockMesh->updateCameraOffset(m_camera_offset);

                // Pretty random but this should work somewhat nicely
                bool faraway = d >= BS*50;
                //bool faraway = d >= m_control.wanted_range * BS;
                if(mapBlockMesh->isAnimationForced() ||
                        !faraway ||
                        mesh_animate_count_far < (m_control.range_all ? 200 : 50))
                {
                    bool animated = mapBlockMesh->animate(
                                        faraway,
                                        animation_time,
                                        crack,
                                        daynight_ratio);
                    if(animated)
                        mesh_animate_count++;
                    if(animated && faraway)
                        mesh_animate_count_far++;
                }
                else
                {
                    mapBlockMesh->decreaseAnimationForceTimer();
                }
            }

            /*
            	Get the meshbuffers of the block
            */
            {
                //JMutexAutoLock lock(block->mesh_mutex);

                auto *mesh = mapBlockMesh->getMesh();
                if (!mesh)
                    continue;

                u32 c = mesh->getMeshBufferCount();
                for(u32 i=0; i<c; i++)
                {
                    scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);

                    buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, m_cache_trilinear_filter);
                    buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, m_cache_bilinear_filter);
                    buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, m_cache_anistropic_filter);

                    const video::SMaterial& material = buf->getMaterial();
                    video::IMaterialRenderer* rnd =
                        driver->getMaterialRenderer(material.MaterialType);
                    bool transparent = (rnd && rnd->isTransparent());
                    if(transparent == is_transparent_pass)
                    {
                        if(buf->getVertexCount() == 0)
                            errorstream<<"Block ["<<analyze_block(block)
                                       <<"] contains an empty meshbuf"<<std::endl;
                        drawbufs.add(buf);
                    }
                }
            }
        }

        std::vector<MeshBufList> &lists = drawbufs.lists;

        //int timecheck_counter = 0;
        for(std::vector<MeshBufList>::iterator i = lists.begin();
                i != lists.end(); ++i) {
#if 0
            timecheck_counter++;
            if(timecheck_counter > 50) {
                timecheck_counter = 0;
                int time2 = time(0);
                if(time2 > time1 + 4) {
                    infostream << "ClientMap::renderMap(): "
                               "Rendering takes ages, returning."
                               << std::endl;
                    return;
                }
            }
#endif

            MeshBufList &list = *i;

            driver->setMaterial(list.m);

            for(std::vector<scene::IMeshBuffer*>::iterator j = list.bufs.begin();
                    j != list.bufs.end(); ++j) {
                scene::IMeshBuffer *buf = *j;
                driver->drawMeshBuffer(buf);
                vertex_count += buf->getVertexCount();
                meshbuffer_count++;
            }

        }
    } // ScopeProfiler

    // Log only on solid pass because values are the same
    if(pass == scene::ESNRP_SOLID) {
        g_profiler->avg("CM: animated meshes", mesh_animate_count);
        g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far);
    }

    g_profiler->avg(prefix+"vertices drawn", vertex_count);
    if(blocks_had_pass_meshbuf != 0)
        g_profiler->avg(prefix+"meshbuffers per block",
                        (float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
    if(blocks_drawn != 0)
        g_profiler->avg(prefix+"empty blocks (frac)",
                        (float)blocks_without_stuff / blocks_drawn);

    g_profiler->avg("CM: PrimitiveDrawn", driver->getPrimitiveCountDrawn());

    /*infostream<<"renderMap(): is_transparent_pass="******", rendered "<<vertex_count<<" vertices."<<std::endl;*/
}
Ejemplo n.º 2
0
void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
{
	DSTACK(__FUNCTION_NAME);

	bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
	
	std::string prefix;
	if(pass == scene::ESNRP_SOLID)
		prefix = "CM: solid: ";
	else
		prefix = "CM: transparent: ";

	/*
		This is called two times per frame, reset on the non-transparent one
	*/
	if(pass == scene::ESNRP_SOLID)
	{
		m_last_drawn_sectors.clear();
	}

	bool use_trilinear_filter = g_settings->getBool("trilinear_filter");
	bool use_bilinear_filter = g_settings->getBool("bilinear_filter");
	bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter");

	/*
		Get time for measuring timeout.
		
		Measuring time is very useful for long delays when the
		machine is swapping a lot.
	*/
	int time1 = time(0);

	/*
		Get animation parameters
	*/
	float animation_time = m_client->getAnimationTime();
	int crack = m_client->getCrackLevel();
	u32 daynight_ratio = m_client->getEnv().getDayNightRatio();

	m_camera_mutex.Lock();
	v3f camera_position = m_camera_position;
	v3f camera_direction = m_camera_direction;
	f32 camera_fov = m_camera_fov;
	m_camera_mutex.Unlock();

	/*
		Get all blocks and draw all visible ones
	*/

	v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
	
	v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);

	v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
	v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;

	// Take a fair amount as we will be dropping more out later
	// Umm... these additions are a bit strange but they are needed.
	v3s16 p_blocks_min(
			p_nodes_min.X / MAP_BLOCKSIZE - 3,
			p_nodes_min.Y / MAP_BLOCKSIZE - 3,
			p_nodes_min.Z / MAP_BLOCKSIZE - 3);
	v3s16 p_blocks_max(
			p_nodes_max.X / MAP_BLOCKSIZE + 1,
			p_nodes_max.Y / MAP_BLOCKSIZE + 1,
			p_nodes_max.Z / MAP_BLOCKSIZE + 1);
	
	u32 vertex_count = 0;
	u32 meshbuffer_count = 0;
	
	// For limiting number of mesh animations per frame
	u32 mesh_animate_count = 0;
	u32 mesh_animate_count_far = 0;
	
	// Blocks that were drawn and had a mesh
	u32 blocks_drawn = 0;
	// Blocks which had a corresponding meshbuffer for this pass
	u32 blocks_had_pass_meshbuf = 0;
	// Blocks from which stuff was actually drawn
	u32 blocks_without_stuff = 0;

	/*
		Draw the selected MapBlocks
	*/

	{
	ScopeProfiler sp(g_profiler, prefix+"drawing blocks", SPT_AVG);

	MeshBufListList drawbufs;

	for(std::map<v3s16, MapBlock*>::iterator
			i = m_drawlist.begin();
			i != m_drawlist.end(); ++i)
	{
		MapBlock *block = i->second;

		// If the mesh of the block happened to get deleted, ignore it
		if(block->mesh == NULL)
			continue;
		
		float d = 0.0;
		if(isBlockInSight(block->getPos(), camera_position,
				camera_direction, camera_fov,
				100000*BS, &d) == false)
		{
			continue;
		}

		// Mesh animation
		{
			//JMutexAutoLock lock(block->mesh_mutex);
			MapBlockMesh *mapBlockMesh = block->mesh;
			assert(mapBlockMesh);
			// Pretty random but this should work somewhat nicely
			bool faraway = d >= BS*50;
			//bool faraway = d >= m_control.wanted_range * BS;
			if(mapBlockMesh->isAnimationForced() ||
					!faraway ||
					mesh_animate_count_far < (m_control.range_all ? 200 : 50))
			{
				bool animated = mapBlockMesh->animate(
						faraway,
						animation_time,
						crack,
						daynight_ratio);
				if(animated)
					mesh_animate_count++;
				if(animated && faraway)
					mesh_animate_count_far++;
			}
			else
			{
				mapBlockMesh->decreaseAnimationForceTimer();
			}
		}

		/*
			Get the meshbuffers of the block
		*/
		{
			//JMutexAutoLock lock(block->mesh_mutex);

			MapBlockMesh *mapBlockMesh = block->mesh;
			assert(mapBlockMesh);

			scene::SMesh *mesh = mapBlockMesh->getMesh();
			assert(mesh);

			u32 c = mesh->getMeshBufferCount();
			for(u32 i=0; i<c; i++)
			{
				scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);

				buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
				buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
				buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);

				const video::SMaterial& material = buf->getMaterial();
				video::IMaterialRenderer* rnd =
						driver->getMaterialRenderer(material.MaterialType);
				bool transparent = (rnd && rnd->isTransparent());
				if(transparent == is_transparent_pass)
				{
					if(buf->getVertexCount() == 0)
						errorstream<<"Block ["<<analyze_block(block)
								<<"] contains an empty meshbuf"<<std::endl;
					drawbufs.add(buf);
				}
			}
		}
	}
	
	std::list<MeshBufList> &lists = drawbufs.lists;
	
	int timecheck_counter = 0;
	for(std::list<MeshBufList>::iterator i = lists.begin();
			i != lists.end(); ++i)
	{
		{
			timecheck_counter++;
			if(timecheck_counter > 50)
			{
				timecheck_counter = 0;
				int time2 = time(0);
				if(time2 > time1 + 4)
				{
					infostream<<"ClientMap::renderMap(): "
						"Rendering takes ages, returning."
						<<std::endl;
					return;
				}
			}
		}

		MeshBufList &list = *i;
		
		driver->setMaterial(list.m);
		
		for(std::list<scene::IMeshBuffer*>::iterator j = list.bufs.begin();
				j != list.bufs.end(); ++j)
		{
			scene::IMeshBuffer *buf = *j;
			driver->drawMeshBuffer(buf);
			vertex_count += buf->getVertexCount();
			meshbuffer_count++;
		}
#if 0
		/*
			Draw the faces of the block
		*/
		{
			//JMutexAutoLock lock(block->mesh_mutex);

			MapBlockMesh *mapBlockMesh = block->mesh;
			assert(mapBlockMesh);

			scene::SMesh *mesh = mapBlockMesh->getMesh();
			assert(mesh);

			u32 c = mesh->getMeshBufferCount();
			bool stuff_actually_drawn = false;
			for(u32 i=0; i<c; i++)
			{
				scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
				const video::SMaterial& material = buf->getMaterial();
				video::IMaterialRenderer* rnd =
						driver->getMaterialRenderer(material.MaterialType);
				bool transparent = (rnd && rnd->isTransparent());
				// Render transparent on transparent pass and likewise.
				if(transparent == is_transparent_pass)
				{
					if(buf->getVertexCount() == 0)
						errorstream<<"Block ["<<analyze_block(block)
								<<"] contains an empty meshbuf"<<std::endl;
					/*
						This *shouldn't* hurt too much because Irrlicht
						doesn't change opengl textures if the old
						material has the same texture.
					*/
					driver->setMaterial(buf->getMaterial());
					driver->drawMeshBuffer(buf);
					vertex_count += buf->getVertexCount();
					meshbuffer_count++;
					stuff_actually_drawn = true;
				}
			}
			if(stuff_actually_drawn)
				blocks_had_pass_meshbuf++;
			else
				blocks_without_stuff++;
		}
#endif
	}
	} // ScopeProfiler
	
	// Log only on solid pass because values are the same
	if(pass == scene::ESNRP_SOLID){
		g_profiler->avg("CM: animated meshes", mesh_animate_count);
		g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far);
	}
	
	g_profiler->avg(prefix+"vertices drawn", vertex_count);
	if(blocks_had_pass_meshbuf != 0)
		g_profiler->avg(prefix+"meshbuffers per block",
				(float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
	if(blocks_drawn != 0)
		g_profiler->avg(prefix+"empty blocks (frac)",
				(float)blocks_without_stuff / blocks_drawn);

	/*infostream<<"renderMap(): is_transparent_pass="******", rendered "<<vertex_count<<" vertices."<<std::endl;*/
}
Ejemplo n.º 3
0
void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
{
	DSTACK(FUNCTION_NAME);

	bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;

	std::string prefix;
	if (pass == scene::ESNRP_SOLID)
		prefix = "CM: solid: ";
	else
		prefix = "CM: transparent: ";

	/*
		This is called two times per frame, reset on the non-transparent one
	*/
	if (pass == scene::ESNRP_SOLID)
		m_last_drawn_sectors.clear();

	/*
		Get time for measuring timeout.

		Measuring time is very useful for long delays when the
		machine is swapping a lot.
	*/
	std::time_t time1 = time(0);

	/*
		Get animation parameters
	*/
	float animation_time = m_client->getAnimationTime();
	int crack = m_client->getCrackLevel();
	u32 daynight_ratio = m_client->getEnv().getDayNightRatio();

	v3f camera_position = m_camera_position;
	v3f camera_direction = m_camera_direction;
	f32 camera_fov = m_camera_fov;

	/*
		Get all blocks and draw all visible ones
	*/

	u32 vertex_count = 0;
	u32 meshbuffer_count = 0;

	// For limiting number of mesh animations per frame
	u32 mesh_animate_count = 0;
	u32 mesh_animate_count_far = 0;

	// Blocks that were drawn and had a mesh
	u32 blocks_drawn = 0;
	// Blocks which had a corresponding meshbuffer for this pass
	u32 blocks_had_pass_meshbuf = 0;
	// Blocks from which stuff was actually drawn
	u32 blocks_without_stuff = 0;

	/*
		Draw the selected MapBlocks
	*/

	{
	ScopeProfiler sp(g_profiler, prefix + "drawing blocks", SPT_AVG);

	MeshBufListList drawbufs;

	for (std::map<v3s16, MapBlock*>::iterator i = m_drawlist.begin();
			i != m_drawlist.end(); ++i) {
		MapBlock *block = i->second;

		// If the mesh of the block happened to get deleted, ignore it
		if (!block->mesh)
			continue;

		float d = 0.0;
		if (!isBlockInSight(block->getPos(), camera_position,
				camera_direction, camera_fov, 100000 * BS, &d))
			continue;

		// 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
			bool faraway = d >= BS * 50;
			//bool faraway = d >= m_control.wanted_range * BS;
			if (mapBlockMesh->isAnimationForced() || !faraway ||
					mesh_animate_count_far < (m_control.range_all ? 200 : 50)) {
				bool animated = mapBlockMesh->animate(faraway, animation_time,
					crack, daynight_ratio);
				if (animated)
					mesh_animate_count++;
				if (animated && faraway)
					mesh_animate_count_far++;
			} else {
				mapBlockMesh->decreaseAnimationForceTimer();
			}
		}

		/*
			Get the meshbuffers of the block
		*/
		{
			//MutexAutoLock lock(block->mesh_mutex);

			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& material = buf->getMaterial();
					video::IMaterialRenderer* rnd =
						driver->getMaterialRenderer(material.MaterialType);
					bool transparent = (rnd && rnd->isTransparent());
					if (transparent == is_transparent_pass) {
						if (buf->getVertexCount() == 0)
							errorstream << "Block [" << analyze_block(block)
								<< "] contains an empty meshbuf" << std::endl;

						material.setFlag(video::EMF_TRILINEAR_FILTER,
							m_cache_trilinear_filter);
						material.setFlag(video::EMF_BILINEAR_FILTER,
							m_cache_bilinear_filter);
						material.setFlag(video::EMF_ANISOTROPIC_FILTER,
							m_cache_anistropic_filter);
						material.setFlag(video::EMF_WIREFRAME,
							m_control.show_wireframe);

						drawbufs.add(buf, layer);
					}
				}
			}
		}
	}

	// Render all layers in order
	for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
		std::vector<MeshBufList> &lists = drawbufs.lists[layer];

		int timecheck_counter = 0;
		for (MeshBufList &list : lists) {
			timecheck_counter++;
			if (timecheck_counter > 50) {
				timecheck_counter = 0;
				std::time_t time2 = time(0);
				if (time2 > time1 + 4) {
					infostream << "ClientMap::renderMap(): "
						"Rendering takes ages, returning."
						<< std::endl;
					return;
				}
			}

			driver->setMaterial(list.m);

			for (scene::IMeshBuffer *buf : list.bufs) {
				driver->drawMeshBuffer(buf);
				vertex_count += buf->getVertexCount();
				meshbuffer_count++;
			}
		}
	}
	} // ScopeProfiler

	// Log only on solid pass because values are the same
	if (pass == scene::ESNRP_SOLID) {
		g_profiler->avg("CM: animated meshes", mesh_animate_count);
		g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far);
	}

	g_profiler->avg(prefix + "vertices drawn", vertex_count);
	if (blocks_had_pass_meshbuf != 0)
		g_profiler->avg(prefix + "meshbuffers per block",
			(float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
	if (blocks_drawn != 0)
		g_profiler->avg(prefix + "empty blocks (frac)",
			(float)blocks_without_stuff / blocks_drawn);

	/*infostream<<"renderMap(): is_transparent_pass="******", rendered "<<vertex_count<<" vertices."<<std::endl;*/
}