Summary description for BspStaticFaceGroup.
Inheritance: Axiom.Graphics.StaticFaceGroup
		/// <summary>
		///		Caches a face group and calculates texture lighting coordinates.
		/// </summary>
		protected int CacheLightGeometry( TextureLight light, BufferBase pIndexesBuf, BufferBase pTexLightMapsBuf,
		                                  BufferBase pVerticesBuf, BspStaticFaceGroup faceGroup )
		{
#if !AXIOM_SAFE_ONLY
			unsafe
#endif
			{
				// Skip sky always
				if ( faceGroup.isSky )
				{
					return 0;
				}

				int idxStart = 0;
				int numIdx = 0;
				int vertexStart = 0;

				if ( faceGroup.type == FaceGroup.FaceList )
				{
					idxStart = faceGroup.elementStart;
					numIdx = faceGroup.numElements;
					vertexStart = faceGroup.vertexStart;
				}
				else if ( faceGroup.type == FaceGroup.Patch )
				{
					idxStart = faceGroup.patchSurf.IndexOffset;
					numIdx = faceGroup.patchSurf.CurrentIndexCount;
					vertexStart = faceGroup.patchSurf.VertexOffset;
				}
				else
				{
					// Unsupported face type
					return 0;
				}

				var idxSize = this.level.Indexes.IndexSize;
				var idxSrc = this.level.Indexes.Lock( idxStart*idxSize, numIdx*idxSize, BufferLocking.ReadOnly );
#if SILVERLIGHT
				var src = idxSrc.ToUShortPointer();
#else
				var src = idxSrc.ToUIntPointer();
#endif

				int maxIndex = 0;
				for ( int i = 0; i < numIdx; i++ )
				{
					var index = (int)src[ i ];
					if ( index > maxIndex )
					{
						maxIndex = index;
					}
				}

				var vertexPos = new Vector3[maxIndex + 1];
				var vertexIsStored = new bool[maxIndex + 1];

				for ( int i = 0; i < numIdx; i++ )
				{
					var index = (int)src[ i ];
					var pVertices = pVerticesBuf.ToBspVertexPointer();
					if ( !vertexIsStored[ index ] )
					{
						vertexPos[ index ] = pVertices[ vertexStart + index ].position;
						vertexIsStored[ index ] = true;
					}
					pVerticesBuf.UnPin();
				}

				Vector2[] texCoors;
				ColorEx[] colors;

				bool res = light.CalculateTexCoordsAndColors( faceGroup.plane, vertexPos, out texCoors, out colors );

				if ( res )
				{
					var pTexLightMaps = pTexLightMapsBuf.ToTextureLightMapPointer();
					for ( int i = 0; i <= maxIndex; i++ )
					{
						pTexLightMaps[ vertexStart + i ] = new TextureLightMap
						                                   {
						                                   	color = Root.Instance.RenderSystem.ConvertColor( colors[ i ] ),
						                                   	textureLightMap = texCoors[ i ]
						                                   };
					}
					pTexLightMapsBuf.UnPin();

					// Offset the indexes here
					// we have to do this now rather than up-front because the
					// indexes are sometimes reused to address different vertex chunks
					if ( this.level.Indexes.Type == IndexType.Size16 )
					{
						var pIndexes = pIndexesBuf.ToUShortPointer();
						for ( int i = 0; i < numIdx; i++ )
						{
							pIndexes[ i ] = (ushort)( src[ i ] + vertexStart );
						}
					}
					else
					{
						var pIndexes = pIndexesBuf.ToUIntPointer();
						for ( int i = 0; i < numIdx; i++ )
						{
							pIndexes[ i ] = (uint)( src[ i ] + vertexStart );
						}
					}
					this.level.Indexes.Unlock();

					// return number of elements
					return numIdx;
				}
				else
				{
					this.level.Indexes.Unlock();

					return 0;
				}
			}
		}
        private BspStaticFaceGroup CopyShaderFaceData(Quake3Level q3lvl, int face, Material shadMat, int shadIdx)
        {
            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 !!!");
            }
            return dest;
        }
		/// <summary>
		///		Caches a face group for imminent rendering.
		/// </summary>
		protected int CacheGeometry( BufferBase indexes, BspStaticFaceGroup faceGroup )
		{
			// Skip sky always
			if ( faceGroup.isSky )
			{
				return 0;
			}

			int idxStart = 0;
			int numIdx = 0;
			int vertexStart = 0;

			if ( faceGroup.type == FaceGroup.FaceList )
			{
				idxStart = faceGroup.elementStart;
				numIdx = faceGroup.numElements;
				vertexStart = faceGroup.vertexStart;
			}
			else if ( faceGroup.type == FaceGroup.Patch )
			{
				idxStart = faceGroup.patchSurf.IndexOffset;
				numIdx = faceGroup.patchSurf.CurrentIndexCount;
				vertexStart = faceGroup.patchSurf.VertexOffset;
			}
			else
			{
				// Unsupported face type
				return 0;
			}

#if !AXIOM_SAFE_ONLY
			unsafe
#endif
			{
				// Offset the indexes here
				// we have to do this now rather than up-front because the
				// indexes are sometimes reused to address different vertex chunks
				var idxSize = this.level.Indexes.IndexSize;
				var idxSrc = this.level.Indexes.Lock( idxStart*idxSize, numIdx*idxSize, BufferLocking.ReadOnly );
				if ( this.level.Indexes.Type == IndexType.Size16 )
				{
					var src = idxSrc.ToUShortPointer();
					var pIndexes = indexes.ToUShortPointer();
					for ( int i = 0; i < numIdx; i++ )
					{
						pIndexes[ i ] = (ushort)( src[ i ] + vertexStart );
					}
				}
				else
				{
					var src = idxSrc.ToUIntPointer();
					var pIndexes = indexes.ToUIntPointer();
					for ( int i = 0; i < numIdx; i++ )
					{
						pIndexes[ i ] = (uint)( src[ i ] + vertexStart );
					}
				}
				this.level.Indexes.Unlock();
			}

			// return number of elements
			return numIdx;
		}
