ExtractLightmaps() public method

Extracts the embedded lightmap texture data and loads them as textures.
Calling this method makes the lightmap texture data embedded in the .bsp file available to the renderer. Lightmaps are extracted and loaded as Texture objects (subclass specific to RenderSystem subclass) and are named "@lightmap1", "@lightmap2" etc.
public ExtractLightmaps ( ) : void
return void
示例#1
0
        /// <summary>
        ///		/** Internal utility function for loading data from Quake3.
        /// </summary>
        protected void LoadQuake3Level(Quake3Level q3lvl)
        {
            SceneManager sm = SceneManagerEnumerator.Instance.GetSceneManager(SceneType.Interior);

            LoadEntities(q3lvl);

            Quake3ShaderManager.Instance.ParseAllSources(".shader");
            q3lvl.ExtractLightmaps();

            LoadLevelVertices(q3lvl);

            LoadLevelFaces(q3lvl);

            // now build patch information
            BuildQuake3Patches(q3lvl.NumVertices, q3lvl.NumElements);

            //-----------------------------------------------------------------------
            // Create materials for shaders
            //-----------------------------------------------------------------------
            CreateShaderMaterials(q3lvl, sm);

            //-----------------------------------------------------------------------
            // Nodes
            //-----------------------------------------------------------------------
            CreateNodes(q3lvl);

            //-----------------------------------------------------------------------
            // Brushes
            //-----------------------------------------------------------------------
            CreateBrushes(q3lvl);

            //-----------------------------------------------------------------------
            // Leaves
            //-----------------------------------------------------------------------
            CreateLeaves(q3lvl);

            // Vis - just copy
            visData.numClusters = q3lvl.VisData.clusterCount;
            visData.rowLength   = q3lvl.VisData.rowSize;
            visData.tableData   = new byte[q3lvl.VisData.rowSize * q3lvl.VisData.clusterCount];

            Array.Copy(q3lvl.VisData.data, 0, visData.tableData, 0, visData.tableData.Length);
        }
        /// <summary>
        ///		/** Internal utility function for loading data from Quake3.
        /// </summary>
        protected void LoadQuake3Level(Quake3Level q3lvl)
        {
            SceneManager sm = SceneManagerEnumerator.Instance.GetSceneManager(SceneType.Interior);
            LoadEntities(q3lvl);

            Quake3ShaderManager.Instance.ParseAllSources(".shader");
            q3lvl.ExtractLightmaps();

            LoadLevelVertices(q3lvl);

            LoadLevelFaces(q3lvl);

            // now build patch information
            BuildQuake3Patches(q3lvl.NumVertices, q3lvl.NumElements);

            //-----------------------------------------------------------------------
            // Create materials for shaders
            //-----------------------------------------------------------------------
            CreateShaderMaterials(q3lvl, sm);

            //-----------------------------------------------------------------------
            // Nodes
            //-----------------------------------------------------------------------
            CreateNodes(q3lvl);

            //-----------------------------------------------------------------------
            // Brushes
            //-----------------------------------------------------------------------
            CreateBrushes(q3lvl);

            //-----------------------------------------------------------------------
            // Leaves
            //-----------------------------------------------------------------------
            CreateLeaves(q3lvl);

            // Vis - just copy
            visData.numClusters = q3lvl.VisData.clusterCount;
            visData.rowLength = q3lvl.VisData.rowSize;
            visData.tableData = new byte[q3lvl.VisData.rowSize * q3lvl.VisData.clusterCount];

            Array.Copy(q3lvl.VisData.data, 0, visData.tableData, 0, visData.tableData.Length);
        }
