/// <summary> /// Copy constructor. Creates a deep copy of another GModel. /// </summary> /// <param name="gm">GModel to clone.</param> public GModel(GModel gm) { model = gm.model; skinningData = gm.skinningData; Texture = gm.Texture; MaterialColors = gm.MaterialColors != null ? (Vector3[])gm.MaterialColors.Clone() : null; Emissive = gm.Emissive; EmissiveTexture = gm.EmissiveTexture; IsWaterfall = gm.IsWaterfall; }
/// <summary> /// Draw forward-rendered model. /// </summary> /// <param name="model">Model to draw</param> /// <param name="position">Position</param> /// <param name="rotation">Rotation</param> /// <param name="scale">Scale (x, y, z)</param> /// <param name="enableShading">Enables textures and lighting</param> private void DrawForwardShadedModel( GModel gmodel, ref Vector3 position, ref Quaternion rotation, ref Vector3 scale, bool enableShading) { Model model = gmodel.model; // Calculate transforms Matrix world = Matrix.CreateScale(scale) * Matrix.CreateFromQuaternion(rotation) * Matrix.CreateTranslation(position); Matrix[] meshTransforms = new Matrix[model.Bones.Count]; model.CopyAbsoluteBoneTransformsTo(meshTransforms); // get bone transforms // Render the mesh foreach (ModelMesh mesh in model.Meshes) { // Set effect data Matrix animatedWorld = meshTransforms[mesh.ParentBone.Index] * world; Matrix worldViewProjection = animatedWorld * camera.View * camera.Projection; forwardUnshadedEffect.Parameters["xDepthTex"].SetValue(deferredTargets[1].RenderTarget); forwardUnshadedEffect.Parameters["xWorld"].SetValue(animatedWorld); forwardUnshadedEffect.Parameters["xWorldViewProjection"].SetValue(worldViewProjection); // Draw forwardUnshadedEffect.CurrentTechnique.Passes[0].Apply(); // single-pass foreach (ModelMeshPart part in mesh.MeshParts) { Device.Indices = part.IndexBuffer; Device.SetVertexBuffer(part.VertexBuffer); Device.DrawIndexedPrimitives( PrimitiveType.TriangleList, part.VertexOffset, 0, part.NumVertices, part.StartIndex, part.PrimitiveCount); // draw call count nDrawCalls++; } } }
/// <summary> /// Draws models, shaded or unshaded. Contains the actual drawing code. /// </summary> /// <param name="model">Model to draw</param> /// <param name="position">Position</param> /// <param name="rotation">Rotation</param> /// <param name="scale">Scale (x, y, z)</param> /// <param name="enableShading">Enables textures and lighting</param> private void DrawDeferredShadedModel( GModel gmodel, ref Vector3 position, ref Quaternion rotation, ref Vector3 scale, bool enableShading, Matrix[] bones) { Model model = gmodel.model; // Calculate transforms Matrix world = Matrix.CreateScale(scale) * Matrix.CreateFromQuaternion(rotation) * Matrix.CreateTranslation(position); Matrix[] meshTransforms = new Matrix[model.Bones.Count]; model.CopyAbsoluteBoneTransformsTo(meshTransforms); // get bone transforms // Set effect Effect effect; if (model.Tag is SkinningData && bones != null) { deferredSkinnedEffect.CurrentTechnique = deferredSkinnedEffect.Techniques["DeferredSkinned"]; effect = deferredSkinnedEffect; effect.Parameters["xBones"].SetValue(bones); } else if (gmodel.Texture != null && renderState == RenderState.Deferred) { effect = deferredTextureEffect; effect.Parameters["xTexture"].SetValue(gmodel.Texture); } else if (renderState == RenderState.Deferred) { deferredEffect.CurrentTechnique = deferredEffect.Techniques["Deferred"]; effect = deferredEffect; } else // shadow { deferredEffect.CurrentTechnique = deferredEffect.Techniques["DeferredLightMap"]; effect = deferredEffect; } // Emissive if (gmodel.EmissiveTexture != null) { effect.Parameters["xEnableEmissiveTexture"].SetValue(1); effect.Parameters["xEmissiveTex"].SetValue(gmodel.EmissiveTexture); effect.Parameters["xEmissive"].SetValue(gmodel.Emissive); } else { effect.Parameters["xEnableEmissiveTexture"].SetValue(0); effect.Parameters["xEmissive"].SetValue(gmodel.Emissive); } // Render the mesh int iMeshColor = 0; effect.Parameters["xWorld"].SetValue(world); foreach (ModelMesh mesh in model.Meshes) { if (bones != null) effect.Parameters["xBone"].SetValue(bones[mesh.ParentBone.Index]); else effect.Parameters["xBone"].SetValue(meshTransforms[mesh.ParentBone.Index]); foreach (ModelMeshPart part in mesh.MeshParts) { if (gmodel.MaterialColors != null) effect.Parameters["xColor"].SetValue(gmodel.MaterialColors[iMeshColor++]); effect.CurrentTechnique.Passes[0].Apply(); // Deferred and DeferredTextured are both single-pass Device.Indices = part.IndexBuffer; Device.SetVertexBuffer(part.VertexBuffer); Device.DrawIndexedPrimitives( PrimitiveType.TriangleList, part.VertexOffset, 0, part.NumVertices, part.StartIndex, part.PrimitiveCount); // draw call count nDrawCalls++; } } }
/// <summary> /// Loads a model from a file and places it in the models dictionary. /// </summary> /// <param name="fileName">Path to model</param> /// <param name="texture">Texture override (null for default)</param> /// <param name="emissiveTexture">Emissive texture (or null)</param> protected override GModel LoadModel(string fileName, string texture, string emissiveTexture) { GModel gmodel; // Check for pre-existence List<GModel> modelList; if (models.ContainsKey(fileName)) { modelList = models[fileName]; // Find GModel if it exists foreach (GModel listModel in modelList) { if (listModel.TexturePath == texture && listModel.EmissivePath == emissiveTexture) { return listModel; } } // Didn't find, copy an existing model gmodel = new GModel(modelList[0]); } else { gmodel = new GModel(); modelList = new List<GModel>(); modelList.Add(gmodel); models.Add(fileName, modelList); // Load model gmodel.model = content.Load<Model>(fileName); gmodel.Texture = null; //Load skinning and animation (null if none) gmodel.skinningData = gmodel.model.Tag as SkinningData; } // Assign texture if one is provided if (texture != null) { gmodel.Texture = content.Load<Texture2D>(texture); gmodel.MaterialColors = null; } // Else, check for materials and textures LinkedList<Vector3> colors = new LinkedList<Vector3>(); foreach (ModelMesh mesh in gmodel.model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { BasicEffect be = part.Effect as BasicEffect; if (be != null && be.TextureEnabled) { gmodel.Texture = be.Texture; // only one texture supported } else { colors.AddLast(be != null ? be.DiffuseColor : Vector3.One); } } } gmodel.MaterialColors = gmodel.Texture == null ? colors.ToArray() : null; gmodel.EmissiveTexture = null; if (emissiveTexture != null) gmodel.EmissiveTexture = content.Load<Texture2D>(emissiveTexture); gmodel.Emissive = 0; // HACK: workaround for the lack of a materials system gmodel.IsWaterfall = (fileName == @"MapObjects\RttT\models\waterfall-1"); return gmodel; }
/// <summary> /// Draws a character's shield. /// </summary> /// <param name="shieldModel">Model</param> /// <param name="position">Center position</param> /// <param name="scale">Scale</param> public override void DrawShield(GModel shieldModel, Vector3 position, float scale) { // Rasterizer state settings if (Device.RasterizerState.FillMode != FillMode.Solid) { RasterizerState rs = new RasterizerState(); rs.FillMode = FillMode.Solid; rs.CullMode = CullMode.CullCounterClockwiseFace; Device.RasterizerState = rs; } Device.BlendState = BlendState.Additive; // Parameters Matrix world = Matrix.CreateScale(scale) * Matrix.CreateTranslation(position); shieldEffect.Parameters["xWorld"].SetValue(world); shieldEffect.Parameters["xShieldTex"].SetValue(shieldModel.Texture); // Draw shieldEffect.CurrentTechnique.Passes[0].Apply(); // single-pass foreach (ModelMeshPart part in shieldModel.model.Meshes[0].MeshParts) { Device.Indices = part.IndexBuffer; Device.SetVertexBuffer(part.VertexBuffer); Device.DrawIndexedPrimitives( PrimitiveType.TriangleList, part.VertexOffset, 0, part.NumVertices, part.StartIndex, part.PrimitiveCount); // draw call count nDrawCalls++; } }
/// <summary> /// Draws a model with deferred shading. /// </summary> /// <param name="gmodel">Model info</param> /// <param name="position">Position</param> /// <param name="rotation">Rotation</param> /// <param name="scale">Scale</param> /// <param name="bones">Animation data.</param> public override void DrawModel(GModel gmodel, Vector3 position, Quaternion rotation, Vector3 scale, Matrix[] bones) { // Rasterizer state settings if (renderState == RenderState.Deferred && Device.RasterizerState.FillMode != FillMode.Solid) { RasterizerState rs = new RasterizerState(); rs.FillMode = FillMode.Solid; rs.CullMode = CullMode.CullCounterClockwiseFace; Device.RasterizerState = rs; } DrawDeferredShadedModel(gmodel, ref position, ref rotation, ref scale, true, bones); }
/// <summary> /// Draws a model with deferred shading. /// </summary> /// <param name="gmodel">Model info</param> /// <param name="position">Position</param> /// <param name="rotation">Rotation</param> /// <param name="scale">Scale</param> /// <param name="bones">Animation data.</param> public override void DrawModel(GModel gmodel, Vector3 position, Quaternion rotation, float scale, Matrix[] bones) { DrawModel(gmodel, position, rotation, new Vector3(scale), bones); }
/// <summary> /// Draws a model with deferred shading. /// </summary> /// <param name="model">Model</param> /// <param name="position">Position</param> /// <param name="rotation">Model rotation</param> public override void DrawModel(GModel gmodel, Vector3 position, Quaternion rotation, float scale) { DrawModel(gmodel, position, rotation, new Vector3(scale), null); }
/// <summary> /// Uses geometry instancing to draw several models. Models must have one /// ModelMesh with a single ModelMeshPart. /// </summary> /// <param name="model">Model</param> /// <param name="transforms">Transform data</param> /// <param name="nPlatforms">Number of transforms</param> public override void DrawInstancedPlatforms(GModel gmodel, Matrix[] transforms, int nPlatforms) { // The single mesh part being drawn. ModelMeshPart meshPart = gmodel.model.Meshes[0].MeshParts[0]; if (instanceBuffer == null || instanceBuffer.VertexCount < nPlatforms) { if (instanceBuffer != null) instanceBuffer.Dispose(); instanceBuffer = new DynamicVertexBuffer(Device, instanceDeclaration, nPlatforms, BufferUsage.WriteOnly); } // Draw model Device.RasterizerState = RasterizerState.CullCounterClockwise; // Upload instance transform data Device.SetVertexBuffers(); instanceBuffer.SetData(transforms, 0, nPlatforms, SetDataOptions.Discard); Device.SetVertexBuffers( new VertexBufferBinding(meshPart.VertexBuffer), new VertexBufferBinding(instanceBuffer, 0, 1) ); Device.Indices = meshPart.IndexBuffer; if (gmodel.Texture != null && renderState == RenderState.Deferred) { instanceEffect.CurrentTechnique = instanceEffect.Techniques["DeferredInstancedTextured"]; instanceEffect.Parameters["xTexture"].SetValue(gmodel.Texture); } else if (renderState == RenderState.Deferred) { instanceEffect.CurrentTechnique = instanceEffect.Techniques["DeferredInstanced"]; instanceEffect.Parameters["xColor"].SetValue(gmodel.MaterialColors[0]); } else { instanceEffect.CurrentTechnique = instanceEffect.Techniques["DeferredInstancedLight"]; } // Emissive if (gmodel.EmissiveTexture != null) { instanceEffect.Parameters["xEnableEmissiveTexture"].SetValue(1); instanceEffect.Parameters["xEmissiveTex"].SetValue(gmodel.EmissiveTexture); instanceEffect.Parameters["xEmissive"].SetValue(gmodel.Emissive); } else { instanceEffect.Parameters["xEnableEmissiveTexture"].SetValue(0); instanceEffect.Parameters["xEmissive"].SetValue(gmodel.Emissive); } instanceEffect.Parameters["xTextureOffset"].SetValue( gmodel.IsWaterfall ? waterfallTimer / waterfallPeriod : 0); instanceEffect.CurrentTechnique.Passes[0].Apply(); Device.DrawInstancedPrimitives( PrimitiveType.TriangleList, 0, 0, meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount, nPlatforms); }
/// <summary> /// Draws a character's shield. /// </summary> /// <param name="shieldModel">Model</param> /// <param name="position">Center position</param> /// <param name="scale">Scale</param> public abstract void DrawShield(GModel shieldModel, Vector3 position, float scale);
/// <summary> /// Draws a model with a basic shader. /// </summary> /// <param name="model">Model</param> /// <param name="position">Position</param> /// <param name="rotation">Model rotation</param> /// <param name="scale">Model scaling</param> public abstract void DrawModel(GModel gmodel, Vector3 position, Quaternion rotation, Vector3 scale, Matrix[] bones);
/// <summary> /// Draws a model with a basic shader. /// </summary> /// <param name="model">Model</param> /// <param name="position">Position</param> /// <param name="rotation">Model rotation</param> public abstract void DrawModel(GModel gmodel, Vector3 position, Quaternion rotation, float scale);
/// <summary> /// Uses geometry instancing to draw several models. Models must have one /// ModelMesh with a single ModelMeshPart. /// </summary> /// <param name="model">Model</param> /// <param name="transforms">Transform data</param> /// <param name="nPlatforms">Number of transforms</param> public abstract void DrawInstancedPlatforms(GModel model, Matrix[] transforms, int nPlatforms);