Exemple #4
0
		/// <summary>
		///		Caches a face group and calculates texture lighting coordinates.
		/// </summary>
		unsafe protected int CacheLightGeometry( TextureLight light, uint* pIndexes, TextureLightMap* pTexLightMaps, BspVertex* pVertices, BspStaticFaceGroup faceGroup )
		{
			// Skip sky always
			if ( faceGroup.isSky )
				return 0;

			int idxStart = 0;
			int numIdx = 0;
			int vertexStart = 0;

			if ( faceGroup.type == FaceGroup.FaceList )
			{
				idxStart = faceGroup.elementStart;
				numIdx = faceGroup.numElements;
				vertexStart = faceGroup.vertexStart;
			}
			else if ( faceGroup.type == FaceGroup.Patch )
			{
				idxStart = faceGroup.patchSurf.IndexOffset;
				numIdx = faceGroup.patchSurf.CurrentIndexCount;
				vertexStart = faceGroup.patchSurf.VertexOffset;
			}
			else
			{
				// Unsupported face type
				return 0;
			}

			uint* src = (uint*)level.Indexes.Lock(
				idxStart * sizeof( uint ),
				numIdx * sizeof( uint ),
				BufferLocking.ReadOnly );

			int maxIndex = 0;
			for ( int i = 0; i < numIdx; i++ )
			{
				int index = (int)*( src + i );
				if ( index > maxIndex )
					maxIndex = index;
			}

			Vector3[] vertexPos = new Vector3[ maxIndex + 1 ];
			bool[] vertexIsStored = new bool[ maxIndex + 1 ];

			for ( int i = 0; i < numIdx; i++ )
			{
				uint index = *( src + i );
				if ( !vertexIsStored[ index ] )
				{
					vertexPos[ index ] = ( *( pVertices + vertexStart + index ) ).position;
					vertexIsStored[ index ] = true;
				}
			}

			Vector2[] texCoors;
			ColorEx[] colors;

			bool res = light.CalculateTexCoordsAndColors( faceGroup.plane, vertexPos, out texCoors, out colors );

			if ( res )
			{
				for ( int i = 0; i <= maxIndex; i++ )
				{
					pTexLightMaps[ vertexStart + i ].color = Root.Instance.RenderSystem.ConvertColor( colors[ i ] );
					pTexLightMaps[ vertexStart + i ].textureLightMap = texCoors[ i ];
				}

				// Offset the indexes here
				// we have to do this now rather than up-front because the
				// indexes are sometimes reused to address different vertex chunks
				for ( int i = 0; i < numIdx; i++ )
					*pIndexes++ = (uint)( *src++ + vertexStart );

				level.Indexes.Unlock();

				// return number of elements
				return numIdx;
			}
			else
			{
				level.Indexes.Unlock();

				return 0;
			}
		}