示例#3
0
		/// <summary>
		///		/** Internal utility function for loading data from Quake3.
		/// </summary>
		protected void LoadQuake3Level( Quake3Level q3lvl )
		{
			ResourceGroupManager rgm = ResourceGroupManager.Instance;
			rgm.notifyWorldGeometryStageStarted( "Parsing entities" );
			LoadEntities( q3lvl );
			rgm.notifyWorldGeometryStageEnded();

			rgm.notifyWorldGeometryStageStarted( "Extracting lightmaps" );
			q3lvl.ExtractLightmaps();
			rgm.notifyWorldGeometryStageEnded();

			//-----------------------------------------------------------------------
			// Vertices
			//-----------------------------------------------------------------------
			// Allocate memory for vertices & copy
			vertexData = new VertexData();

			// Create vertex declaration
			VertexDeclaration decl = vertexData.vertexDeclaration;
			int offset = 0;
			int lightTexOffset = 0;
			decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Position );
			offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
			decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Normal );
			offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
			decl.AddElement( 0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 );
			offset += VertexElement.GetTypeSize( VertexElementType.Float2 );
			decl.AddElement( 0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 1 );

			// Build initial patches - we need to know how big the vertex buffer needs to be
			// to accommodate the subdivision
			// we don't want to include the elements for texture lighting, so we clone it
			rgm.notifyWorldGeometryStageStarted( "Initializing patches" );
			InitQuake3Patches( q3lvl, (VertexDeclaration)decl.Clone() );
			rgm.notifyWorldGeometryStageEnded();

			// this is for texture lighting color and alpha
			decl.AddElement( 1, lightTexOffset, VertexElementType.Color, VertexElementSemantic.Diffuse );
			lightTexOffset += VertexElement.GetTypeSize( VertexElementType.Color );
			// this is for texture lighting coords
			decl.AddElement( 1, lightTexOffset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 2 );

			rgm.notifyWorldGeometryStageStarted( "Setting up vertex data" );
			// Create the vertex buffer, allow space for patches
			HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone(0), q3lvl.NumVertices + patchVertexCount,	BufferUsage.StaticWriteOnly /* the vertices will be read often for texture lighting, use shadow buffer */, true );

			// Create the vertex buffer for texture lighting, allow space for patches
			HardwareVertexBuffer texLightBuf = HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone(1), q3lvl.NumVertices + patchVertexCount, BufferUsage.DynamicWriteOnly, false );

			// COPY static vertex data - Note that we can't just block-copy the vertex data because we have to reorder
			// our vertex elements; this is to ensure compatibility with older cards when using
			// hardware vertex buffers - Direct3D requires that the buffer format maps onto a
			// FVF in those older drivers.
			// Lock just the non-patch area for now.

			unsafe
			{
				BspVertex vert = new BspVertex();
				TextureLightMap texLightMap = new TextureLightMap();

				// Keep another base pointer for use later in patch building
				for ( int v = 0; v < q3lvl.NumVertices; v++ )
				{
					QuakeVertexToBspVertex( q3lvl.Vertices[ v ], out vert, out texLightMap );

					BspVertex* bvptr = &vert;
					TextureLightMap* tlptr = &texLightMap;

					vbuf.WriteData(
						v * sizeof( BspVertex ),
						sizeof( BspVertex ),
						(IntPtr)bvptr
						);

					texLightBuf.WriteData(
						v * sizeof( TextureLightMap ),
						sizeof( TextureLightMap ),
						(IntPtr)tlptr
						);

				}
			}

			// Setup binding
			vertexData.vertexBufferBinding.SetBinding( 0, vbuf );

			// Setup texture lighting binding
			vertexData.vertexBufferBinding.SetBinding( 1, texLightBuf );

			// Set other data
			vertexData.vertexStart = 0;
			vertexData.vertexCount = q3lvl.NumVertices + patchVertexCount;
			rgm.notifyWorldGeometryStageEnded();

			//-----------------------------------------------------------------------
			// Faces
			//-----------------------------------------------------------------------
			rgm.notifyWorldGeometryStageStarted( "Setting up face data" );
			leafFaceGroups = new int[ q3lvl.LeafFaces.Length ];
			Array.Copy( q3lvl.LeafFaces, 0, leafFaceGroups, 0, leafFaceGroups.Length );

			faceGroups = new BspStaticFaceGroup[ q3lvl.Faces.Length ];

			// Set up index buffer
			// NB Quake3 indexes are 32-bit
			// Copy the indexes into a software area for staging
			numIndexes = q3lvl.NumElements + patchIndexCount;

			// Create an index buffer manually in system memory, allow space for patches
			indexes = HardwareBufferManager.Instance.CreateIndexBuffer(
				IndexType.Size32,
				numIndexes,
				BufferUsage.Dynamic
				);

			// Write main indexes
			indexes.WriteData( 0, Marshal.SizeOf( typeof( uint ) ) * q3lvl.NumElements, q3lvl.Elements, true );
			rgm.notifyWorldGeometryStageEnded();

			// now build patch information
			rgm.notifyWorldGeometryStageStarted( "Building patches" );
			BuildQuake3Patches( q3lvl.NumVertices, q3lvl.NumElements );
			rgm.notifyWorldGeometryStageEnded();

			//-----------------------------------------------------------------------
			// Create materials for shaders
			//-----------------------------------------------------------------------
			// NB this only works for the 'default' shaders for now
			// i.e. those that don't have a .shader script and thus default
			// to just texture + lightmap
			// TODO: pre-parse all .shader files and create lookup for next stage (use ROGL shader_file_t)

			// Material names are shadername#lightmapnumber
			// This is because I like to define materials up front completely
			// rather than combine lightmap and shader dynamically (it's
			// more generic). It results in more materials, but they're small
			// beer anyway. Texture duplication is prevented by infrastructure.
			// To do this I actually need to parse the faces since they have the
			// shader/lightmap combo (lightmap number is not in the shader since
			// it can be used with multiple lightmaps)
			string shaderName;
			int face = q3lvl.Faces.Length;
			int progressCountdown = 100;
			int progressCount = 0;

			while ( face-- > 0 )
			{
				// Progress reporting
				if ( progressCountdown == 100 )
				{
					++progressCount;
					String str = String.Format( "Loading materials (phase {0})", progressCount );
					rgm.notifyWorldGeometryStageStarted( str );
				}
				else if ( progressCountdown == 0 )
				{
					// stage report
					rgm.notifyWorldGeometryStageEnded();
					progressCountdown = 100 + 1;
				}

				// Check to see if existing material
				// Format shader#lightmap
				int shadIdx = q3lvl.Faces[ face ].shader;

				shaderName = String.Format( "{0}#{1}", q3lvl.Shaders[ shadIdx ].name, q3lvl.Faces[ face ].lmTexture );
				Material shadMat = (Material)MaterialManager.Instance.GetByName( shaderName );

				if ( shadMat == null && !bspOptions.useLightmaps )
				{
					// try the no-lightmap material
					shaderName = String.Format( "{0}#n", q3lvl.Shaders[ shadIdx ].name );
					shadMat = (Material)MaterialManager.Instance.GetByName( shaderName );
				}

				if ( shadMat == null )
				{
					// Color layer
					// NB no extension in Q3A(doh), have to try shader, .jpg, .tga
					string tryName = q3lvl.Shaders[ shadIdx ].name;

					// Try shader first
					Quake3Shader shader = (Quake3Shader)Quake3ShaderManager.Instance.GetByName( tryName );

					if ( shader != null )
					{
						shadMat = shader.CreateAsMaterial( q3lvl.Faces[ face ].lmTexture );
					}
					else
					{
						// No shader script, try default type texture
						shadMat = (Material)MaterialManager.Instance.Create( shaderName, rgm.WorldResourceGroupName );
						Pass shadPass = shadMat.GetTechnique( 0 ).GetPass( 0 );

						// Try jpg
						TextureUnitState tex = null;
						if ( ResourceGroupManager.Instance.ResourceExists( rgm.WorldResourceGroupName, tryName + ".jpg" ) )
						{
							tex = shadPass.CreateTextureUnitState( tryName + ".jpg" );
						}
						if ( ResourceGroupManager.Instance.ResourceExists( rgm.WorldResourceGroupName, tryName + ".tga" ) )
						{
							tex = shadPass.CreateTextureUnitState( tryName + ".tga" );
						}

						if ( tex != null )
						{
							// Set replace on all first layer textures for now
							tex.SetColorOperation( LayerBlendOperation.Replace );
                            tex.SetTextureAddressingMode( TextureAddressing.Wrap );
							// for ambient lighting
							tex.ColorBlendMode.source2 = LayerBlendSource.Manual;
						}

						if ( bspOptions.useLightmaps && q3lvl.Faces[ face ].lmTexture != -1 )
						{
							// Add lightmap, additive blending
							tex = shadPass.CreateTextureUnitState( String.Format( "@lightmap{0}", q3lvl.Faces[ face ].lmTexture ) );

							// Blend
							tex.SetColorOperation( LayerBlendOperation.Modulate );

							// Use 2nd texture co-ordinate set
							tex.TextureCoordSet = 1;

							// Clamp
                            tex.SetTextureAddressingMode( TextureAddressing.Clamp );
						}

						shadMat.CullingMode = CullingMode.None;
						shadMat.Lighting = false;
					}
				}

				shadMat.Load();

				// Copy face data
				BspStaticFaceGroup dest = new BspStaticFaceGroup();
				InternalBspFace src = q3lvl.Faces[ face ];

				if ( ( q3lvl.Shaders[ src.shader ].surfaceFlags & SurfaceFlags.Sky ) == SurfaceFlags.Sky )
					dest.isSky = true;
				else
					dest.isSky = false;

				dest.materialHandle = shadMat.Handle;
				dest.elementStart = src.elemStart;
				dest.numElements = src.elemCount;
				dest.numVertices = src.vertCount;
				dest.vertexStart = src.vertStart;
				dest.plane = new Plane();

				if ( Quake3ShaderManager.Instance.GetByName( q3lvl.Shaders[ shadIdx ].name ) != null )
				{
					// it's a quake shader
					dest.isQuakeShader = true;
				}

				if ( src.type == BspFaceType.Normal )
				{
					dest.type = FaceGroup.FaceList;

					// Assign plane
					dest.plane.Normal = new Vector3(
						src.normal[ 0 ],
						src.normal[ 1 ],
						src.normal[ 2 ]
						);
					dest.plane.D = -dest.plane.Normal.Dot(
						new Vector3(
						src.org[ 0 ],
						src.org[ 1 ],
						src.org[ 2 ]
						)
						);

					// Don't rebase indexes here - Quake3 re-uses some indexes for multiple vertex
					// groups eg repeating small details have the same relative vertex data but
					// use the same index data.
				}
				else if ( src.type == BspFaceType.Patch )
				{
					// Seems to be some crap in the Q3 level where vertex count = 0 or num control points = 0?
					if ( ( dest.numVertices == 0 ) || ( src.meshCtrl[ 0 ] == 0 ) )
					{
						dest.type = FaceGroup.Unknown;
					}
					else
					{
						// Set up patch surface
						dest.type = FaceGroup.Patch;

						// Locate the patch we already built
						if ( !patches.ContainsKey( face ) )
							throw new AxiomException( "Patch not found from previous built state." );

						dest.patchSurf = (PatchSurface)patches[ face ];
					}
				}
				else if ( src.type == BspFaceType.Mesh )
				{
					dest.type = FaceGroup.FaceList;

					// Assign plane
					dest.plane.Normal = new Vector3( src.normal[ 0 ], src.normal[ 1 ], src.normal[ 2 ] );
					dest.plane.D = -dest.plane.Normal.Dot( new Vector3( src.org[ 0 ], src.org[ 1 ], src.org[ 2 ] ) );
				}
				else
				{
					LogManager.Instance.Write( "!!! Unknown face type !!!" );
				}

				faceGroups[ face ] = dest;
			}

			//-----------------------------------------------------------------------
			// Nodes
			//-----------------------------------------------------------------------
			// Allocate memory for all nodes (leaves and splitters)
			nodes = new BspNode[ q3lvl.NumNodes + q3lvl.NumLeaves ];
			numLeaves = q3lvl.NumLeaves;
			leafStart = q3lvl.NumNodes;

			// Run through and initialize the array so front/back node pointers
			// aren't null.
			for ( int i = 0; i < nodes.Length; i++ )
				nodes[ i ] = new BspNode();

			// Convert nodes
			// In our array, first q3lvl.NumNodes are non-leaf, others are leaves
			for ( int i = 0; i < q3lvl.NumNodes; i++ )
			{
				BspNode node = nodes[ i ];
				InternalBspNode q3node = q3lvl.Nodes[ i ];

				node.IsLeaf = false;
				node.Owner = this;

				Plane splitPlane = new Plane();

				// Set plane
				splitPlane.Normal = new Vector3(
					q3lvl.Planes[ q3node.plane ].normal[ 0 ],
					q3lvl.Planes[ q3node.plane ].normal[ 1 ],
					q3lvl.Planes[ q3node.plane ].normal[ 2 ]
					);
				splitPlane.D = -q3lvl.Planes[ q3node.plane ].distance;

				node.SplittingPlane = splitPlane;

				// Set bounding box
				node.BoundingBox = new AxisAlignedBox(
					new Vector3(
						q3node.bbox[ 0 ],
						q3node.bbox[ 1 ],
						q3node.bbox[ 2 ]
					),
					new Vector3(
						q3node.bbox[ 3 ],
						q3node.bbox[ 4 ],
						q3node.bbox[ 5 ]
					)
				);

				// Set back pointer
				// Negative indexes in Quake3 mean leaves.
				if ( q3node.back < 0 )
					node.BackNode = nodes[ leafStart + ( ~( q3node.back ) ) ];
				else
					node.BackNode = nodes[ q3node.back ];

				// Set front pointer
				// Negative indexes in Quake3 mean leaves
				if ( q3node.front < 0 )
					node.FrontNode = nodes[ leafStart + ( ~( q3node.front ) ) ];
				else
					node.FrontNode = nodes[ q3node.front ];
			}

			//-----------------------------------------------------------------------
			// Brushes
			//-----------------------------------------------------------------------
			// Reserve enough memory for all brushes, solid or not (need to maintain indexes)
			brushes = new BspBrush[ q3lvl.NumBrushes ];

			for ( int i = 0; i < q3lvl.NumBrushes; i++ )
			{
				InternalBspBrush q3brush = q3lvl.Brushes[ i ];

				// Create a new OGRE brush
				BspBrush brush = new BspBrush();
				int numBrushSides = q3brush.numSides;
				int brushSideIdx = q3brush.firstSide;

				// Iterate over the sides and create plane for each
				while ( numBrushSides-- > 0 )
				{
					InternalBspPlane side = q3lvl.Planes[ q3lvl.BrushSides[ brushSideIdx ].planeNum ];

					// Notice how we normally invert Q3A plane distances, but here we do not
					// Because we want plane normals pointing out of solid brushes, not in.
					Plane brushSide = new Plane(
						new Vector3(
							q3lvl.Planes[ q3lvl.BrushSides[ brushSideIdx ].planeNum ].normal[ 0 ],
							q3lvl.Planes[ q3lvl.BrushSides[ brushSideIdx ].planeNum ].normal[ 1 ],
							q3lvl.Planes[ q3lvl.BrushSides[ brushSideIdx ].planeNum ].normal[ 2 ]
						), q3lvl.Planes[ q3lvl.BrushSides[ brushSideIdx ].planeNum ].distance );

					brush.Planes.Add( brushSide );
					brushSideIdx++;
				}

				// Build world fragment
				brush.Fragment.FragmentType = WorldFragmentType.PlaneBoundedRegion;
				brush.Fragment.Planes = brush.Planes;

				brushes[ i ] = brush;
			}

			//-----------------------------------------------------------------------
			// Leaves
			//-----------------------------------------------------------------------
			for ( int i = 0; i < q3lvl.NumLeaves; ++i )
			{
				BspNode node = nodes[ i + this.LeafStart ];
				InternalBspLeaf q3leaf = q3lvl.Leaves[ i ];

				node.IsLeaf = true;
				node.Owner = this;

				// Set bounding box
				node.BoundingBox.Minimum = new Vector3(
					q3leaf.bbox[ 0 ],
					q3leaf.bbox[ 1 ],
					q3leaf.bbox[ 2 ]
					);
				node.BoundingBox.Maximum = new Vector3(
					q3leaf.bbox[ 3 ],
					q3leaf.bbox[ 4 ],
					q3leaf.bbox[ 5 ]
					);

				// Set faces
				node.FaceGroupStart = q3leaf.faceStart;
				node.NumFaceGroups = q3leaf.faceCount;
				node.VisCluster = q3leaf.cluster;

				// Load Brushes for this leaf
				int realBrushIdx = 0, solidIdx = 0;
				int brushCount = q3leaf.brushCount;
				int brushIdx = q3leaf.brushStart;

				node.SolidBrushes = new BspBrush[ brushCount ];

				while ( brushCount-- > 0 )
				{
					realBrushIdx = q3lvl.LeafBrushes[ brushIdx ];
					InternalBspBrush q3brush = q3lvl.Brushes[ realBrushIdx ];

					// Only load solid ones, we don't care about any other types
					// Shader determines this.
					InternalBspShader brushShader = q3lvl.Shaders[ q3brush.shaderIndex ];

					if ( ( brushShader.contentFlags & ContentFlags.Solid ) == ContentFlags.Solid )
						node.SolidBrushes[ solidIdx ] = brushes[ realBrushIdx ];

					brushIdx++;
					solidIdx++;
				}
			}

			// Vis - just copy
			visData.numClusters = q3lvl.VisData.clusterCount;
			visData.rowLength = q3lvl.VisData.rowSize;
			visData.tableData = new byte[ q3lvl.VisData.rowSize * q3lvl.VisData.clusterCount ];

			Array.Copy( q3lvl.VisData.data, 0, visData.tableData, 0, visData.tableData.Length );
		}