/// <summary> /// Renders a single frame of the scene. /// </summary> public void render() { device.Clear(ClearFlags.Stencil | ClearFlags.Target | ClearFlags.ZBuffer, cfgBackColor, 1f, 15); device.SetTexture(0, null); device.BeginScene(); float fovy = (float)Math.PI / 4; float aspectRatio = (float)pParams.BackBufferWidth / pParams.BackBufferHeight; device.Transform.Projection = Matrix.PerspectiveFovLH(fovy, aspectRatio, 0.01f, 1000f); device.Transform.View = Matrix.LookAtLH( new Vector3(0f, 0f, 20f), new Vector3(0f, 0f, 0f), new Vector3(0f, 1f, 0f)); //View RenderBase.OVector3 minVector = new RenderBase.OVector3(); RenderBase.OVector3 maxVector = new RenderBase.OVector3(); if (currentModel > -1) { minVector = models.model[currentModel].minVector; maxVector = models.model[currentModel].maxVector; } float minSize = Math.Min(Math.Min(minVector.x, minVector.y), minVector.z); float maxSize = Math.Max(Math.Max(maxVector.x, maxVector.y), maxVector.z); float scale = (10f / (maxSize - minSize)); //Try to adjust to screen if (maxSize - minSize == 0) scale = 1; Matrix centerMatrix = Matrix.Translation( -(minVector.x + maxVector.x) / 2, -(minVector.y + maxVector.y) / 2, -(minVector.z + maxVector.z) / 2); Matrix translationMatrix = Matrix.Translation( (-translation.X / 50) / scale, (translation.Y / 50) / scale, zoom / scale); Matrix baseTransform = Matrix.Identity; baseTransform *= Matrix.RotationY(rotation.Y) * Matrix.RotationX(rotation.X); baseTransform *= centerMatrix * translationMatrix * Matrix.Scaling(-scale, scale, scale); //Grid if (cfgShowGuidelines) { resetRenderState(); device.Transform.World = baseTransform; device.VertexFormat = CustomVertex.PositionColored.Format; using (VertexBuffer buffer = new VertexBuffer(typeof(CustomVertex.PositionColored), gridBuffer.Length, device, Usage.None, CustomVertex.PositionColored.Format, Pool.Managed)) { buffer.SetData(gridBuffer, 0, LockFlags.None); device.SetStreamSource(0, buffer, 0); device.DrawPrimitives(PrimitiveType.LineList, 0, gridBuffer.Length / 2); } } if (fragmentShaderMode) { fragmentShader.Begin(0); fragmentShader.SetValue("world", device.Transform.World); fragmentShader.SetValue("view", device.Transform.View); fragmentShader.SetValue("projection", device.Transform.Projection); fragmentShader.SetValue("lights[0].pos", new Vector4(0, -10, -10, 0)); fragmentShader.SetValue("lights[0].ambient", new Vector4(0.1f, 0.1f, 0.1f, 1)); fragmentShader.SetValue("lights[0].diffuse", new Vector4(1, 1, 1, 1)); fragmentShader.SetValue("lights[0].specular", new Vector4(1, 1, 1, 1)); fragmentShader.SetValue("numLights", 1); } if (cfgWireframeMode) device.RenderState.FillMode = FillMode.WireFrame; else device.RenderState.FillMode = FillMode.Solid; if (currentModel > -1) { RenderBase.OModel mdl = models.model[currentModel]; device.Transform.World = getMatrix(mdl.transform) * baseTransform; #region "Skeletal Animation" Matrix[] animationSkeletonTransform = new Matrix[mdl.skeleton.Count]; if (ctrlSA.animate) { Matrix[] skeletonTransform = new Matrix[mdl.skeleton.Count]; for (int index = 0; index < mdl.skeleton.Count; index++) { skeletonTransform[index] = Matrix.Identity; transformSkeleton(mdl.skeleton, index, ref skeletonTransform[index]); } List<RenderBase.OSkeletalAnimationBone> bone = ((RenderBase.OSkeletalAnimation)models.skeletalAnimation.list[ctrlSA.CurrentAnimation]).bone; List<OAnimationBone> frameAnimationSkeleton = new List<OAnimationBone>(); for (int index = 0; index < mdl.skeleton.Count; index++) { OAnimationBone newBone = new OAnimationBone(); newBone.parentId = mdl.skeleton[index].parentId; newBone.rotationQuaternion = getQuaternion(mdl.skeleton[index].rotation); newBone.translation = new RenderBase.OVector3(mdl.skeleton[index].translation); newBone.scale = new RenderBase.OVector3(1, 1, 1); foreach (RenderBase.OSkeletalAnimationBone b in bone) { if (b.name == mdl.skeleton[index].name) { if (b.isFullBakedFormat) { newBone.hasTransform = true; newBone.transform = b.transform[(int)ctrlSA.Frame % b.transform.Count]; } else if (b.isFrameFormat) { float fl = (float)Math.Floor(ctrlSA.Frame); float fr = (float)Math.Ceiling(ctrlSA.Frame); float mu = ctrlSA.Frame - fl; if (b.scale.exists) { int il = Math.Min((int)fl, b.scale.vector.Count - 1); int ir = Math.Min((int)fr, b.scale.vector.Count - 1); RenderBase.OVector4 sl = b.scale.vector[il]; RenderBase.OVector4 sr = b.scale.vector[ir]; RenderBase.OVector4 s = AnimationUtils.interpolateLinear(sl, sr, mu); newBone.scale = new RenderBase.OVector3(s.x, s.y, s.z); } if (b.rotationQuaternion.exists) { int il = Math.Min((int)fl, b.rotationQuaternion.vector.Count - 1); int ir = Math.Min((int)fr, b.rotationQuaternion.vector.Count - 1); Quaternion ql = getQuaternion(b.rotationQuaternion.vector[il]); Quaternion qr = getQuaternion(b.rotationQuaternion.vector[ir]); newBone.rotationQuaternion = Quaternion.Slerp(ql, qr, mu); } if (b.translation.exists) { int il = Math.Min((int)fl, b.translation.vector.Count - 1); int ir = Math.Min((int)fr, b.translation.vector.Count - 1); RenderBase.OVector4 tl = b.translation.vector[il]; RenderBase.OVector4 tr = b.translation.vector[ir]; RenderBase.OVector4 t = AnimationUtils.interpolateLinear(tl, tr, mu); newBone.translation = new RenderBase.OVector3(t.x, t.y, t.z); newBone.translation.x *= mdl.skeleton[index].absoluteScale.x; newBone.translation.y *= mdl.skeleton[index].absoluteScale.y; newBone.translation.z *= mdl.skeleton[index].absoluteScale.z; } } else { //Rotation float fl = (float)Math.Floor(ctrlSA.Frame); float fr = (float)Math.Ceiling(ctrlSA.Frame); float mu = ctrlSA.Frame - fl; RenderBase.OVector3 vl = new RenderBase.OVector3(mdl.skeleton[index].rotation); RenderBase.OVector3 vr = new RenderBase.OVector3(mdl.skeleton[index].rotation); if (b.rotationX.exists) { vl.x = AnimationUtils.getKey(b.rotationX, fl); vr.x = AnimationUtils.getKey(b.rotationX, fr); } if (b.rotationY.exists) { vl.y = AnimationUtils.getKey(b.rotationY, fl); vr.y = AnimationUtils.getKey(b.rotationY, fr); } if (b.rotationZ.exists) { vl.z = AnimationUtils.getKey(b.rotationZ, fl); vr.z = AnimationUtils.getKey(b.rotationZ, fr); } Quaternion ql = getQuaternion(vl); Quaternion qr = getQuaternion(vr); newBone.rotationQuaternion = Quaternion.Slerp(ql, qr, mu); //Translation if (b.translationX.exists) { newBone.translation.x = AnimationUtils.getKey(b.translationX, ctrlSA.Frame); newBone.translation.x *= mdl.skeleton[index].absoluteScale.x; } if (b.translationY.exists) { newBone.translation.y = AnimationUtils.getKey(b.translationY, ctrlSA.Frame); newBone.translation.y *= mdl.skeleton[index].absoluteScale.y; } if (b.translationZ.exists) { newBone.translation.z = AnimationUtils.getKey(b.translationZ, ctrlSA.Frame); newBone.translation.z *= mdl.skeleton[index].absoluteScale.z; } } break; } } frameAnimationSkeleton.Add(newBone); } for (int index = 0; index < mdl.skeleton.Count; index++) { animationSkeletonTransform[index] = Matrix.Identity; if (frameAnimationSkeleton[index].hasTransform) animationSkeletonTransform[index] = getMatrix(frameAnimationSkeleton[index].transform); else { animationSkeletonTransform[index] *= Matrix.Scaling( frameAnimationSkeleton[index].scale.x, frameAnimationSkeleton[index].scale.y, frameAnimationSkeleton[index].scale.z); int id = index; while (id > -1) { RenderBase.OVector3 t = new RenderBase.OVector3(frameAnimationSkeleton[id].translation); if (frameAnimationSkeleton[id].parentId > -1) t *= frameAnimationSkeleton[frameAnimationSkeleton[id].parentId].scale; animationSkeletonTransform[index] *= Matrix.RotationQuaternion(frameAnimationSkeleton[id].rotationQuaternion); animationSkeletonTransform[index] *= Matrix.Translation(t.x, t.y, t.z); id = frameAnimationSkeleton[id].parentId; } } animationSkeletonTransform[index] = Matrix.Invert(skeletonTransform[index]) * animationSkeletonTransform[index]; } } #endregion for (int objectIndex = 0; objectIndex < mdl.mesh.Count; objectIndex++) { RenderBase.OMesh obj = mdl.mesh[objectIndex]; bool isVisible = obj.isVisible; if (ctrlVA.animate) { foreach (RenderBase.OVisibilityAnimationData data in ((RenderBase.OVisibilityAnimation)models.visibilityAnimation.list[ctrlVA.CurrentAnimation]).data) { RenderBase.OAnimationKeyFrame frame = AnimationUtils.getLeftFrame(data.visibilityList.keyFrames, ctrlVA.Frame); if (data.name == obj.name) isVisible = frame.bValue; } } if (!(isVisible || cfgShowAllMeshes)) continue; RenderBase.OMaterial material = mdl.material[obj.materialId]; #region "Material Animation" int[] textureId = { -1, -1, -1 }; Color blendColor = material.fragmentOperation.blend.blendColor; Color[] borderColor = new Color[3]; borderColor[0] = material.textureMapper[0].borderColor; borderColor[1] = material.textureMapper[1].borderColor; borderColor[2] = material.textureMapper[2].borderColor; if (ctrlMA.animate) { foreach (RenderBase.OMaterialAnimationData data in ((RenderBase.OMaterialAnimation)models.materialAnimation.list[ctrlMA.CurrentAnimation]).data) { if (data.name == material.name) { switch (data.type) { case RenderBase.OMaterialAnimationType.textureMapper0: getMaterialAnimationInt(data, ref textureId[0]); break; case RenderBase.OMaterialAnimationType.textureMapper1: getMaterialAnimationInt(data, ref textureId[1]); break; case RenderBase.OMaterialAnimationType.textureMapper2: getMaterialAnimationInt(data, ref textureId[2]); break; case RenderBase.OMaterialAnimationType.borderColorMapper0: getMaterialAnimationColor(data, ref borderColor[0]); break; case RenderBase.OMaterialAnimationType.borderColorMapper1: getMaterialAnimationColor(data, ref borderColor[1]); break; case RenderBase.OMaterialAnimationType.borderColorMapper2: getMaterialAnimationColor(data, ref borderColor[2]); break; case RenderBase.OMaterialAnimationType.blendColor: getMaterialAnimationColor(data, ref blendColor); break; } } } } #endregion if (fragmentShaderMode) { #region "Shader combiner parameters" RenderBase.OMaterialColor materialColor = new RenderBase.OMaterialColor(); materialColor = material.materialColor; if (ctrlMA.animate) { foreach (RenderBase.OMaterialAnimationData data in ((RenderBase.OMaterialAnimation)models.materialAnimation.list[ctrlMA.CurrentAnimation]).data) { if (data.name == material.name) { switch (data.type) { case RenderBase.OMaterialAnimationType.constant0: getMaterialAnimationColor(data, ref materialColor.constant0); break; case RenderBase.OMaterialAnimationType.constant1: getMaterialAnimationColor(data, ref materialColor.constant1); break; case RenderBase.OMaterialAnimationType.constant2: getMaterialAnimationColor(data, ref materialColor.constant2); break; case RenderBase.OMaterialAnimationType.constant3: getMaterialAnimationColor(data, ref materialColor.constant3); break; case RenderBase.OMaterialAnimationType.constant4: getMaterialAnimationColor(data, ref materialColor.constant4); break; case RenderBase.OMaterialAnimationType.constant5: getMaterialAnimationColor(data, ref materialColor.constant5); break; case RenderBase.OMaterialAnimationType.diffuse: getMaterialAnimationColor(data, ref materialColor.diffuse); break; case RenderBase.OMaterialAnimationType.specular0: getMaterialAnimationColor(data, ref materialColor.specular0); break; case RenderBase.OMaterialAnimationType.specular1: getMaterialAnimationColor(data, ref materialColor.specular1); ; break; case RenderBase.OMaterialAnimationType.ambient: getMaterialAnimationColor(data, ref materialColor.ambient); break; } } } } fragmentShader.SetValue("hasTextures", textures.Count > 0); fragmentShader.SetValue("uvCount", obj.texUVCount); fragmentShader.SetValue("isD0Enabled", material.fragmentShader.lighting.isDistribution0Enabled); fragmentShader.SetValue("isD1Enabled", material.fragmentShader.lighting.isDistribution1Enabled); fragmentShader.SetValue("isG0Enabled", material.fragmentShader.lighting.isGeometryFactor0Enabled); fragmentShader.SetValue("isG1Enabled", material.fragmentShader.lighting.isGeometryFactor1Enabled); fragmentShader.SetValue("isREnabled", material.fragmentShader.lighting.isReflectionEnabled); fragmentShader.SetValue("bumpIndex", (int)material.fragmentShader.bump.texture); fragmentShader.SetValue("bumpMode", (int)material.fragmentShader.bump.mode); fragmentShader.SetValue("mEmissive", getColor(materialColor.emission)); fragmentShader.SetValue("mAmbient", getColor(materialColor.ambient)); fragmentShader.SetValue("mDiffuse", getColor(materialColor.diffuse)); fragmentShader.SetValue("mSpecular", getColor(materialColor.specular0)); fragmentShader.SetValue("hasNormal", obj.hasNormal); for (int i = 0; i < 6; i++) { RenderBase.OTextureCombiner textureCombiner = material.fragmentShader.textureCombiner[i]; fragmentShader.SetValue(string.Format("combiners[{0}].colorCombine", i), (int)textureCombiner.combineRgb); fragmentShader.SetValue(string.Format("combiners[{0}].alphaCombine", i), (int)textureCombiner.combineAlpha); fragmentShader.SetValue(string.Format("combiners[{0}].colorScale", i), (float)textureCombiner.rgbScale); fragmentShader.SetValue(string.Format("combiners[{0}].alphaScale", i), (float)textureCombiner.alphaScale); for (int j = 0; j < 3; j++) { fragmentShader.SetValue(string.Format("combiners[{0}].colorArg[{1}]", i, j), (int)textureCombiner.rgbSource[j]); fragmentShader.SetValue(string.Format("combiners[{0}].colorOp[{1}]", i, j), (int)textureCombiner.rgbOperand[j]); fragmentShader.SetValue(string.Format("combiners[{0}].alphaArg[{1}]", i, j), (int)textureCombiner.alphaSource[j]); fragmentShader.SetValue(string.Format("combiners[{0}].alphaOp[{1}]", i, j), (int)textureCombiner.alphaOperand[j]); } Color constantColor = Color.White; switch (textureCombiner.constantColor) { case RenderBase.OConstantColor.ambient: constantColor = materialColor.ambient; break; case RenderBase.OConstantColor.constant0: constantColor = materialColor.constant0; break; case RenderBase.OConstantColor.constant1: constantColor = materialColor.constant1; break; case RenderBase.OConstantColor.constant2: constantColor = materialColor.constant2; break; case RenderBase.OConstantColor.constant3: constantColor = materialColor.constant3; break; case RenderBase.OConstantColor.constant4: constantColor = materialColor.constant4; break; case RenderBase.OConstantColor.constant5: constantColor = materialColor.constant5; break; case RenderBase.OConstantColor.diffuse: constantColor = materialColor.diffuse; break; case RenderBase.OConstantColor.emission: constantColor = materialColor.emission; break; case RenderBase.OConstantColor.specular0: constantColor = materialColor.specular0; break; case RenderBase.OConstantColor.specular1: constantColor = materialColor.specular1; break; } fragmentShader.SetValue(string.Format("combiners[{0}].constant", i), new Vector4( (float)constantColor.R / 0xff, (float)constantColor.G / 0xff, (float)constantColor.B / 0xff, (float)constantColor.A / 0xff)); } #endregion } int legacyTextureIndex = -1; int legacyTextureUnit = -1; for (int i = 0; i < textures.Count; i++) { string[] name = new string[3]; name[0] = material.name0; name[1] = material.name1; name[2] = material.name2; if (ctrlMA.animate) { RenderBase.OMaterialAnimation ma = (RenderBase.OMaterialAnimation)models.materialAnimation.list[ctrlMA.CurrentAnimation]; for (int j = 0; j < 3; j++) if (textureId[j] > -1) name[j] = ma.textureName[textureId[j]]; } if (cfgLegacyTexturingMode == 0 && !fragmentShaderMode) { if (textures[i].name == name[0]) { legacyTextureIndex = i; legacyTextureUnit = 0; break; } } else { for (int j = 0; j < 3; j++) { if (fragmentShaderMode) { if (textures[i].name == name[j]) { string shaderTexture = string.Format("texture{0}", j); fragmentShader.SetValue(shaderTexture, textures[i].texture); } } else { if (textures[i].name == name[j] && legacyTextureUnit < j) { legacyTextureIndex = i; legacyTextureUnit = j; } } } } } if (!fragmentShaderMode) { if (legacyTextureIndex > -1) device.SetTexture(0, textures[legacyTextureIndex].texture); else device.SetTexture(0, null); } #region "Texture Filtering/Addressing Setup" //Filtering for (int s = 0; s < 3; s++) { RenderBase.OTextureCoordinator coordinator = material.textureCoordinator[s]; Vector2 translate = new Vector2(coordinator.translateU, coordinator.translateV); Vector2 scaling = new Vector2(coordinator.scaleU, coordinator.scaleV); if (scaling == Vector2.Empty) scaling = new Vector2(1, 1); float rotate = coordinator.rotate; #region "Material Animation" if (ctrlMA.animate) { foreach (RenderBase.OMaterialAnimationData data in ((RenderBase.OMaterialAnimation)models.materialAnimation.list[ctrlMA.CurrentAnimation]).data) { if (data.name == material.name) { switch (data.type) { case RenderBase.OMaterialAnimationType.translateCoordinator0: if (s == 0) getMaterialAnimationVector2(data, ref translate); break; //Translation case RenderBase.OMaterialAnimationType.translateCoordinator1: if (s == 1) getMaterialAnimationVector2(data, ref translate); break; case RenderBase.OMaterialAnimationType.translateCoordinator2: if (s == 2) getMaterialAnimationVector2(data, ref translate); break; case RenderBase.OMaterialAnimationType.scaleCoordinator0: if (s == 0) getMaterialAnimationVector2(data, ref scaling); break; //Scaling case RenderBase.OMaterialAnimationType.scaleCoordinator1: if (s == 1) getMaterialAnimationVector2(data, ref scaling); break; case RenderBase.OMaterialAnimationType.scaleCoordinator2: if (s == 2) getMaterialAnimationVector2(data, ref scaling); break; case RenderBase.OMaterialAnimationType.rotateCoordinator0: if (s == 0) getMaterialAnimationFloat(data, ref rotate); break; //Rotation case RenderBase.OMaterialAnimationType.rotateCoordinator1: if (s == 1) getMaterialAnimationFloat(data, ref rotate); break; case RenderBase.OMaterialAnimationType.rotateCoordinator2: if (s == 2) getMaterialAnimationFloat(data, ref rotate); break; } } } } #endregion if (fragmentShaderMode) { fragmentShader.SetValue(string.Format("uvTranslate[{0}]", s), new Vector4(-translate.X, -translate.Y, 0, 0)); fragmentShader.SetValue(string.Format("uvScale[{0}]", s), new Vector4(scaling.X, scaling.Y, 0, 0)); fragmentShader.SetValue(string.Format("uvTransform[{0}]", s), Matrix.RotationZ(rotate)); } else { device.SetTextureStageState(s, TextureStageStates.TextureTransform, (int)TextureTransform.Count2); Matrix uvTransform = rotateCenter2D(rotate) * Matrix.Scaling(scaling.X, scaling.Y, 1) * translate2D(-translate); if (s == legacyTextureUnit) device.Transform.Texture0 = uvTransform; } device.SetSamplerState(s, SamplerStageStates.MinFilter, (int)TextureFilter.Linear); switch (material.textureMapper[s].magFilter) { case RenderBase.OTextureMagFilter.nearest: device.SetSamplerState(s, SamplerStageStates.MagFilter, (int)TextureFilter.None); break; case RenderBase.OTextureMagFilter.linear: device.SetSamplerState(s, SamplerStageStates.MagFilter, (int)TextureFilter.Linear); break; } //Addressing device.SetSamplerState(s, SamplerStageStates.BorderColor, borderColor[s].ToArgb()); switch (material.textureMapper[s].wrapU) { case RenderBase.OTextureWrap.repeat: device.SetSamplerState(s, SamplerStageStates.AddressU, (int)TextureAddress.Wrap); break; case RenderBase.OTextureWrap.mirroredRepeat: device.SetSamplerState(s, SamplerStageStates.AddressU, (int)TextureAddress.Mirror); break; case RenderBase.OTextureWrap.clampToEdge: device.SetSamplerState(s, SamplerStageStates.AddressU, (int)TextureAddress.Clamp); break; case RenderBase.OTextureWrap.clampToBorder: device.SetSamplerState(s, SamplerStageStates.AddressU, (int)TextureAddress.Border); break; } switch (material.textureMapper[s].wrapV) { case RenderBase.OTextureWrap.repeat: device.SetSamplerState(s, SamplerStageStates.AddressV, (int)TextureAddress.Wrap); break; case RenderBase.OTextureWrap.mirroredRepeat: device.SetSamplerState(s, SamplerStageStates.AddressV, (int)TextureAddress.Mirror); break; case RenderBase.OTextureWrap.clampToEdge: device.SetSamplerState(s, SamplerStageStates.AddressV, (int)TextureAddress.Clamp); break; case RenderBase.OTextureWrap.clampToBorder: device.SetSamplerState(s, SamplerStageStates.AddressV, (int)TextureAddress.Border); break; } } #endregion #region "Culling/Alpha/Depth/Stencil testing/blending stuff Setup" //Culling switch (material.rasterization.cullMode) { case RenderBase.OCullMode.backFace: device.RenderState.CullMode = Cull.Clockwise; break; case RenderBase.OCullMode.frontFace: device.RenderState.CullMode = Cull.CounterClockwise; break; case RenderBase.OCullMode.never: device.RenderState.CullMode = Cull.None; break; } //Alpha testing RenderBase.OAlphaTest alpha = material.fragmentShader.alphaTest; device.RenderState.AlphaTestEnable = alpha.isTestEnabled; device.RenderState.AlphaFunction = getCompare(alpha.testFunction); device.RenderState.ReferenceAlpha = (int)alpha.testReference; //Depth testing RenderBase.ODepthOperation depth = material.fragmentOperation.depth; device.RenderState.ZBufferEnable = depth.isTestEnabled; device.RenderState.ZBufferFunction = getCompare(depth.testFunction); device.RenderState.ZBufferWriteEnable = depth.isMaskEnabled; //Alpha blending RenderBase.OBlendOperation blend = material.fragmentOperation.blend; device.RenderState.AlphaBlendEnable = blend.mode == RenderBase.OBlendMode.blend; device.RenderState.SeparateAlphaBlendEnabled = true; device.RenderState.SourceBlend = getBlend(blend.rgbFunctionSource); device.RenderState.DestinationBlend = getBlend(blend.rgbFunctionDestination); device.RenderState.BlendOperation = getBlendOperation(blend.rgbBlendEquation); device.RenderState.AlphaSourceBlend = getBlend(blend.alphaFunctionSource); device.RenderState.AlphaDestinationBlend = getBlend(blend.alphaFunctionDestination); device.RenderState.AlphaBlendOperation = getBlendOperation(blend.alphaBlendEquation); device.RenderState.BlendFactorColor = blendColor.ToArgb(); //Stencil testing RenderBase.OStencilOperation stencil = material.fragmentOperation.stencil; device.RenderState.StencilEnable = stencil.isTestEnabled; device.RenderState.StencilFunction = getCompare(stencil.testFunction); device.RenderState.ReferenceStencil = (int)stencil.testReference; device.RenderState.StencilWriteMask = (int)stencil.testMask; device.RenderState.StencilFail = getStencilOperation(stencil.failOperation); device.RenderState.StencilZBufferFail = getStencilOperation(stencil.zFailOperation); device.RenderState.StencilPass = getStencilOperation(stencil.passOperation); #endregion #region "Rendering" //Vertex rendering VertexFormats vertexFormat = VertexFormats.Position | VertexFormats.Normal | VertexFormats.Texture3 | VertexFormats.Diffuse; device.VertexFormat = vertexFormat; if (fragmentShaderMode) fragmentShader.BeginPass(0); if (meshes[objectIndex].Length > 0) { customVertex[] buffer = meshes[objectIndex]; if (ctrlSA.animate) { buffer = new customVertex[meshes[objectIndex].Length]; for (int vertex = 0; vertex < buffer.Length; vertex++) { buffer[vertex] = meshes[objectIndex][vertex]; RenderBase.OVertex input = obj.vertices[vertex]; Vector3 position = new Vector3(input.position.x, input.position.y, input.position.z); Vector4 p = new Vector4(); int weightIndex = 0; float weightSum = 0; foreach (int boneIndex in input.node) { float weight = 0; if (weightIndex < input.weight.Count) weight = input.weight[weightIndex++]; weightSum += weight; p += Vector3.Transform(position, animationSkeletonTransform[boneIndex]) * weight; } if (weightSum < 1) p += new Vector4(position.X, position.Y, position.Z, 0) * (1 - weightSum); buffer[vertex].x = p.X; buffer[vertex].y = p.Y; buffer[vertex].z = p.Z; } } using (VertexBuffer vertexBuffer = new VertexBuffer(typeof(customVertex), buffer.Length, device, Usage.None, vertexFormat, Pool.Managed)) { vertexBuffer.SetData(buffer, 0, LockFlags.None); device.SetStreamSource(0, vertexBuffer, 0); device.DrawPrimitives(PrimitiveType.TriangleList, 0, buffer.Length / 3); } } if (fragmentShaderMode) fragmentShader.EndPass(); #endregion } } if (fragmentShaderMode) fragmentShader.End(); //HUD if (cfgShowInformation && currentModel > -1) { resetRenderState(); RenderBase.OModel mdl = models.model[currentModel]; StringBuilder info = new StringBuilder(); info.AppendLine("Meshes: " + mdl.mesh.Count); info.AppendLine("Triangles: " + (models.model[currentModel].verticesCount / 3)); info.AppendLine("Bones: " + mdl.skeleton.Count); info.AppendLine("Materials: " + mdl.material.Count); info.AppendLine("Textures: " + models.texture.Count); if (ctrlSA.CurrentAnimation > -1) info.AppendLine("S. Frame: " + ctrlSA.CurrentFrameInfo); if (ctrlMA.CurrentAnimation > -1) info.AppendLine("M. Frame: " + ctrlMA.CurrentFrameInfo); if (ctrlVA.CurrentAnimation > -1) info.AppendLine("V. Frame: " + ctrlVA.CurrentFrameInfo); drawText(info.ToString(), 256, 192); } device.EndScene(); device.Present(); ctrlSA.advanceFrame(); ctrlMA.advanceFrame(); ctrlVA.advanceFrame(); }
public void render() { //Compile the Fragment Shader if (!useLegacyTexturing) { string compilationErros; fragmentShader = Effect.FromString(device, Properties.Resources.OFragmentShader, null, null, ShaderFlags.SkipOptimization, null, out compilationErros); if (compilationErros != "") MessageBox.Show("Failed to compile Fragment Shader!" + Environment.NewLine + compilationErros, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); fragmentShader.Technique = "Combiner"; } RenderBase.OVector3 minVector = new RenderBase.OVector3(); RenderBase.OVector3 maxVector = new RenderBase.OVector3(); if (model.model.Count > 0) currentModel = 0; updateTextures(); #region "Grid buffer creation" CustomVertex.PositionColored[] gridBuffer = new CustomVertex.PositionColored[218]; int bufferIndex = 0; for (int i = -50; i <= 50; i += 2) { if (i == 0) { gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(-50f, 0, i, Color.White.ToArgb()); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(0, 0, i, Color.White.ToArgb()); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(5f, 0, i, Color.White.ToArgb()); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(50f, 0, i, Color.White.ToArgb()); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(i, 0, -50f, Color.White.ToArgb()); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(i, 0, -5f, Color.White.ToArgb()); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(i, 0, 0, Color.White.ToArgb()); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(i, 0, 50f, Color.White.ToArgb()); } else { int lColor; if ((i % 10) == 0) lColor = Color.White.ToArgb(); else lColor = Color.DarkGray.ToArgb(); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(-50f, 0, i, lColor); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(50f, 0, i, lColor); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(i, 0, -50f, lColor); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(i, 0, 50f, lColor); } } gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(0, 0, 0, Color.Red.ToArgb()); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(5f, 0, 0, Color.Red.ToArgb()); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(0, 0, 0, Color.Green.ToArgb()); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(0, 5f, 0, Color.Green.ToArgb()); gridBuffer[bufferIndex++] = new CustomVertex.PositionColored(0, 0, 0, Color.Blue.ToArgb()); gridBuffer[bufferIndex] = new CustomVertex.PositionColored(0, 0, -5f, Color.Blue.ToArgb()); #endregion keepRendering = true; while (keepRendering) { device.Clear(ClearFlags.Stencil | ClearFlags.Target | ClearFlags.ZBuffer, bgColor, 1.0f, 15); device.SetTexture(0, null); device.BeginScene(); device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, (float)pParams.BackBufferWidth / pParams.BackBufferHeight, 0.01f, 1000.0f); device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 0.0f, 20.0f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f)); //View if (currentModel > -1) { minVector = model.model[currentModel].minVector; maxVector = model.model[currentModel].maxVector; } float minSize = Math.Min(Math.Min(minVector.x, minVector.y), minVector.z); float maxSize = Math.Max(Math.Max(maxVector.x, maxVector.y), maxVector.z); float scale = (10f / (maxSize - minSize)); //Try to adjust to screen if (maxSize - minSize == 0) scale = 1; Matrix centerMatrix = Matrix.Translation( -(minVector.x + maxVector.x) / 2, -(minVector.y + maxVector.y) / 2, -(minVector.z + maxVector.z) / 2); Matrix translationMatrix = Matrix.Translation( (-translation.X / 50) / scale, (translation.Y / 50) / scale, zoom / scale); Matrix baseTransform = Matrix.Identity; baseTransform *= Matrix.RotationY(rotation.Y) * Matrix.RotationX(rotation.X); baseTransform *= centerMatrix * translationMatrix * Matrix.Scaling(-scale, scale, scale); //Grid if (showGrid) { resetRenderState(); device.Transform.World = baseTransform; device.VertexFormat = CustomVertex.PositionColored.Format; VertexBuffer lineBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), gridBuffer.Length, device, Usage.None, CustomVertex.PositionColored.Format, Pool.Managed); lineBuffer.SetData(gridBuffer, 0, LockFlags.None); device.SetStreamSource(0, lineBuffer, 0); device.DrawPrimitives(PrimitiveType.LineList, 0, gridBuffer.Length / 2); lineBuffer.Dispose(); } if (!useLegacyTexturing) { fragmentShader.Begin(0); #region "Shader Setup" fragmentShader.SetValue("world", device.Transform.World); fragmentShader.SetValue("view", device.Transform.View); fragmentShader.SetValue("projection", device.Transform.Projection); fragmentShader.SetValue("lights[0].pos", new Vector4(0, -10, -10, 0)); fragmentShader.SetValue("lights[0].ambient", new Vector4(0.1f, 0.1f, 0.1f, 1)); fragmentShader.SetValue("lights[0].diffuse", new Vector4(1, 1, 1, 1)); fragmentShader.SetValue("lights[0].specular", new Vector4(1, 1, 1, 1)); fragmentShader.SetValue("numLights", 1); #endregion } if (wireframeMode) device.RenderState.FillMode = FillMode.WireFrame; else device.RenderState.FillMode = FillMode.Solid; if (currentModel > -1) { RenderBase.OModel mdl = model.model[currentModel]; device.Transform.World = getMatrix(mdl.transform) * baseTransform; #region "Skeletal Animation" Matrix[] animationSkeletonTransform = new Matrix[mdl.skeleton.Count]; if (ctrlSA.animate) { Matrix[] skeletonTransform = new Matrix[mdl.skeleton.Count]; for (int index = 0; index < mdl.skeleton.Count; index++) { skeletonTransform[index] = Matrix.Identity; transformSkeleton(mdl.skeleton, index, ref skeletonTransform[index]); } List<RenderBase.OSkeletalAnimationBone> bone = ((RenderBase.OSkeletalAnimation)model.skeletalAnimation.list[ctrlSA.CurrentAnimation]).bone; List<OAnimationBone> frameAnimationSkeleton = new List<OAnimationBone>(); for (int index = 0; index < mdl.skeleton.Count; index++) { OAnimationBone newBone = new OAnimationBone(); newBone.parentId = mdl.skeleton[index].parentId; newBone.rotationQuaternion = getQuaternion(mdl.skeleton[index].rotation); newBone.translation = new RenderBase.OVector3(mdl.skeleton[index].translation); foreach (RenderBase.OSkeletalAnimationBone b in bone) { if (b.name == mdl.skeleton[index].name) { if (b.isFullBakedFormat) { newBone.hasTransform = true; newBone.transform = b.transform[(int)ctrlSA.Frame % b.transform.Count]; } else if (b.isFrameFormat) { float fa = (float)Math.Floor(ctrlSA.Frame); float fb = (float)Math.Ceiling(ctrlSA.Frame); if (b.rotationQuaternion.exists) { int aIndex = Math.Min((int)fa, b.rotationQuaternion.vector.Count - 1); int bIndex = Math.Min((int)fb, b.rotationQuaternion.vector.Count - 1); Quaternion q1 = getQuaternion(b.rotationQuaternion.vector[aIndex]); Quaternion q2 = getQuaternion(b.rotationQuaternion.vector[bIndex]); newBone.rotationQuaternion = Quaternion.Slerp(q1, q2, ctrlSA.Frame - fa); } if (b.translation.exists) { int aIndex = Math.Min((int)fa, b.translation.vector.Count - 1); int bIndex = Math.Min((int)fb, b.translation.vector.Count - 1); RenderBase.OVector4 t1 = b.translation.vector[aIndex]; RenderBase.OVector4 t2 = b.translation.vector[bIndex]; RenderBase.OVector4 t = AnimationUtils.interpolateLinear(t1, t2, ctrlSA.Frame - fa); newBone.translation = new RenderBase.OVector3(t.x, t.y, t.z); newBone.translation.x *= mdl.skeleton[index].absoluteScale.x; newBone.translation.y *= mdl.skeleton[index].absoluteScale.y; newBone.translation.z *= mdl.skeleton[index].absoluteScale.z; } } else { /* * Rotation */ float fa = (float)Math.Floor(ctrlSA.Frame); float fb = (float)Math.Ceiling(ctrlSA.Frame); float x1, x2, y1, y2, z1, z2; x1 = x2 = mdl.skeleton[index].rotation.x; y1 = y2 = mdl.skeleton[index].rotation.y; z1 = z2 = mdl.skeleton[index].rotation.z; if (b.rotationX.exists) x1 = AnimationUtils.getKey(b.rotationX, fa); if (b.rotationY.exists) y1 = AnimationUtils.getKey(b.rotationY, fa); if (b.rotationZ.exists) z1 = AnimationUtils.getKey(b.rotationZ, fa); if (b.rotationX.exists) x2 = AnimationUtils.getKey(b.rotationX, fb); if (b.rotationY.exists) y2 = AnimationUtils.getKey(b.rotationY, fb); if (b.rotationZ.exists) z2 = AnimationUtils.getKey(b.rotationZ, fb); Quaternion q1 = getQuaternion(new RenderBase.OVector3(x1, y1, z1)); Quaternion q2 = getQuaternion(new RenderBase.OVector3(x2, y2, z2)); newBone.rotationQuaternion = Quaternion.Slerp(q1, q2, ctrlSA.Frame - fa); /* * Translation */ if (b.translationX.exists) { newBone.translation.x = AnimationUtils.getKey(b.translationX, ctrlSA.Frame); newBone.translation.x *= mdl.skeleton[index].absoluteScale.x; } if (b.translationY.exists) { newBone.translation.y = AnimationUtils.getKey(b.translationY, ctrlSA.Frame); newBone.translation.y *= mdl.skeleton[index].absoluteScale.y; } if (b.translationZ.exists) { newBone.translation.z = AnimationUtils.getKey(b.translationZ, ctrlSA.Frame); newBone.translation.z *= mdl.skeleton[index].absoluteScale.z; } } break; } } frameAnimationSkeleton.Add(newBone); } for (int index = 0; index < mdl.skeleton.Count; index++) { animationSkeletonTransform[index] = Matrix.Identity; if (frameAnimationSkeleton[index].hasTransform) animationSkeletonTransform[index] = getMatrix(frameAnimationSkeleton[index].transform); else transformAnimationSkeleton(frameAnimationSkeleton, index, ref animationSkeletonTransform[index]); animationSkeletonTransform[index] = Matrix.Invert(skeletonTransform[index]) * animationSkeletonTransform[index]; } } #endregion int objectIndex = 0; foreach (RenderBase.OMesh obj in mdl.mesh) { bool isVisible = obj.isVisible; if (ctrlVA.animate) { foreach (RenderBase.OVisibilityAnimationData data in ((RenderBase.OVisibilityAnimation)model.visibilityAnimation.list[ctrlVA.CurrentAnimation]).data) { RenderBase.OAnimationKeyFrame frame = AnimationUtils.getSmallerPoint(data.visibilityList.keyFrames, ctrlVA.Frame); if (data.name == obj.name) isVisible = frame.bValue; } } if (isVisible) { RenderBase.OMaterial material = mdl.material[obj.materialId]; #region "Material Animation" int[] textureId = { -1, -1, -1 }; Color blendColor = material.fragmentOperation.blend.blendColor; Color[] borderColor = new Color[3]; borderColor[0] = material.textureMapper[0].borderColor; borderColor[1] = material.textureMapper[1].borderColor; borderColor[2] = material.textureMapper[2].borderColor; if (ctrlMA.animate) { foreach (RenderBase.OMaterialAnimationData data in ((RenderBase.OMaterialAnimation)model.materialAnimation.list[ctrlMA.CurrentAnimation]).data) { if (data.name == material.name) { switch (data.type) { case RenderBase.OMaterialAnimationType.textureMapper0: getMaterialAnimationInt(data, ref textureId[0]); break; case RenderBase.OMaterialAnimationType.textureMapper1: getMaterialAnimationInt(data, ref textureId[1]); break; case RenderBase.OMaterialAnimationType.textureMapper2: getMaterialAnimationInt(data, ref textureId[2]); break; case RenderBase.OMaterialAnimationType.borderColorMapper0: getMaterialAnimationColor(data, ref borderColor[0]); break; case RenderBase.OMaterialAnimationType.borderColorMapper1: getMaterialAnimationColor(data, ref borderColor[1]); break; case RenderBase.OMaterialAnimationType.borderColorMapper2: getMaterialAnimationColor(data, ref borderColor[2]); break; case RenderBase.OMaterialAnimationType.blendColor: getMaterialAnimationColor(data, ref blendColor); break; } } } } #endregion int legacyTexture = -1; if (!useLegacyTexturing) { #region "Shader combiner parameters" RenderBase.OMaterialColor materialColor = new RenderBase.OMaterialColor(); materialColor = material.materialColor; if (ctrlMA.animate) { foreach (RenderBase.OMaterialAnimationData data in ((RenderBase.OMaterialAnimation)model.materialAnimation.list[ctrlMA.CurrentAnimation]).data) { if (data.name == material.name) { switch (data.type) { case RenderBase.OMaterialAnimationType.constant0: getMaterialAnimationColor(data, ref materialColor.constant0); break; case RenderBase.OMaterialAnimationType.constant1: getMaterialAnimationColor(data, ref materialColor.constant1); break; case RenderBase.OMaterialAnimationType.constant2: getMaterialAnimationColor(data, ref materialColor.constant2); break; case RenderBase.OMaterialAnimationType.constant3: getMaterialAnimationColor(data, ref materialColor.constant3); break; case RenderBase.OMaterialAnimationType.constant4: getMaterialAnimationColor(data, ref materialColor.constant4); break; case RenderBase.OMaterialAnimationType.constant5: getMaterialAnimationColor(data, ref materialColor.constant5); break; case RenderBase.OMaterialAnimationType.diffuse: getMaterialAnimationColor(data, ref materialColor.diffuse); break; case RenderBase.OMaterialAnimationType.specular0: getMaterialAnimationColor(data, ref materialColor.specular0); break; case RenderBase.OMaterialAnimationType.specular1: getMaterialAnimationColor(data, ref materialColor.specular1); ; break; case RenderBase.OMaterialAnimationType.ambient: getMaterialAnimationColor(data, ref materialColor.ambient); break; } } } } fragmentShader.SetValue("hasTextures", textures.Count > 0); fragmentShader.SetValue("uvCount", obj.texUVCount); fragmentShader.SetValue("isD0Enabled", material.fragmentShader.lighting.isDistribution0Enabled); fragmentShader.SetValue("isD1Enabled", material.fragmentShader.lighting.isDistribution1Enabled); fragmentShader.SetValue("isG0Enabled", material.fragmentShader.lighting.isGeometryFactor0Enabled); fragmentShader.SetValue("isG1Enabled", material.fragmentShader.lighting.isGeometryFactor1Enabled); fragmentShader.SetValue("isREnabled", material.fragmentShader.lighting.isReflectionEnabled); fragmentShader.SetValue("bumpIndex", (int)material.fragmentShader.bump.texture); fragmentShader.SetValue("bumpMode", (int)material.fragmentShader.bump.mode); fragmentShader.SetValue("mEmissive", getColor(materialColor.emission)); fragmentShader.SetValue("mAmbient", getColor(materialColor.ambient)); fragmentShader.SetValue("mDiffuse", getColor(materialColor.diffuse)); fragmentShader.SetValue("mSpecular", getColor(materialColor.specular0)); fragmentShader.SetValue("hasNormal", obj.hasNormal); for (int i = 0; i < 6; i++) { RenderBase.OTextureCombiner textureCombiner = material.fragmentShader.textureCombiner[i]; fragmentShader.SetValue(String.Format("combiners[{0}].colorCombine", i), (int)textureCombiner.combineRgb); fragmentShader.SetValue(String.Format("combiners[{0}].alphaCombine", i), (int)textureCombiner.combineAlpha); fragmentShader.SetValue(String.Format("combiners[{0}].colorScale", i), (float)textureCombiner.rgbScale); fragmentShader.SetValue(String.Format("combiners[{0}].alphaScale", i), (float)textureCombiner.alphaScale); for (int j = 0; j < 3; j++) { fragmentShader.SetValue(String.Format("combiners[{0}].colorArg[{1}]", i, j), (int)textureCombiner.rgbSource[j]); fragmentShader.SetValue(String.Format("combiners[{0}].colorOp[{1}]", i, j), (int)textureCombiner.rgbOperand[j]); fragmentShader.SetValue(String.Format("combiners[{0}].alphaArg[{1}]", i, j), (int)textureCombiner.alphaSource[j]); fragmentShader.SetValue(String.Format("combiners[{0}].alphaOp[{1}]", i, j), (int)textureCombiner.alphaOperand[j]); } Color constantColor = Color.White; switch (textureCombiner.constantColor) { case RenderBase.OConstantColor.ambient: constantColor = materialColor.ambient; break; case RenderBase.OConstantColor.constant0: constantColor = materialColor.constant0; break; case RenderBase.OConstantColor.constant1: constantColor = materialColor.constant1; break; case RenderBase.OConstantColor.constant2: constantColor = materialColor.constant2; break; case RenderBase.OConstantColor.constant3: constantColor = materialColor.constant3; break; case RenderBase.OConstantColor.constant4: constantColor = materialColor.constant4; break; case RenderBase.OConstantColor.constant5: constantColor = materialColor.constant5; break; case RenderBase.OConstantColor.diffuse: constantColor = materialColor.diffuse; break; case RenderBase.OConstantColor.emission: constantColor = materialColor.emission; break; case RenderBase.OConstantColor.specular0: constantColor = materialColor.specular0; break; case RenderBase.OConstantColor.specular1: constantColor = materialColor.specular1; break; } fragmentShader.SetValue(String.Format("combiners[{0}].constant", i), new Vector4( (float)constantColor.R / 0xff, (float)constantColor.G / 0xff, (float)constantColor.B / 0xff, (float)constantColor.A / 0xff)); } if (ctrlMA.animate) { RenderBase.OMaterialAnimation materialAnimation = (RenderBase.OMaterialAnimation)model.materialAnimation.list[ctrlMA.CurrentAnimation]; foreach (CustomTexture texture in textures) { if (texture.name == (textureId[0] > -1 ? materialAnimation.textureName[textureId[0]] : material.name0)) fragmentShader.SetValue("texture0", texture.texture); else if (texture.name == (textureId[1] > -1 ? materialAnimation.textureName[textureId[1]] : material.name1)) fragmentShader.SetValue("texture1", texture.texture); else if (texture.name == (textureId[2] > -1 ? materialAnimation.textureName[textureId[2]] : material.name2)) fragmentShader.SetValue("texture2", texture.texture); } } else { foreach (CustomTexture texture in textures) { if (texture.name == material.name0) fragmentShader.SetValue("texture0", texture.texture); else if (texture.name == material.name1) fragmentShader.SetValue("texture1", texture.texture); else if (texture.name == material.name2) fragmentShader.SetValue("texture2", texture.texture); } } #endregion } else { string[] name = new string[3]; name[0] = material.name0; name[1] = material.name1; name[2] = material.name2; if (ctrlMA.animate) { RenderBase.OMaterialAnimation materialAnimation = (RenderBase.OMaterialAnimation)model.materialAnimation.list[ctrlMA.CurrentAnimation]; for (int i = 0; i < 3; i++) if (textureId[i] > -1) name[i] = materialAnimation.textureName[textureId[i]]; } int nCount = int.MaxValue; int maxPixelCount = 0; for (int i = 0; i < textures.Count; i++) { for (int j = 0; j < 3; j++) { if (textures[i].name == name[j]) { //Strings with more "n" on the names are most likely to be Normal Maps, and we don't want those. int n = textures[i].name.Length - textures[i].name.ToLower().Replace("n", "").Length; int pixelCount = textures[i].width * textures[i].height; //Bigger textures are more likely to contain relevant stuff if (n <= nCount && pixelCount >= maxPixelCount) { legacyTexture = i; nCount = n; maxPixelCount = pixelCount; } } } } if (legacyTexture > -1) device.SetTexture(0, textures[legacyTexture].texture); else device.SetTexture(0, null); } #region "Texture Filtering/Addressing Setup" //Filtering for (int s = 0; s < 3; s++) { RenderBase.OTextureCoordinator coordinator = material.textureCoordinator[s]; Vector2 translate = new Vector2(coordinator.translateU, coordinator.translateV); Vector2 scaling = new Vector2(coordinator.scaleU, coordinator.scaleV); if (scaling == Vector2.Empty) scaling = new Vector2(1, 1); float rotate = coordinator.rotate; #region "Material Animation" if (ctrlMA.animate) { foreach (RenderBase.OMaterialAnimationData data in ((RenderBase.OMaterialAnimation)model.materialAnimation.list[ctrlMA.CurrentAnimation]).data) { if (data.name == material.name) { switch (data.type) { case RenderBase.OMaterialAnimationType.translateCoordinator0: if (s == 0) getMaterialAnimationVector2(data, ref translate); break; //Translation case RenderBase.OMaterialAnimationType.translateCoordinator1: if (s == 1) getMaterialAnimationVector2(data, ref translate); break; case RenderBase.OMaterialAnimationType.translateCoordinator2: if (s == 2) getMaterialAnimationVector2(data, ref translate); break; case RenderBase.OMaterialAnimationType.scaleCoordinator0: if (s == 0) getMaterialAnimationVector2(data, ref scaling); break; //Scaling case RenderBase.OMaterialAnimationType.scaleCoordinator1: if (s == 1) getMaterialAnimationVector2(data, ref scaling); break; case RenderBase.OMaterialAnimationType.scaleCoordinator2: if (s == 2) getMaterialAnimationVector2(data, ref scaling); break; case RenderBase.OMaterialAnimationType.rotateCoordinator0: if (s == 0) getMaterialAnimationFloat(data, ref rotate); break; //Rotation case RenderBase.OMaterialAnimationType.rotateCoordinator1: if (s == 1) getMaterialAnimationFloat(data, ref rotate); break; case RenderBase.OMaterialAnimationType.rotateCoordinator2: if (s == 2) getMaterialAnimationFloat(data, ref rotate); break; } } } } #endregion translate.X = -translate.X; //For some reason UVs need to be flipped to show up correct on animation translate.Y = -translate.Y; Matrix uvTransform = rotateCenter2D(rotate) * Matrix.Scaling(scaling.X, scaling.Y, 1) * translate2D(translate); if (!useLegacyTexturing) { fragmentShader.SetValue(String.Format("uvTranslate[{0}]", s), new Vector4(translate.X, translate.Y, 0, 0)); fragmentShader.SetValue(String.Format("uvScale[{0}]", s), new Vector4(scaling.X, scaling.Y, 0, 0)); fragmentShader.SetValue(String.Format("uvTransform[{0}]", s), Matrix.RotationZ(rotate)); } else { device.SetTextureStageState(s, TextureStageStates.TextureTransform, (int)TextureTransform.Count2); if (s == legacyTexture) device.Transform.Texture0 = uvTransform; } device.SetSamplerState(s, SamplerStageStates.MinFilter, (int)TextureFilter.Linear); switch (material.textureMapper[s].magFilter) { case RenderBase.OTextureMagFilter.nearest: device.SetSamplerState(s, SamplerStageStates.MagFilter, (int)TextureFilter.None); break; case RenderBase.OTextureMagFilter.linear: device.SetSamplerState(s, SamplerStageStates.MagFilter, (int)TextureFilter.Linear); break; } //Addressing device.SetSamplerState(s, SamplerStageStates.BorderColor, borderColor[s].ToArgb()); switch (material.textureMapper[s].wrapU) { case RenderBase.OTextureWrap.repeat: device.SetSamplerState(s, SamplerStageStates.AddressU, (int)TextureAddress.Wrap); break; case RenderBase.OTextureWrap.mirroredRepeat: device.SetSamplerState(s, SamplerStageStates.AddressU, (int)TextureAddress.Mirror); break; case RenderBase.OTextureWrap.clampToEdge: device.SetSamplerState(s, SamplerStageStates.AddressU, (int)TextureAddress.Clamp); break; case RenderBase.OTextureWrap.clampToBorder: device.SetSamplerState(s, SamplerStageStates.AddressU, (int)TextureAddress.Border); break; } switch (material.textureMapper[s].wrapV) { case RenderBase.OTextureWrap.repeat: device.SetSamplerState(s, SamplerStageStates.AddressV, (int)TextureAddress.Wrap); break; case RenderBase.OTextureWrap.mirroredRepeat: device.SetSamplerState(s, SamplerStageStates.AddressV, (int)TextureAddress.Mirror); break; case RenderBase.OTextureWrap.clampToEdge: device.SetSamplerState(s, SamplerStageStates.AddressV, (int)TextureAddress.Clamp); break; case RenderBase.OTextureWrap.clampToBorder: device.SetSamplerState(s, SamplerStageStates.AddressV, (int)TextureAddress.Border); break; } } #endregion #region "Culling/Alpha/Depth/Stencil testing/blending stuff Setup" //Culling switch (material.rasterization.cullMode) { case RenderBase.OCullMode.backFace: device.RenderState.CullMode = Cull.Clockwise; break; case RenderBase.OCullMode.frontFace: device.RenderState.CullMode = Cull.CounterClockwise; break; case RenderBase.OCullMode.never: device.RenderState.CullMode = Cull.None; break; } //Alpha testing RenderBase.OAlphaTest alpha = material.fragmentShader.alphaTest; device.RenderState.AlphaTestEnable = alpha.isTestEnabled; device.RenderState.AlphaFunction = getCompare(alpha.testFunction); device.RenderState.ReferenceAlpha = (int)alpha.testReference; //Depth testing RenderBase.ODepthOperation depth = material.fragmentOperation.depth; device.RenderState.ZBufferEnable = depth.isTestEnabled; device.RenderState.ZBufferFunction = getCompare(depth.testFunction); device.RenderState.ZBufferWriteEnable = depth.isMaskEnabled; //Alpha blending RenderBase.OBlendOperation blend = material.fragmentOperation.blend; device.RenderState.AlphaBlendEnable = blend.mode == RenderBase.OBlendMode.blend; device.RenderState.SeparateAlphaBlendEnabled = true; device.RenderState.SourceBlend = getBlend(blend.rgbFunctionSource); device.RenderState.DestinationBlend = getBlend(blend.rgbFunctionDestination); device.RenderState.BlendOperation = getBlendOperation(blend.rgbBlendEquation); device.RenderState.AlphaSourceBlend = getBlend(blend.alphaFunctionSource); device.RenderState.AlphaDestinationBlend = getBlend(blend.alphaFunctionDestination); device.RenderState.AlphaBlendOperation = getBlendOperation(blend.alphaBlendEquation); device.RenderState.BlendFactorColor = blendColor.ToArgb(); //Stencil testing RenderBase.OStencilOperation stencil = material.fragmentOperation.stencil; device.RenderState.StencilEnable = stencil.isTestEnabled; device.RenderState.StencilFunction = getCompare(stencil.testFunction); device.RenderState.ReferenceStencil = (int)stencil.testReference; device.RenderState.StencilWriteMask = (int)stencil.testMask; device.RenderState.StencilFail = getStencilOperation(stencil.failOperation); device.RenderState.StencilZBufferFail = getStencilOperation(stencil.zFailOperation); device.RenderState.StencilPass = getStencilOperation(stencil.passOperation); #endregion #region "Rendering" //Vertex rendering VertexFormats vertexFormat = VertexFormats.Position | VertexFormats.Normal | VertexFormats.Texture3 | VertexFormats.Diffuse; device.VertexFormat = vertexFormat; VertexBuffer vertexBuffer; if (!useLegacyTexturing) fragmentShader.BeginPass(0); if (obj.renderBuffer.Length > 0) { if (ctrlSA.animate) { RenderBase.CustomVertex[] buffer = new RenderBase.CustomVertex[obj.renderBuffer.Length]; for (int vertex = 0; vertex < obj.renderBuffer.Length; vertex++) { buffer[vertex] = obj.renderBuffer[vertex]; RenderBase.OVertex input = obj.vertices[vertex]; Vector3 position = new Vector3(input.position.x, input.position.y, input.position.z); Vector4 p = new Vector4(); int weightIndex = 0; float weightSum = 0; foreach (int boneIndex in input.node) { float weight = 0; if (weightIndex < input.weight.Count) weight = input.weight[weightIndex++]; weightSum += weight; p += Vector3.Transform(position, animationSkeletonTransform[boneIndex]) * weight; } if (weightSum < 1) p += new Vector4(position.X, position.Y, position.Z, 0) * (1 - weightSum); buffer[vertex].x = p.X; buffer[vertex].y = p.Y; buffer[vertex].z = p.Z; } vertexBuffer = new VertexBuffer(typeof(RenderBase.CustomVertex), buffer.Length, device, Usage.None, vertexFormat, Pool.Managed); vertexBuffer.SetData(buffer, 0, LockFlags.None); device.SetStreamSource(0, vertexBuffer, 0); device.DrawPrimitives(PrimitiveType.TriangleList, 0, buffer.Length / 3); } else { vertexBuffer = new VertexBuffer(typeof(RenderBase.CustomVertex), obj.renderBuffer.Length, device, Usage.None, vertexFormat, Pool.Managed); vertexBuffer.SetData(obj.renderBuffer, 0, LockFlags.None); device.SetStreamSource(0, vertexBuffer, 0); device.DrawPrimitives(PrimitiveType.TriangleList, 0, obj.renderBuffer.Length / 3); } vertexBuffer.Dispose(); } if (!useLegacyTexturing) fragmentShader.EndPass(); #endregion objectIndex++; } } } if (!useLegacyTexturing) fragmentShader.End(); //HUD if (showHUD && currentModel > -1) { resetRenderState(); RenderBase.OModel mdl = model.model[currentModel]; StringBuilder info = new StringBuilder(); info.AppendLine("Meshes: " + model.model[currentModel].mesh.Count); info.AppendLine("Triangles: " + (model.model[currentModel].verticesCount / 3)); info.AppendLine("Bones: " + mdl.skeleton.Count); info.AppendLine("Materials: " + mdl.material.Count); info.AppendLine("Textures: " + model.texture.Count); if (ctrlSA.CurrentAnimation > -1) info.AppendLine("S. Frame: " + ctrlSA.Frame + " / " + model.skeletalAnimation.list[ctrlSA.CurrentAnimation].frameSize.ToString()); if (ctrlMA.CurrentAnimation > -1) info.AppendLine("M. Frame: " + ctrlMA.Frame + " / " + model.materialAnimation.list[ctrlMA.CurrentAnimation].frameSize.ToString()); if (ctrlVA.CurrentAnimation > -1) info.AppendLine("V. Frame: " + ctrlVA.Frame + " / " + model.visibilityAnimation.list[ctrlVA.CurrentAnimation].frameSize.ToString()); drawText(info.ToString(), 256, 192); } device.EndScene(); device.Present(); if (ctrlSA.animate) ctrlSA.advanceFrame(model.skeletalAnimation.list[ctrlSA.CurrentAnimation].frameSize); if (ctrlMA.animate) ctrlMA.advanceFrame(model.materialAnimation.list[ctrlMA.CurrentAnimation].frameSize); if (ctrlVA.animate) ctrlVA.advanceFrame(model.visibilityAnimation.list[ctrlVA.CurrentAnimation].frameSize); Application.DoEvents(); } }