예제 #1
0
파일: mesh.cpp 프로젝트: t0suj4/minetest
void shadeMeshFaces(scene::IMesh *mesh)
{
	if (mesh == NULL)
		return;

	u32 mc = mesh->getMeshBufferCount();
	for (u32 j = 0; j < mc; j++) {
		scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
		const u32 stride = getVertexPitchFromType(buf->getVertexType());
		u32 vertex_count = buf->getVertexCount();
		u8 *vertices = (u8 *)buf->getVertices();
		for (u32 i = 0; i < vertex_count; i++) {
			video::S3DVertex *vertex = (video::S3DVertex *)(vertices + i * stride);
			video::SColor &vc = vertex->Color;
			if (vertex->Normal.Y < -0.5) {
				applyFacesShading (vc, 0.447213);
			} else if (vertex->Normal.Z > 0.5) {
				applyFacesShading (vc, 0.670820);
			} else if (vertex->Normal.Z < -0.5) {
				applyFacesShading (vc, 0.670820);
			} else if (vertex->Normal.X > 0.5) {
				applyFacesShading (vc, 0.836660);
			} else if (vertex->Normal.X < -0.5) {
				applyFacesShading (vc, 0.836660);
			}
		}
	}
}
예제 #2
0
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, bool use_scale)
{
	PreMeshBuffer &p = findBuffer(layer, layernum, numVertices);

	f32 scale = 1.0f;
	if (use_scale)
		scale = 1.0f / layer.scale;

	u32 vertex_count = p.vertices.size();
	for (u32 i = 0; i < numVertices; i++) {
		video::SColor color = c;
		if (!light_source)
			applyFacesShading(color, vertices[i].Normal);
		p.vertices.emplace_back(vertices[i].Pos + pos, vertices[i].Normal, color,
				scale * vertices[i].TCoords);
	}

	for (u32 i = 0; i < numIndices; i++)
		p.indices.push_back(indices[i] + vertex_count);
}
예제 #3
0
MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
	clearHardwareBuffer(false),
	step(data->step),
	timestamp(data->timestamp),
	m_mesh(new scene::SMesh()),
	m_gamedef(data->m_gamedef),
	m_animation_force_timer(0), // force initial animation
	m_last_crack(-1),
	m_crack_materials(),
	m_highlighted_materials(),
	m_last_daynight_ratio((u32) -1),
	m_daynight_diffs(),
	m_usage_timer(0)
{
	m_enable_shaders = g_settings->getBool("enable_shaders");
	m_enable_highlighting = g_settings->getBool("enable_node_highlighting");

	// 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
	// 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
	//TimeTaker timer1("MapBlockMesh()");

	data->fill_data();

	std::vector<FastFace> fastfaces_new;

	/*
		We are including the faces of the trailing edges of the block.
		This means that when something changes, the caller must
		also update the meshes of the blocks at the leading edges.

		NOTE: This is the slowest part of this method.
	*/
	{
		// 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
		//TimeTaker timer2("updateAllFastFaceRows()");
		updateAllFastFaceRows(data, fastfaces_new, step);
	}
	// End of slow part

	//if (data->debug) infostream<<" step="<<step<<" fastfaces_new.size="<<fastfaces_new.size()<<std::endl;

	/*
		Convert FastFaces to MeshCollector
	*/

	MeshCollector collector;

	{
		// avg 0ms (100ms spikes when loading textures the first time)
		// (NOTE: probably outdated)
		//TimeTaker timer2("MeshCollector building");

		for(u32 i=0; i<fastfaces_new.size(); i++)
		{
			FastFace &f = fastfaces_new[i];

			const u16 indices[] = {0,1,2,2,3,0};
			const u16 indices_alternate[] = {0,1,3,2,3,1};

			if(f.tile.texture == NULL)
				continue;

			const u16 *indices_p = indices;

			/*
				Revert triangles for nicer looking gradient if vertices
				1 and 3 have same color or 0 and 2 have different color.
				getRed() is the day color.
			*/
			if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
					|| f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
				indices_p = indices_alternate;

			collector.append(f.tile, f.vertices, 4, indices_p, 6);
		}
	}

	/*
		Add special graphics:
		- torches
		- flowing water
		- fences
		- whatever
	*/

	if(step <= 1)
	mapblock_mesh_generate_special(data, collector);

	m_highlight_mesh_color = data->m_highlight_mesh_color;

	/*
		Convert MeshCollector to SMesh
	*/
	ITextureSource *tsrc = m_gamedef->tsrc();
	IShaderSource *shdrsrc = m_gamedef->getShaderSource();

	for(u32 i = 0; i < collector.prebuffers.size(); i++)
	{
		PreMeshBuffer &p = collector.prebuffers[i];

		if (step <= data->draw_control.farmesh || !data->draw_control.farmesh) {
		// Generate animation data
		// - Cracks
		if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
		{
			// Find the texture name plus ^[crack:N:
			std::ostringstream os(std::ios::binary);
			os<<tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
			if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
				os<<"o";  // use ^[cracko
			os<<":"<<(u32)p.tile.animation_frame_count<<":";
			m_crack_materials.insert(std::make_pair(i, os.str()));
			// Replace tile texture with the cracked one
			p.tile.texture = tsrc->getTexture(
					os.str()+"0",
					&p.tile.texture_id);
		}
		}
		// - Texture animation
		if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
		{
			// Add to MapBlockMesh in order to animate these tiles
			m_animation_tiles[i] = p.tile;
			m_animation_frames[i] = 0;
			if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
				// Get starting position from noise
				m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
						data->m_blockpos.X, data->m_blockpos.Y,
						data->m_blockpos.Z, 0));
			} else {
				// Play all synchronized
				m_animation_frame_offsets[i] = 0;
			}
			// Replace tile texture with the first animation frame
			FrameSpec animation_frame = p.tile.frames.find(0)->second;
			p.tile.texture = animation_frame.texture;
		}

		if(m_enable_highlighting && p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED)
			m_highlighted_materials.push_back(i);	

		for(u32 j = 0; j < p.vertices.size(); j++)
		{
			// Note applyFacesShading second parameter is precalculated sqrt
			// value for speed improvement
			// Skip it for lightsources and top faces.
			video::SColor &vc = p.vertices[j].Color;
			if (!vc.getBlue()) {
				if (p.vertices[j].Normal.Y < -0.5) {
					applyFacesShading (vc, 0.447213);
				} else if (p.vertices[j].Normal.X > 0.5) {
					applyFacesShading (vc, 0.670820);
				} else if (p.vertices[j].Normal.X < -0.5) {
					applyFacesShading (vc, 0.670820);
				} else if (p.vertices[j].Normal.Z > 0.5) {
					applyFacesShading (vc, 0.836660);
				} else if (p.vertices[j].Normal.Z < -0.5) {
					applyFacesShading (vc, 0.836660);
				}
			}
			if(!m_enable_shaders)
			{
				// - Classic lighting (shaders handle this by themselves)
				// Set initial real color and store for later updates
				u8 day = vc.getRed();
				u8 night = vc.getGreen();
				finalColorBlend(vc, day, night, 1000);
				if(day != night)
					m_daynight_diffs[i][j] = std::make_pair(day, night);
			}
		}

		// Create material
		video::SMaterial material;
		material.setFlag(video::EMF_LIGHTING, false);
		material.setFlag(video::EMF_BACK_FACE_CULLING, true);
		material.setFlag(video::EMF_BILINEAR_FILTER, false);
		material.setFlag(video::EMF_FOG_ENABLE, true);
		//material.setFlag(video::EMF_WIREFRAME, true);
		material.setTexture(0, p.tile.texture);

		if (p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED) {
			material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
		} else {
			if (m_enable_shaders) {
				material.MaterialType = shdrsrc->getShaderInfo(p.tile.shader_id).material;
				p.tile.applyMaterialOptionsWithShaders(material);
				if (p.tile.normal_texture) {
					material.setTexture(1, p.tile.normal_texture);
					material.setTexture(2, tsrc->getTexture("enable_img.png"));
				} else {
					material.setTexture(2, tsrc->getTexture("disable_img.png"));
				}
			} else {
				p.tile.applyMaterialOptions(material);
			}
		}

		// Create meshbuffer
		// This is a "Standard MeshBuffer",
		// it's a typedeffed CMeshBuffer<video::S3DVertex>
		scene::SMeshBuffer *buf = new scene::SMeshBuffer();
		// Set material
		buf->Material = material;
		// Add to mesh
		m_mesh->addMeshBuffer(buf);
		// Mesh grabbed it
		buf->drop();
		buf->append(&p.vertices[0], p.vertices.size(),
				&p.indices[0], p.indices.size());
	}

	m_camera_offset = camera_offset;

	/*
		Do some stuff to the mesh
	*/

	v3f t = v3f(0,0,0);
	if (step>1) {
		scaleMesh(m_mesh, v3f(step,step,step));
		// TODO: remove this wrong numbers, find formula   good test: fly above ocean
		if (step == 2)	t = v3f(BS/2,		 BS/2,		BS/2);
		if (step == 4)	t = v3f(BS*1.666,	-BS/3.0,	BS*1.666);
		if (step == 8)	t = v3f(BS*2.666,	-BS*2.4,	BS*2.666);
		if (step == 16)	t = v3f(BS*6.4,		-BS*6.4,	BS*6.4);
	}
	translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS) + t);

	if(m_mesh)
	{
#if 0
		// Usually 1-700 faces and 1-7 materials
		infostream<<"Updated MapBlock mesh p="<<data->m_blockpos<<" has "<<fastfaces_new.size()<<" faces "
				<<"and uses "<<m_mesh->getMeshBufferCount()
				<<" materials "<<" step="<<step<<" range="<<data->range<< " mesh="<<m_mesh<<std::endl;
#endif
	}

	//std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;

	// Check if animation is required for this mesh
	m_has_animation =
		!m_crack_materials.empty() ||
		!m_daynight_diffs.empty() ||
		!m_animation_tiles.empty() ||
		!m_highlighted_materials.empty();
}
예제 #4
0
MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
	m_mesh(new scene::SMesh()),
	m_minimap_mapblock(NULL),
	m_gamedef(data->m_gamedef),
	m_tsrc(m_gamedef->getTextureSource()),
	m_shdrsrc(m_gamedef->getShaderSource()),
	m_animation_force_timer(0), // force initial animation
	m_last_crack(-1),
	m_crack_materials(),
	m_highlighted_materials(),
	m_last_daynight_ratio((u32) -1),
	m_daynight_diffs()
{
	m_enable_shaders = data->m_use_shaders;
	m_enable_highlighting = g_settings->getBool("enable_node_highlighting");

	if (g_settings->getBool("enable_minimap")) {
		m_minimap_mapblock = new MinimapMapblock;
		m_minimap_mapblock->getMinimapNodes(
			&data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
	}

	// 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
	// 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
	//TimeTaker timer1("MapBlockMesh()");

	std::vector<FastFace> fastfaces_new;
	fastfaces_new.reserve(512);

	/*
		We are including the faces of the trailing edges of the block.
		This means that when something changes, the caller must
		also update the meshes of the blocks at the leading edges.

		NOTE: This is the slowest part of this method.
	*/
	{
		// 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
		//TimeTaker timer2("updateAllFastFaceRows()");
		updateAllFastFaceRows(data, fastfaces_new);
	}
	// End of slow part

	/*
		Convert FastFaces to MeshCollector
	*/

	MeshCollector collector;

	{
		// avg 0ms (100ms spikes when loading textures the first time)
		// (NOTE: probably outdated)
		//TimeTaker timer2("MeshCollector building");

		for(u32 i=0; i<fastfaces_new.size(); i++)
		{
			FastFace &f = fastfaces_new[i];

			const u16 indices[] = {0,1,2,2,3,0};
			const u16 indices_alternate[] = {0,1,3,2,3,1};

			if(f.tile.texture == NULL)
				continue;

			const u16 *indices_p = indices;

			/*
				Revert triangles for nicer looking gradient if vertices
				1 and 3 have same color or 0 and 2 have different color.
				getRed() is the day color.
			*/
			if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
					|| f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
				indices_p = indices_alternate;

			collector.append(f.tile, f.vertices, 4, indices_p, 6);
		}
	}

	/*
		Add special graphics:
		- torches
		- flowing water
		- fences
		- whatever
	*/

	mapblock_mesh_generate_special(data, collector);

	m_highlight_mesh_color = data->m_highlight_mesh_color;

	/*
		Convert MeshCollector to SMesh
	*/

	for(u32 i = 0; i < collector.prebuffers.size(); i++)
	{
		PreMeshBuffer &p = collector.prebuffers[i];

		// Generate animation data
		// - Cracks
		if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
		{
			// Find the texture name plus ^[crack:N:
			std::ostringstream os(std::ios::binary);
			os<<m_tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
			if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
				os<<"o";  // use ^[cracko
			os<<":"<<(u32)p.tile.animation_frame_count<<":";
			m_crack_materials.insert(std::make_pair(i, os.str()));
			// Replace tile texture with the cracked one
			p.tile.texture = m_tsrc->getTextureForMesh(
					os.str()+"0",
					&p.tile.texture_id);
		}
		// - Texture animation
		if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
		{
			// Add to MapBlockMesh in order to animate these tiles
			m_animation_tiles[i] = p.tile;
			m_animation_frames[i] = 0;
			if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
				// Get starting position from noise
				m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
						data->m_blockpos.X, data->m_blockpos.Y,
						data->m_blockpos.Z, 0));
			} else {
				// Play all synchronized
				m_animation_frame_offsets[i] = 0;
			}
			// Replace tile texture with the first animation frame
			FrameSpec animation_frame = p.tile.frames[0];
			p.tile.texture = animation_frame.texture;
		}

		if(m_enable_highlighting && p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED)
			m_highlighted_materials.push_back(i);

		for(u32 j = 0; j < p.vertices.size(); j++)
		{
			video::S3DVertexTangents *vertex = &p.vertices[j];
			// Note applyFacesShading second parameter is precalculated sqrt
			// value for speed improvement
			// Skip it for lightsources and top faces.
			video::SColor &vc = vertex->Color;
			if (!vc.getBlue()) {
				if (vertex->Normal.Y < -0.5) {
					applyFacesShading (vc, 0.447213);
				} else if (vertex->Normal.X > 0.5) {
					applyFacesShading (vc, 0.670820);
				} else if (vertex->Normal.X < -0.5) {
					applyFacesShading (vc, 0.670820);
				} else if (vertex->Normal.Z > 0.5) {
					applyFacesShading (vc, 0.836660);
				} else if (vertex->Normal.Z < -0.5) {
					applyFacesShading (vc, 0.836660);
				}
			}
			if(!m_enable_shaders)
			{
				// - Classic lighting (shaders handle this by themselves)
				// Set initial real color and store for later updates
				u8 day = vc.getRed();
				u8 night = vc.getGreen();
				finalColorBlend(vc, day, night, 1000);
				if(day != night)
					m_daynight_diffs[i][j] = std::make_pair(day, night);
			}
		}

		// Create material
		video::SMaterial material;
		material.setFlag(video::EMF_LIGHTING, false);
		material.setFlag(video::EMF_BACK_FACE_CULLING, true);
		material.setFlag(video::EMF_BILINEAR_FILTER, false);
		material.setFlag(video::EMF_FOG_ENABLE, true);
		material.setTexture(0, p.tile.texture);

		if (p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED) {
			material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
		} else {
			if (m_enable_shaders) {
				material.MaterialType = m_shdrsrc->getShaderInfo(p.tile.shader_id).material;
				p.tile.applyMaterialOptionsWithShaders(material);
				if (p.tile.normal_texture) {
					material.setTexture(1, p.tile.normal_texture);
				}
				material.setTexture(2, p.tile.flags_texture);
			} else {
				p.tile.applyMaterialOptions(material);
			}
		}

	// Create meshbuffer
	scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
	// Set material
	buf->Material = material;
	// Add to mesh
	m_mesh->addMeshBuffer(buf);
	// Mesh grabbed it
	buf->drop();
	buf->append(&p.vertices[0], p.vertices.size(),
		&p.indices[0], p.indices.size());
}
	m_camera_offset = camera_offset;

	/*
		Do some stuff to the mesh
	*/

	translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));

	if (m_enable_shaders) {
		scene::IMeshManipulator* meshmanip = m_gamedef->getSceneManager()->getMeshManipulator();
		meshmanip->recalculateTangents(m_mesh, true, false, false);
	}

	if(m_mesh)
	{
#if 0
		// Usually 1-700 faces and 1-7 materials
		std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
				<<"and uses "<<m_mesh->getMeshBufferCount()
				<<" materials (meshbuffers)"<<std::endl;
#endif

		// Use VBO for mesh (this just would set this for ever buffer)
		// This will lead to infinite memory usage because or irrlicht.
		//m_mesh->setHardwareMappingHint(scene::EHM_STATIC);

		/*
			NOTE: If that is enabled, some kind of a queue to the main
			thread should be made which would call irrlicht to delete
			the hardware buffer and then delete the mesh
		*/
	}

	//std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;

	// Check if animation is required for this mesh
	m_has_animation =
		!m_crack_materials.empty() ||
		!m_daynight_diffs.empty() ||
		!m_animation_tiles.empty() ||
		!m_highlighted_materials.empty();
}