/// <summary> /// Loads a Daggerfall flat (billboard). /// </summary> /// <param name="textureArchive">Texture archive index.</param> /// <param name="textureRecord">Texture record index.</param> /// <param name="textureFlags">Texture create flags.</param> /// <param name="material">Material.</param> /// <param name="startSize">Start size before scaling.</param> /// <param name="finalSize">Final size after scaling.</param> private void LoadDaggerfallFlat( int textureArchive, int textureRecord, MaterialManager.TextureCreateFlags textureFlags, out BaseMaterialEffect material, out Vector2 startSize, out Vector2 finalSize) { // Get path to texture file string path = Path.Combine( core.MaterialManager.Arena2Path, TextureFile.IndexToFileName(textureArchive)); // Get size and scale of this texture System.Drawing.Size size = TextureFile.QuickSize(path, textureRecord); System.Drawing.Size scale = TextureFile.QuickScale(path, textureRecord); // Set start size startSize.X = size.Width; startSize.Y = size.Height; // Apply scale int xChange = (int)(size.Width * (scale.Width / BlocksFile.ScaleDivisor)); int yChange = (int)(size.Height * (scale.Height / BlocksFile.ScaleDivisor)); finalSize.X = size.Width + xChange; finalSize.Y = size.Height + yChange; // Load material material = core.MaterialManager.CreateDaggerfallMaterialEffect( textureArchive, textureRecord, renderBillboards, MaterialManager.DefaultBillboardFlags); }
/// <summary> /// Loads a Daggerfall texture as a billboard. /// </summary> /// <param name="archive">Texture archive.</param> /// <param name="record">Texture record.</param> /// <param name="flat">Flat data.</param> public void LoadBillboard(DaggerfallBlockComponent.BlockFlat flat) { // Get path to texture file string path = Path.Combine( core.MaterialManager.Arena2Path, TextureFile.IndexToFileName(flat.Archive)); // Get size and scale of this texture System.Drawing.Size size = TextureFile.QuickSize(path, flat.Record); System.Drawing.Size scale = TextureFile.QuickScale(path, flat.Record); // Set start size Vector2 startSize; startSize.X = size.Width; startSize.Y = size.Height; // Apply scale Vector2 finalSize; int xChange = (int)(size.Width * (scale.Width / BlocksFile.ScaleDivisor)); int yChange = (int)(size.Height * (scale.Height / BlocksFile.ScaleDivisor)); finalSize.X = (size.Width + xChange); finalSize.Y = (size.Height + yChange); finalSize *= ModelManager.GlobalScale; // Load material this.material = core.MaterialManager.CreateDaggerfallMaterialEffect( flat.Archive, flat.Record, null, MaterialManager.DefaultBillboardFlags); // Save settings this.size = finalSize; // Calcuate offset for correct positioning in scene if (flat.Dungeon) { this.offset = Vector3.Zero; } else { this.offset = new Vector3(0, (finalSize.Y / 2) - (4 * ModelManager.GlobalScale), 0); } // Set bounding sphere BoundingSphere sphere; sphere.Center = Vector3.Zero; if (finalSize.X > finalSize.Y) { sphere.Radius = finalSize.X / 2; } else { sphere.Radius = finalSize.Y / 2; } this.BoundingSphere = sphere; }
/// <summary> /// Loads model data from DFMesh. /// </summary> /// <param name="id">Key of source mesh.</param> /// <param name="modelData">ModelData out.</param> /// <returns>True if successful.</returns> private bool LoadModelData(uint id, out ModelData modelData) { // Return from cache if present if (cacheModelData && modelDataDict.ContainsKey(id)) { modelData = modelDataDict[id]; return(true); } // New model object modelData = new ModelData(); // Find mesh index int index = arch3dFile.GetRecordIndex(id); if (index == -1) { return(false); } // Get DFMesh DFMesh dfMesh = arch3dFile.GetMesh(index); if (dfMesh.TotalVertices == 0) { return(false); } // Load mesh data modelData.DFMesh = dfMesh; LoadVertices(ref modelData); LoadIndices(ref modelData); AddModelTangents(ref modelData); CreateModelBuffers(graphicsDevice, ref modelData); // Load materials for (int i = 0; i < modelData.SubMeshes.Length; i++) { // Create material BaseMaterialEffect material = CreateModelMaterial( modelData.DFMesh.SubMeshes[i].TextureArchive, modelData.DFMesh.SubMeshes[i].TextureRecord); // Save key in submesh modelData.SubMeshes[i].MaterialKey = material.ID; } // Add to cache if (cacheModelData) { modelDataDict.Add(id, modelData); } return(true); }
/// <summary> /// Submit a billboard to be drawn in GBuffer. /// </summary> /// <param name="material">Material used when rendering the billboard.</param> /// <param name="position">Position of billboard in world space.</param> /// <param name="size">Dimensions of billboard.</param> public void SubmitBillboard(BaseMaterialEffect material, Vector3 position, Vector2 size) { if (visibleBillboardsCount < maxVisibleBillboards) { // Add billboard to array visibleBillboards[visibleBillboardsCount].Material = material; visibleBillboards[visibleBillboardsCount].Position = position; visibleBillboards[visibleBillboardsCount].Size = size; visibleBillboardsCount++; } }
/// <summary> /// Draws the component. /// </summary> /// <param name="caller">Entity calling the draw operation.</param> public override void Draw(BaseEntity caller) { // Do nothing if no static geometry if (staticGeometry == null) { return; } // Do nothing if no batches or component is disabled if (staticGeometry.StaticBatches == null || !enabled) { return; } // Calculate world matrix Matrix worldMatrix = matrix * caller.Matrix; // Set transforms core.ModelManager.ModelEffect_World = worldMatrix; core.ModelManager.ModelEffect_View = core.ActiveScene.Camera.ViewMatrix; core.ModelManager.ModelEffect_Projection = core.ActiveScene.Camera.ProjectionMatrix; // Set buffers core.GraphicsDevice.SetVertexBuffer(staticGeometry.VertexBuffer); core.GraphicsDevice.Indices = staticGeometry.IndexBuffer; // Draw batches foreach (var item in staticGeometry.StaticBatches) { // Apply material BaseMaterialEffect materialEffect = core.MaterialManager.GetMaterialEffect(item.Key); materialEffect.Apply(); // Render geometry foreach (EffectPass pass in materialEffect.Effect.CurrentTechnique.Passes) { // Apply effect pass pass.Apply(); // Draw primitives core.GraphicsDevice.DrawIndexedPrimitives( PrimitiveType.TriangleList, 0, 0, staticGeometry.VertexBuffer.VertexCount, item.Value.StartIndex, item.Value.PrimitiveCount); } } }
/// <summary> /// Draws component. /// </summary> /// <param name="caller">Entity calling the draw operation.</param> public override void Draw(BaseEntity caller) { // Do nothing if disabled or no model data if (!enabled || modelData == null) { return; } // Exit if model data is empty if (modelData.SubMeshes == null) { return; } // Calculate world matrix Matrix worldMatrix = matrix * caller.Matrix; // Set transforms core.ModelManager.ModelEffect_World = worldMatrix; core.ModelManager.ModelEffect_View = core.ActiveScene.Camera.ViewMatrix; core.ModelManager.ModelEffect_Projection = core.ActiveScene.Camera.ProjectionMatrix; // Set buffers core.GraphicsDevice.SetVertexBuffer(modelData.VertexBuffer); core.GraphicsDevice.Indices = modelData.IndexBuffer; // Draw batches foreach (var sm in modelData.SubMeshes) { // Apply material BaseMaterialEffect materialEffect = core.MaterialManager.GetMaterialEffect(sm.MaterialKey); materialEffect.Apply(); // Render geometry foreach (EffectPass pass in materialEffect.Effect.CurrentTechnique.Passes) { // Apply effect pass pass.Apply(); // Draw indexed primitives core.GraphicsDevice.DrawIndexedPrimitives( PrimitiveType.TriangleList, 0, 0, modelData.VertexBuffer.VertexCount, sm.StartIndex, sm.PrimitiveCount); } } }
/// <summary> /// Creates a new Daggerfall texture material. /// </summary> /// <param name="archive">Texture archive.</param> /// <param name="record">Texture record.</param> /// <returns>BaseMaterialEffect</returns> public BaseMaterialEffect CreateModelMaterial(int archive, int record) { // Create default material effect BaseMaterialEffect material = materialManager.CreateDaggerfallMaterialEffect( archive, record, modelEffect, MaterialManager.DefaultModelFlags); // Setup material effect material.Technique = modelEffect.Techniques["Default"]; material.DiffuseTextureParam = modelEffect.Parameters["Texture"]; return(material); }
/// <summary> /// Adds exterior ground tiles to the batch. /// </summary> /// <param name="blockData">Block data.</param> private void AddRMBGroundTiles(ref DFBlock blockData) { // Make ground slightly lower to minimise depth-fighting on ground aligned polygons const float groundHeight = 0f; // Corner positions Vector3 topLeftPos, topRightPos, bottomLeftPos, bottomRightPos; Vector2 topLeftUV, topRightUV, bottomLeftUV, bottomRightUV; // Create vertices. These will be updated for each tile based on position and UV orientation. VertexPositionNormalTextureBump[] vertices = new VertexPositionNormalTextureBump[4]; // Create indices. These are the same for every tile. int[] indices = new int[] { 0, 1, 2, 1, 3, 2 }; // Loop through tiles int tileCount = 16; float tileDimension = 256.0f * ModelManager.GlobalScale; for (int y = 0; y < tileCount; y++) { for (int x = 0; x < tileCount; x++) { // Get source tile data DFBlock.RmbGroundTiles tile = blockData.RmbBlock.FldHeader.GroundData.GroundTiles[x, y]; // Set random terrain marker back to grass int textureRecord = (tile.TextureRecord > 55) ? 2 : tile.TextureRecord; // Create material BaseMaterialEffect material = core.ModelManager.CreateModelMaterial( (int)DFLocation.ClimateTextureSet.Exterior_Terrain, textureRecord); material.SamplerState0 = SamplerState.AnisotropicClamp; // Create vertices for this quad topLeftPos = new Vector3(x * tileDimension, groundHeight, y * tileDimension); topRightPos = new Vector3(topLeftPos.X + tileDimension, groundHeight, topLeftPos.Z); bottomLeftPos = new Vector3(topLeftPos.X, groundHeight, topLeftPos.Z + tileDimension); bottomRightPos = new Vector3(topLeftPos.X + tileDimension, groundHeight, topLeftPos.Z + tileDimension); // Set UVs if (tile.IsRotated && !tile.IsFlipped) { // Rotate only topLeftUV = new Vector2(1, 0); topRightUV = new Vector2(1, 1); bottomLeftUV = new Vector2(0, 0); bottomRightUV = new Vector2(0, 1); } else if (tile.IsFlipped && !tile.IsRotated) { // Flip only topLeftUV = new Vector2(1, 1); topRightUV = new Vector2(0, 1); bottomLeftUV = new Vector2(1, 0); bottomRightUV = new Vector2(0, 0); } else if (tile.IsRotated && tile.IsRotated) { // Rotate and flip topLeftUV = new Vector2(0, 1); topRightUV = new Vector2(0, 0); bottomLeftUV = new Vector2(1, 1); bottomRightUV = new Vector2(1, 0); } else { // No rotate or flip topLeftUV = new Vector2(0, 0); topRightUV = new Vector2(1, 0); bottomLeftUV = new Vector2(0, 1); bottomRightUV = new Vector2(1, 1); } // Set vertices vertices[0] = new VertexPositionNormalTextureBump(topLeftPos, Vector3.Up, topLeftUV, Vector3.Zero, Vector3.Zero); vertices[1] = new VertexPositionNormalTextureBump(topRightPos, Vector3.Up, topRightUV, Vector3.Zero, Vector3.Zero); vertices[2] = new VertexPositionNormalTextureBump(bottomLeftPos, Vector3.Up, bottomLeftUV, Vector3.Zero, Vector3.Zero); vertices[3] = new VertexPositionNormalTextureBump(bottomRightPos, Vector3.Up, bottomRightUV, Vector3.Zero, Vector3.Zero); // Add to builder staticGeometry.AddToBuilder(material.ID, vertices, indices, Matrix.Identity); } } }