Exemple #5
0
		/// <summary>
		///		Caches a face group for imminent rendering.
		/// </summary>
		protected int CacheGeometry( IntPtr indexes, BspStaticFaceGroup faceGroup )
		{
			// Skip sky always
			if ( faceGroup.isSky )
				return 0;

			int idxStart = 0;
			int numIdx = 0;
			int vertexStart = 0;

			if ( faceGroup.type == FaceGroup.FaceList )
			{
				idxStart = faceGroup.elementStart;
				numIdx = faceGroup.numElements;
				vertexStart = faceGroup.vertexStart;
			}
			else if ( faceGroup.type == FaceGroup.Patch )
			{
				idxStart = faceGroup.patchSurf.IndexOffset;
				numIdx = faceGroup.patchSurf.CurrentIndexCount;
				vertexStart = faceGroup.patchSurf.VertexOffset;
			}
			else
			{
				// Unsupported face type
				return 0;
			}

			unsafe
			{
				uint* src = (uint*)level.Indexes.Lock(
					idxStart * sizeof( uint ),
					numIdx * sizeof( uint ),
					BufferLocking.ReadOnly );
				uint* pIndexes = (uint*)indexes;

				// Offset the indexes here
				// we have to do this now rather than up-front because the
				// indexes are sometimes reused to address different vertex chunks
				for ( int i = 0; i < numIdx; i++ )
					*pIndexes++ = (uint)( *src++ + vertexStart );

				level.Indexes.Unlock();
			}

			// return number of elements
			return numIdx;
		}
Exemple #6
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 );
		}
Exemple #7
0
        private BspStaticFaceGroup CopyShaderFaceData(Quake3Level q3lvl, int face, Material shadMat, int shadIdx)
        {
            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 !!!");
            }
            return(dest);
        }
Exemple #8
0
        private void CreateShaderMaterials(Quake3Level q3lvl, SceneManager sm)
        {
            // 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;

            while (face-- > 0)
            {
                // 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 = sm.GetMaterial(shaderName);

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

                if (shadMat == null)
                {
                    // Colour 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(sm, q3lvl.Faces[face].lmTexture);
                    }
                    else
                    {
                        // No shader script, try default type texture
                        shadMat = sm.CreateMaterial(shaderName);
                        Pass shadPass = shadMat.GetTechnique(0).GetPass(0);

                        // Try jpg
                        TextureUnitState tex = shadPass.CreateTextureUnitState(tryName + ".jpg");
                        tex.Load();

                        if (tex.IsBlank)
                        {
                            // Try tga
                            tex.SetTextureName(tryName + ".tga");
                        }

                        // Set replace on all first layer textures for now
                        tex.SetColorOperation(LayerBlendOperation.Replace);
                        tex.TextureAddressing = 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.TextureAddressing = TextureAddressing.Clamp;
                        }

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

                shadMat.Load();

                // Copy face data
                BspStaticFaceGroup dest = CopyShaderFaceData(q3lvl, face, shadMat, shadIdx);

                faceGroups[face] = dest;
            }
        }