Switch-Toolbox/Switch_FileFormatsMain/GL/BFRES_Render.cs
KillzXGaming 6d7579e6e0 More improvements.
Camera is now centerd when a bfres is selected. This will apply to reseting the camera aswell. The method is based on Smash Forge so thanks to the devs for it.
Start on bfsha program linking for bfres materials. Dunno how far i'll take this.
Basic ortho mode added. Needs improvements to zoom in and mainly just changes the projection matrix to ortho atm. Controls are not altered.
2019-05-21 18:08:57 -04:00

1198 lines
49 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using Syroot.NintenTools.NSW.Bfres;
using Syroot.NintenTools.NSW.Bfres.Helpers;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using System.Windows.Forms;
using GL_EditorFramework.GL_Core;
using GL_EditorFramework.Interfaces;
using Switch_Toolbox.Library;
using Switch_Toolbox.Library.Rendering;
using Switch_Toolbox.Library.IO;
using Switch_Toolbox.Library.Forms;
using ResU = Syroot.NintenTools.Bfres;
using Bfres.Structs;
using SF = SFGraphics.GLObjects.Shaders;
namespace FirstPlugin
{
public class BFRESRender : AbstractGlDrawable
{
public Matrix4 ModelTransform = Matrix4.Identity;
Vector3 position = new Vector3(0);
public static Vector4 hoverColor = new Vector4(1);
public static Vector4 selectColor = new Vector4(1);
protected bool Selected = false;
public bool Hovered = false;
public bool IsSelected() => Selected;
// gl buffer objects
int vbo_position;
int ibo_elements;
public List<FMDL> models
{
get
{
List<FMDL> fmdls = new List<FMDL>();
foreach (var node in ResFileNode.Nodes)
{
if (node is BFRESGroupNode &&
((BFRESGroupNode)node).Type == BRESGroupType.Models)
{
foreach (FMDL mdl in ((BFRESGroupNode)node).Nodes)
fmdls.Add(mdl);
}
}
return fmdls;
}
}
public BFRES ResFileNode;
public BFRESRender()
{
}
private void GenerateBuffers()
{
GL.GenBuffers(1, out vbo_position);
GL.GenBuffers(1, out ibo_elements);
TransformBones();
UpdateVertexData();
UpdateTextureMaps();
}
public void Destroy()
{
bool buffersWereInitialized = ibo_elements != 0 && vbo_position != 0;
if (!buffersWereInitialized)
return;
GL.DeleteBuffer(vbo_position);
GL.DeleteBuffer(ibo_elements);
}
private void TransformBones()
{
foreach (var model in models)
{
foreach (var bone in model.Skeleton.bones)
{
bone.ModelMatrix = ModelTransform;
}
}
}
#region Rendering
// public ShaderProgram BotwShaderProgram;
// public ShaderProgram normalsShaderProgram;
// public ShaderProgram debugShaderProgram;
// public ShaderProgram pbrShaderProgram;
// public ShaderProgram defaultShaderProgram;
// public ShaderProgram solidColorShaderProgram;
public override void Prepare(GL_ControlModern control)
{
/* string pathFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Bfres") + "\\BFRES.frag";
string pathVert = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Bfres") + "\\BFRES.vert";
string pathBotwFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Bfres") + "\\BFRES_Botw.frag";
string pathPbrFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Bfres") + "\\BFRES_PBR.frag";
string pathBfresUtiltyFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Bfres") + "\\BFRES_utility.frag";
string pathBfresTurboShadow = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Bfres") + "\\BFRESTurboShadow.frag";
string pathUtiltyFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Utility") + "\\Utility.frag";
string pathDebugFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Bfres") + "\\BFRES_Debug.frag";
string pathNormalsFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Bfres") + "\\Normals.frag";
string pathNormalsVert = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Bfres") + "\\Normals.vert";
string pathNormalGeom = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Bfres") + "\\Normals.geom";
var defaultFrag = new FragmentShader(System.IO.File.ReadAllText(pathFrag));
var defaultVert = new VertexShader(System.IO.File.ReadAllText(pathVert));
var BotwtFrag = new FragmentShader(System.IO.File.ReadAllText(pathBotwFrag));
var shadowMapAGL = new FragmentShader(System.IO.File.ReadAllText(pathBfresTurboShadow));
var PbrFrag = new FragmentShader(System.IO.File.ReadAllText(pathPbrFrag));
var debugFrag = new FragmentShader(System.IO.File.ReadAllText(pathDebugFrag));
var normalsVert = new VertexShader(System.IO.File.ReadAllText(pathNormalsVert));
var normalsFrag = new FragmentShader(System.IO.File.ReadAllText(pathNormalsFrag));
var normalsGeom = new GeomertyShader(System.IO.File.ReadAllText(pathNormalGeom));
var bfresUtiltyFrag = new FragmentShader(System.IO.File.ReadAllText(pathBfresUtiltyFrag));
var utiltyFrag = new FragmentShader(System.IO.File.ReadAllText(pathUtiltyFrag));
var solidColorFrag = new FragmentShader(
@"#version 330
uniform vec4 color;
out vec4 fragColor;
void main(){
fragColor = color;
}");
var solidColorVert = new VertexShader(
@"#version 330
in vec3 vPosition;
in vec3 vNormal;
in vec3 vColor;
uniform mat4 mtxMdl;
uniform mat4 mtxCam;
out vec3 normal;
out vec3 color;
out vec3 position;
void main(){
normal = vNormal;
color = vColor;
position = vPosition;
gl_Position = mtxMdl * mtxCam * vec4(vPosition.xyz, 1.0);
}");
defaultShaderProgram = new ShaderProgram(new Shader[] { bfresUtiltyFrag, utiltyFrag, defaultFrag, defaultVert, utiltyFrag, shadowMapAGL });
BotwShaderProgram = new ShaderProgram(new Shader[] { bfresUtiltyFrag, utiltyFrag, BotwtFrag, defaultVert, utiltyFrag, shadowMapAGL });
normalsShaderProgram = new ShaderProgram(new Shader[] { normalsFrag, normalsVert, normalsGeom });
debugShaderProgram = new ShaderProgram(new Shader[] { bfresUtiltyFrag, utiltyFrag, debugFrag, defaultVert, utiltyFrag, shadowMapAGL });
pbrShaderProgram = new ShaderProgram(new Shader[] { bfresUtiltyFrag, utiltyFrag, PbrFrag, defaultVert, shadowMapAGL });
solidColorShaderProgram = new ShaderProgram(solidColorFrag, solidColorVert);*/
}
public override void Prepare(GL_ControlLegacy control)
{
}
public override void Draw(GL_ControlLegacy control, Pass pass)
{
bool buffersWereInitialized = ibo_elements != 0 && vbo_position != 0;
if (!buffersWereInitialized)
GenerateBuffers();
if (!Runtime.OpenTKInitialized)
return;
}
public void CenterCamera(GL_ControlModern control)
{
var spheres = new List<Vector4>();
foreach (var mdl in models)
{
foreach (FSHP shp in mdl.shapes)
{
var vertexPositions = shp.vertices.Select(x => x.pos).Distinct();
spheres.Add(control.GenerateBoundingSphere(vertexPositions));
}
}
control.FrameSelect(spheres);
}
public static Vector4 GenerateBoundingSphere(IEnumerable<Vector4> boundingSpheres)
{
// The initial max/min should be the first point.
Vector3 min = boundingSpheres.FirstOrDefault().Xyz - new Vector3(boundingSpheres.FirstOrDefault().W);
Vector3 max = boundingSpheres.FirstOrDefault().Xyz + new Vector3(boundingSpheres.FirstOrDefault().W);
// Calculate the end points using the center and radius
foreach (var sphere in boundingSpheres)
{
min = Vector3.ComponentMin(min, sphere.Xyz - new Vector3(sphere.W));
max = Vector3.ComponentMax(max, sphere.Xyz + new Vector3(sphere.W));
}
return GetBoundingSphereFromSpheres(min, max);
}
private static Vector4 GetBoundingSphereFromSpheres(Vector3 min, Vector3 max)
{
Vector3 lengths = max - min;
float maxLength = Math.Max(lengths.X, Math.Max(lengths.Y, lengths.Z));
Vector3 center = (max + min) / 2.0f;
float radius = maxLength / 2.0f;
return new Vector4(center, radius);
}
public override void Draw(GL_ControlModern control, Pass pass) {
DrawBfres(control, pass);
}
/* public override void Draw(GL_ControlModern control, Pass pass, EditorSceneBase editorScene) {
DrawBfres(control, pass);
}*/
private void DrawBfres(GL_ControlModern control, Pass pass)
{
if (!Runtime.OpenTKInitialized || pass == Pass.TRANSPARENT)
return;
bool buffersWereInitialized = ibo_elements != 0 && vbo_position != 0;
if (!buffersWereInitialized)
GenerateBuffers();
if (Hovered == true)
throw new Exception("model selected");
//Temporarily revert to using this shader system as it is easy to port back
//This is much quicker. Will change after shaders are handled faster
SF.Shader shader = OpenTKSharedResources.shaders["BFRES"];
if (Runtime.EnablePBR)
shader = OpenTKSharedResources.shaders["BFRES_PBR"];
if (models.Count > 0)
{
// if (models[0].Parent.Parent.IsSelected)
// CenterCamera(control);
if (models[0].shapes.Count > 0)
{
if (models[0].shapes[0].GetMaterial().shaderassign.ShaderModel == "uking_mat")
{
shader = OpenTKSharedResources.shaders["BFRES_Botw"];
//Botw uses small models so lower the bone size
Runtime.bonePointSize = 0.040f;
}
}
}
if (Runtime.viewportShading != Runtime.ViewportShading.Default)
shader = OpenTKSharedResources.shaders["BFRES_Debug"];
if (Runtime.viewportShading == Runtime.ViewportShading.Lighting && Runtime.EnablePBR)
shader = OpenTKSharedResources.shaders["BFRES_PBR"];
shader.UseProgram();
control.UpdateModelMatrix(Matrix4.CreateScale(Runtime.previewScale) * ModelTransform);
Matrix4 camMat = control.CameraMatrix;
Matrix4 mdlMat = control.ModelMatrix;
Matrix4 projMat = control.ProjectionMatrix;
Matrix4 computedCamMtx = camMat * projMat;
Matrix4 mvpMat = control.ModelMatrix * control.CameraMatrix * control.ProjectionMatrix;
Matrix4 sphereMatrix = mvpMat;
if (sphereMatrix.Determinant != 0)
sphereMatrix.Invert();
sphereMatrix.Transpose();
shader.SetMatrix4x4("sphereMatrix", ref sphereMatrix);
shader.SetMatrix4x4("mtxCam", ref computedCamMtx);
shader.SetMatrix4x4("mtxMdl", ref mdlMat);
SetRenderSettings(shader);
Vector4 pickingColor = control.NextPickingColor();
shader.SetVector3("difLightColor", new Vector3(1));
shader.SetVector3("ambLightColor", new Vector3(1));
Matrix4 invertedCamera = Matrix4.Identity;
if (invertedCamera.Determinant != 0)
invertedCamera = mvpMat.Inverted();
Vector3 lightDirection = new Vector3(0f, 0f, -1f);
//Todo. Maybe change direction via AAMP file (configs shader data)
shader.SetVector3("specLightDirection", Vector3.TransformNormal(lightDirection, invertedCamera).Normalized());
shader.SetVector3("difLightDirection", Vector3.TransformNormal(lightDirection, invertedCamera).Normalized());
GL.Enable(EnableCap.AlphaTest);
GL.AlphaFunc(AlphaFunction.Gequal, 0.1f);
DrawModels(shader, control);
if (Runtime.renderNormalsPoints)
{
shader = OpenTKSharedResources.shaders["BFRES_Normals"];
shader.UseProgram();
Matrix4 projection = control.ProjectionMatrix;
Matrix4 camMtx = control.CameraMatrix;
shader.SetMatrix4x4("mtxProj", ref projection);
shader.SetMatrix4x4("camMtx", ref camMtx);
shader.SetFloat("normalsLength", Runtime.normalsLineLength);
DrawModels(shader, control);
}
GL.UseProgram(0);
GL.Disable(EnableCap.DepthTest);
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.CullFace);
}
private void DrawModels(SF.Shader shader, GL_ControlModern control)
{
shader.EnableVertexAttributes();
foreach (FMDL mdl in models)
{
if (mdl.Checked)
{
List<FSHP> opaque = new List<FSHP>();
List<FSHP> transparent = new List<FSHP>();
foreach (FSHP m in mdl.depthSortedMeshes)
{
if (m.GetMaterial().isTransparent)
transparent.Add(m);
else
opaque.Add(m);
}
foreach (FSHP shp in mdl.shapes)
{
DrawModel(shp, mdl, shader, mdl.IsSelected);
}
}
}
shader.DisableVertexAttributes();
}
public void DepthSortMeshes(Vector3 cameraPosition)
{
foreach (FMDL fmdl in models)
{
List<FSHP> unsortedMeshes = new List<FSHP>();
foreach (FSHP m in fmdl.shapes)
{
m.sortingDistance = m.CalculateSortingDistance(cameraPosition);
unsortedMeshes.Add(m);
}
fmdl.depthSortedMeshes = unsortedMeshes.OrderBy(o => (o.sortingDistance)).ToList();
}
// Order by the distance from the camera to the closest point on the bounding sphere.
// Positive values are usually closer to camera. Negative values are usually farther away.
}
private void SetRenderSettings(SF.Shader shader)
{
shader.SetBoolToInt("renderVertColor", Runtime.renderVertColor);
shader.SetBoolToInt("useNormalMap", Runtime.useNormalMap);
shader.SetBoolToInt("renderR", Runtime.renderR);
shader.SetBoolToInt("renderG", Runtime.renderG);
shader.SetBoolToInt("renderB", Runtime.renderB);
shader.SetBoolToInt("renderAlpha", Runtime.renderAlpha);
shader.SetInt("renderType", (int)Runtime.viewportShading);
shader.SetInt("uvChannel", (int)Runtime.uvChannel);
shader.SetBoolToInt("renderFog", Runtime.renderFog);
shader.SetBoolToInt("renderDiffuse", Runtime.renderDiffuse);
shader.SetBoolToInt("renderSpecular", Runtime.renderSpecular);
shader.SetBoolToInt("renderFresnel", Runtime.renderFresnel);
}
private static void SetDefaultTextureAttributes(FMAT mat, SF.Shader shader)
{
shader.SetBoolToInt("HasDiffuse", mat.HasDiffuseMap);
shader.SetBoolToInt("HasDiffuseLayer", mat.HasDiffuseLayer);
shader.SetBoolToInt("HasNormalMap", mat.HasNormalMap);
shader.SetBoolToInt("HasEmissionMap", mat.HasEmissionMap);
shader.SetBoolToInt("HasLightMap", mat.HasLightMap);
shader.SetBoolToInt("HasShadowMap", mat.HasShadowMap);
shader.SetBoolToInt("HasSpecularMap", mat.HasSpecularMap);
shader.SetBoolToInt("HasTeamColorMap", mat.HasTeamColorMap);
shader.SetBoolToInt("HasSphereMap", mat.HasSphereMap);
shader.SetBoolToInt("HasSubSurfaceScatteringMap", mat.HasSubSurfaceScatteringMap);
//Unused atm untill I do PBR shader
shader.SetBoolToInt("HasMetalnessMap", mat.HasMetalnessMap);
shader.SetBoolToInt("HasRoughnessMap", mat.HasRoughnessMap);
shader.SetBoolToInt("HasMRA", mat.HasMRA);
}
private static void SetBoneUniforms(SF.Shader shader, FMDL fmdl, FSHP fshp)
{
for (int i = 0; i < fmdl.Skeleton.Node_Array.Length; i++)
{
GL.Uniform1(GL.GetUniformLocation(shader.Id, String.Format("boneIds[{0}]", i)), fmdl.Skeleton.Node_Array[i]);
Matrix4 transform = fmdl.Skeleton.bones[fmdl.Skeleton.Node_Array[i]].invert * fmdl.Skeleton.bones[fmdl.Skeleton.Node_Array[i]].Transform;
GL.UniformMatrix4(GL.GetUniformLocation(shader.Id, String.Format("bones[{0}]", i)), false, ref transform);
}
}
private static void SetTextureUniforms(FMAT mat, FSHP m, SF.Shader shader)
{
SetDefaultTextureAttributes(mat, shader);
GL.ActiveTexture(TextureUnit.Texture0 + 1);
GL.BindTexture(TextureTarget.Texture2D, RenderTools.defaultTex.RenderableTex.TexID);
GL.ActiveTexture(TextureUnit.Texture11);
GL.Uniform1(shader.GetUniformLocation("weightRamp1"), 11);
GL.BindTexture(TextureTarget.Texture2D, RenderTools.BoneWeightGradient.Id);
GL.ActiveTexture(TextureUnit.Texture12);
GL.Uniform1(shader.GetUniformLocation("weightRamp2"), 12);
GL.BindTexture(TextureTarget.Texture2D, RenderTools.BoneWeightGradient2.Id);
GL.Uniform1(shader.GetUniformLocation("debugOption"), 2);
GL.ActiveTexture(TextureUnit.Texture10);
GL.Uniform1(shader.GetUniformLocation("UVTestPattern"), 10);
GL.BindTexture(TextureTarget.Texture2D, RenderTools.uvTestPattern.RenderableTex.TexID);
GL.Uniform1(shader.GetUniformLocation("normalMap"), 0);
GL.Uniform1(shader.GetUniformLocation("BakeShadowMap"), 0);
LoadPBRMaps(shader);
foreach (MatTexture matex in mat.TextureMaps)
{
if (matex.Type == MatTexture.TextureType.Diffuse)
TextureUniform(shader, mat, mat.HasDiffuseMap, "DiffuseMap", matex);
else if (matex.Type == MatTexture.TextureType.Normal)
TextureUniform(shader, mat, mat.HasNormalMap, "NormalMap", matex);
else if (matex.Type == MatTexture.TextureType.Emission)
TextureUniform(shader, mat, mat.HasEmissionMap, "EmissionMap", matex);
else if (matex.Type == MatTexture.TextureType.Specular)
TextureUniform(shader, mat, mat.HasSpecularMap, "SpecularMap", matex);
else if (matex.Type == MatTexture.TextureType.Shadow)
TextureUniform(shader, mat, mat.HasShadowMap, "BakeShadowMap", matex);
else if (matex.Type == MatTexture.TextureType.Light)
TextureUniform(shader, mat, mat.HasLightMap, "BakeLightMap", matex);
else if (matex.Type == MatTexture.TextureType.Metalness)
TextureUniform(shader, mat, mat.HasMetalnessMap, "MetalnessMap", matex);
else if (matex.Type == MatTexture.TextureType.Roughness)
TextureUniform(shader, mat, mat.HasRoughnessMap, "RoughnessMap", matex);
else if (matex.Type == MatTexture.TextureType.TeamColor)
TextureUniform(shader, mat, mat.HasTeamColorMap, "TeamColorMap", matex);
else if (matex.Type == MatTexture.TextureType.Transparency)
TextureUniform(shader, mat, mat.HasTransparencyMap, "TransparencyMap", matex);
else if (matex.Type == MatTexture.TextureType.DiffuseLayer2)
TextureUniform(shader, mat, mat.HasDiffuseLayer, "DiffuseLayer", matex);
else if (matex.Type == MatTexture.TextureType.SphereMap)
TextureUniform(shader, mat, mat.HasSphereMap, "SphereMap", matex);
else if (matex.Type == MatTexture.TextureType.SubSurfaceScattering)
TextureUniform(shader, mat, mat.HasSubSurfaceScatteringMap, "SubSurfaceScatteringMap", matex);
else if (matex.Type == MatTexture.TextureType.MRA)
TextureUniform(shader, mat, mat.HasMRA, "MRA", matex);
}
}
private static void LoadPBRMaps(SF.Shader shader)
{
GL.ActiveTexture(TextureUnit.Texture0 + 26);
RenderTools.specularPbr.Bind();
GL.Uniform1(shader.GetUniformLocation("specularIbl"), 26);
// GL.GenerateMipmap(GenerateMipmapTarget.TextureCubeMap);
// PBR IBL
GL.ActiveTexture(TextureUnit.Texture0 + 25);
RenderTools.diffusePbr.Bind();
GL.Uniform1(shader.GetUniformLocation("irradianceMap"), 25);
GL.ActiveTexture(TextureUnit.Texture0 + 27);
RenderTools.brdfPbr.Bind();
GL.Uniform1(shader.GetUniformLocation("brdfLUT"), 27);
}
private static void TextureUniform(SF.Shader shader, FMAT mat, bool hasTex, string name, MatTexture mattex)
{
if (mattex.textureState == STGenericMatTexture.TextureState.Binded)
return;
// Bind the texture and create the uniform if the material has the right textures.
if (hasTex)
{
GL.Uniform1(shader.GetUniformLocation(name), BindTexture(shader, mattex, mat.GetResFileU() != null));
}
}
public static int BindTexture(SF.Shader shader, MatTexture tex, bool IsWiiU)
{
GL.ActiveTexture(TextureUnit.Texture0 + tex.textureUnit + 1);
GL.BindTexture(TextureTarget.Texture2D, RenderTools.defaultTex.RenderableTex.TexID);
string activeTex = tex.Name;
if (tex.animatedTexName != "")
activeTex = tex.animatedTexName;
if (IsWiiU)
{
foreach (var ftexContainer in PluginRuntime.ftexContainers)
{
if (ftexContainer.ResourceNodes.ContainsKey(activeTex))
{
FTEX ftex = (FTEX)ftexContainer.ResourceNodes[activeTex];
if (ftex.RenderableTex == null || !ftex.RenderableTex.GLInitialized)
ftex.LoadOpenGLTexture();
BindGLTexture(tex, ftex.RenderableTex.TexID);
}
}
}
else
{
foreach (var bntx in PluginRuntime.bntxContainers)
{
if (bntx.Textures.ContainsKey(activeTex))
{
if (bntx.Textures[activeTex].RenderableTex == null ||
!bntx.Textures[activeTex].RenderableTex.GLInitialized)
{
bntx.Textures[activeTex].LoadOpenGLTexture();
}
BindGLTexture(tex, bntx.Textures[activeTex].RenderableTex.TexID);
}
}
}
return tex.textureUnit + 1;
}
private static void BindGLTexture(MatTexture tex, int texid)
{
// GL.ActiveTexture(TextureUnit.Texture0 + texid);
GL.BindTexture(TextureTarget.Texture2D, texid);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)MatTexture.wrapmode[tex.wrapModeS]);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)MatTexture.wrapmode[tex.wrapModeT]);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)MatTexture.minfilter[tex.minFilter]);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)MatTexture.magfilter[tex.magFilter]);
GL.TexParameter(TextureTarget.Texture2D, (TextureParameterName)ExtTextureFilterAnisotropic.TextureMaxAnisotropyExt, 0.0f);
}
private void DrawModel(FSHP m, FMDL mdl, SF.Shader shader, bool ModelSelected)
{
if (m.lodMeshes[m.DisplayLODIndex].faces.Count <= 3)
return;
var mat = m.GetMaterial();
if (shader != OpenTKSharedResources.shaders["BFRES_Normals"])
{
SetRenderPass(mat, shader, m, m.DisplayId);
SetUniforms(mat, shader, m, m.DisplayId);
SetTextureUniforms(mat, m, shader);
}
SetBoneUniforms(shader, mdl, m);
ApplyTransformFix(mdl, m, shader);
SetVertexAttributes(m, shader);
//Check the binded bone if it's visible from bone visual anims
// if (!mdl.Skeleton.bones[m.boneIndx].Visible)
// m.Checked = false;
if (m.Checked && mdl.Skeleton.bones.Count > 0 && mdl.Skeleton.bones[m.BoneIndex].Visible && mat.Enabled)
{
shader.SetVector3("materialSelectColor", new Vector3(0));
if (m.GetMaterial().IsSelected)
{
shader.SetVector3("materialSelectColor", ColorUtility.ToVector3(Color.FromArgb(0,163,204)));
DrawModelSelection(m, shader);
}
else if (m.IsSelected || ModelSelected)
{
DrawModelSelection(m, shader);
}
else
{
if (Runtime.RenderModelWireframe)
{
DrawModelWireframe(m, shader);
}
if (Runtime.RenderModels)
{
DrawMdoelHoverSelection(m, shader, IsSelected(), Hovered);
PrimitiveType primitiveType = PrimitiveType.Triangles;
switch (m.lodMeshes[m.DisplayLODIndex].PrimitiveType)
{
case STPolygonType.Line:
primitiveType = PrimitiveType.Lines;
break;
case STPolygonType.LineStrip:
primitiveType = PrimitiveType.LineStrip;
break;
case STPolygonType.Point:
primitiveType = PrimitiveType.Points;
break;
case STPolygonType.Triangle:
primitiveType = PrimitiveType.Triangles;
break;
}
GL.DrawElements(primitiveType, m.lodMeshes[m.DisplayLODIndex].displayFaceSize, DrawElementsType.UnsignedInt, m.Offset);
}
}
}
}
private static void ApplyTransformFix(FMDL fmdl, FSHP m, SF.Shader shader)
{
Matrix4 idenity = Matrix4.Identity;
shader.SetInt("NoSkinning", 0);
shader.SetInt("RigidSkinning", 0);
shader.SetInt("SingleBoneIndex", m.BoneIndex);
shader.SetMatrix4x4("SingleBoneBindTransform", ref idenity);
//Some objects will have no weights or indices. These will weigh to the bone index in the shape section.
if (m.VertexSkinCount == 1)
{
shader.SetInt("RigidSkinning", 1);
}
if (m.VertexSkinCount == 0)
{
if (fmdl.Skeleton.bones.Count > 0)
{
Matrix4 transform = fmdl.Skeleton.bones[m.BoneIndex].invert * fmdl.Skeleton.bones[m.BoneIndex].Transform;
shader.SetMatrix4x4("SingleBoneBindTransform", ref transform);
shader.SetInt("NoSkinning", 1);
}
}
}
static bool Loaded = false;
public void UpdateVertexData()
{
if (!Runtime.OpenTKInitialized)
return;
STProgressBar progressBar = new STProgressBar();
progressBar.Task = "Updating Vertex Data...";
progressBar.Value = 0;
progressBar.StartPosition = FormStartPosition.CenterScreen;
progressBar.Show();
progressBar.Refresh();
Loaded = false;
DisplayVertex[] Vertices;
int[] Faces;
int poffset = 0;
int voffset = 0;
List<DisplayVertex> Vs = new List<DisplayVertex>();
List<int> Ds = new List<int>();
int TotalShapeCount = models.Sum(b => b.shapes.Count);
int curShape = 0;
int value = 0;
foreach (FMDL mdl in models)
{
//Reset min/max
mdl.MaxPosition = new Vector3(0);
mdl.MinPosition = new Vector3(0);
foreach (FSHP m in mdl.shapes)
{
progressBar.Task = "Updating Shape... " + m.Text;
value = ((curShape * 100) / TotalShapeCount);
progressBar.Value = value;
progressBar.Refresh();
m.Offset = poffset * 4;
List<DisplayVertex> pv = m.CreateDisplayVertices(mdl);
Vs.AddRange(pv);
for (int i = 0; i < m.lodMeshes[m.DisplayLODIndex].displayFaceSize; i++)
{
Ds.Add(m.display[i] + voffset);
}
poffset += m.lodMeshes[m.DisplayLODIndex].displayFaceSize;
voffset += pv.Count;
curShape++;
}
}
progressBar.Value = 100;
progressBar.Close();
// Binds
Vertices = Vs.ToArray();
Faces = Ds.ToArray();
// Bind only once!
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
GL.BufferData<DisplayVertex>(BufferTarget.ArrayBuffer, (IntPtr)(Vertices.Length * DisplayVertex.Size), Vertices, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
GL.BufferData<int>(BufferTarget.ElementArrayBuffer, (IntPtr)(Faces.Length * sizeof(int)), Faces, BufferUsageHint.StaticDraw);
LibraryGUI.Instance.UpdateViewport();
Loaded = true;
}
public void UpdateSingleMaterialTextureMaps(FMAT mat)
{
if (!Runtime.OpenTKInitialized)
return;
foreach (BNTX bntx in PluginRuntime.bntxContainers)
{
foreach (var t in mat.TextureMaps)
{
if (bntx.Textures.ContainsKey(t.Name))
{
if (!bntx.Textures[t.Name].RenderableTex.GLInitialized)
bntx.Textures[t.Name].LoadOpenGLTexture();
}
}
}
LibraryGUI.Instance.UpdateViewport();
}
public void UpdateTextureMaps()
{
if (!Runtime.OpenTKInitialized)
return;
foreach (BNTX bntx in PluginRuntime.bntxContainers)
{
if (!bntx.AllGLInitialized)
{
foreach (var tex in bntx.Textures)
{
if (!tex.Value.RenderableTex.GLInitialized)
tex.Value.LoadOpenGLTexture();
}
}
}
foreach (BFRESGroupNode ftexCont in PluginRuntime.ftexContainers)
{
foreach (var tex in ftexCont.ResourceNodes)
{
if (!((FTEX)tex.Value).RenderableTex.GLInitialized)
((FTEX)tex.Value).LoadOpenGLTexture();
}
}
LibraryGUI.Instance.UpdateViewport();
}
private static void SetRenderPass(FMAT mat, SF.Shader shader, FSHP m, int id)
{
if (mat.shaderassign.ShaderArchive == "Turbo_UBER")
{
AglShaderTurbo aglShader = new AglShaderTurbo();
foreach (var renderInfo in mat.renderinfo)
aglShader.LoadRenderInfo(renderInfo);
// aglShader.LoadRenderPass(mat, shader);
}
}
private static void SetUniforms(FMAT mat, SF.Shader shader, FSHP m, int id)
{
shader.SetBoolToInt("isTransparent", mat.isTransparent);
shader.SetFloat("ao_density", 1);
shader.SetFloat("shadow_density", 1);
shader.SetFloat("normal_map_weight", 1);
//Bake map UV coordinate ST
shader.SetVector4("gsys_bake_st0", new Vector4(1, 1, 0, 0));
shader.SetVector4("gsys_bake_st1", new Vector4(1, 1, 0, 0));
//Colors
shader.SetVector4("const_color0", new Vector4(1, 1, 1, 1));
shader.SetVector4("base_color_mul_color", new Vector4(1, 1, 1, 1));
shader.SetVector3("albedo_tex_color", new Vector3(1, 1, 1));
shader.SetVector3("emission_color", new Vector3(1, 1, 1));
shader.SetVector3("specular_color", new Vector3(1, 1, 1));
shader.SetFloat("fuv1_mtx", 0);
//SRT
shader.SetVector4("tex_mtx0", new Vector4(1, 1, 1, 1));
shader.SetVector2("SRT_Scale", new Vector2(1, 1));
shader.SetFloat("SRT_Rotate", 0);
shader.SetVector2("SRT_Translate", new Vector2(0, 0));
shader.SetInt("selectedBoneIndex", Runtime.SelectedBoneIndex);
SetUniformData(mat, shader, "base_color_mul_color");
shader.SetInt("enableCellShading", 0);
bool HasTans = m.vertexAttributes.Any(x => x.Name == "_t0");
shader.SetBoolToInt("hasTangents", HasTans);
SetUniformData(mat, shader, "fuv1_mtx");
SetUniformData(mat, shader, "gsys_bake_st0");
SetUniformData(mat, shader, "gsys_bake_st1");
SetUniformData(mat, shader, "ao_density");
SetUniformData(mat, shader, "shadow_density");
SetUniformData(mat, shader, "normal_map_weight");
SetUniformData(mat, shader, "const_color0");
SetUniformData(mat, shader, "base_color_mul_color");
SetUniformData(mat, shader, "albedo_tex_color");
SetUniformData(mat, shader, "emission_color");
SetUniformData(mat, shader, "specular_color");
//This uniform sets various maps for BOTW to use second UV channel
SetUniformData(mat, shader, "uking_texture2_texcoord");
SetUniformData(mat, shader, "cIsEnableNormalMap");
SetUniformData(mat, shader, "tex_mtx0");
//Sets shadow type
//0 = Ambient occusion bake map
//1 = Shadow
//2 = Shadow + Ambient occusion map
SetUniformData(mat, shader, "bake_shadow_type");
SetUniformData(mat, shader, "bake_light_type");
SetUniformData(mat, shader, "gsys_bake_light_scale");
SetUniformData(mat, shader, "enable_projection_light");
SetUniformData(mat, shader, "enable_actor_light");
SetUniformData(mat, shader, "bake_calc_type");
}
private static void SetUniformData(FMAT mat, SF.Shader shader, string propertyName)
{
if (mat.shaderassign.options.ContainsKey(propertyName))
{
float value = float.Parse(mat.shaderassign.options[propertyName]);
shader.SetFloat(propertyName, value);
}
if (mat.matparam.ContainsKey(propertyName))
{
if (mat.matparam[propertyName].Type == ShaderParamType.Float)
{
if (mat.anims.ContainsKey(propertyName))
mat.matparam[propertyName].ValueFloat[0] = mat.anims[propertyName][0];
shader.SetFloat(propertyName, mat.matparam[propertyName].ValueFloat[0]);
}
if (mat.matparam[propertyName].Type == ShaderParamType.Float2)
{
if (mat.anims.ContainsKey(propertyName))
{
mat.matparam[propertyName].ValueFloat = new float[2] {
mat.anims[propertyName][0], mat.anims[propertyName][1]};
}
shader.SetVector2(propertyName, Utils.ToVec2(mat.matparam[propertyName].ValueFloat));
}
if (mat.matparam[propertyName].Type == ShaderParamType.Float3)
{
if (mat.anims.ContainsKey(propertyName))
{
mat.matparam[propertyName].ValueFloat = new float[3] {
mat.anims[propertyName][0],
mat.anims[propertyName][1],
mat.anims[propertyName][2]};
}
shader.SetVector3(propertyName, Utils.ToVec3(mat.matparam[propertyName].ValueFloat));
}
if (mat.matparam[propertyName].Type == ShaderParamType.Float4)
{
if (mat.anims.ContainsKey(propertyName))
{
mat.matparam[propertyName].ValueFloat = new float[4] {
mat.anims[propertyName][0], mat.anims[propertyName][1],
mat.anims[propertyName][2], mat.anims[propertyName][3]};
}
shader.SetVector4(propertyName, Utils.ToVec4(mat.matparam[propertyName].ValueFloat));
}
if (mat.matparam[propertyName].Type == ShaderParamType.TexSrt)
{
// Vector 2 Scale
// 1 roation float
// Vector2 translate
TexSrt texSRT = mat.matparam[propertyName].ValueTexSrt;
shader.SetVector2("SRT_Scale", Utils.ToVec2(texSRT.Scaling));
shader.SetFloat("SRT_Rotate", texSRT.Rotation);
shader.SetVector2("SRT_Translate", Utils.ToVec2(texSRT.Translation));
}
}
if (mat.animatedMatParams.ContainsKey(propertyName))
{
if (mat.animatedMatParams[propertyName].Type == ShaderParamType.Float)
{
if (mat.anims.ContainsKey(propertyName))
mat.animatedMatParams[propertyName].ValueFloat[0] = mat.anims[propertyName][0];
shader.SetFloat(propertyName, mat.animatedMatParams[propertyName].ValueFloat[0]);
}
if (mat.animatedMatParams[propertyName].Type == ShaderParamType.Float2)
{
if (mat.anims.ContainsKey(propertyName))
{
mat.animatedMatParams[propertyName].ValueFloat = new float[2] {
mat.anims[propertyName][0], mat.anims[propertyName][1]};
}
shader.SetVector2(propertyName, Utils.ToVec2(mat.animatedMatParams[propertyName].ValueFloat));
}
if (mat.animatedMatParams[propertyName].Type == ShaderParamType.Float3)
{
Console.WriteLine(propertyName + " " + mat.animatedMatParams[propertyName].ValueFloat);
if (mat.anims.ContainsKey(propertyName))
{
mat.animatedMatParams[propertyName].ValueFloat = new float[3] {
mat.anims[propertyName][0],
mat.anims[propertyName][1],
mat.anims[propertyName][2]};
}
shader.SetVector3(propertyName, Utils.ToVec3(mat.animatedMatParams[propertyName].ValueFloat));
}
if (mat.animatedMatParams[propertyName].Type == ShaderParamType.Float4)
{
if (mat.anims.ContainsKey(propertyName))
{
mat.animatedMatParams[propertyName].ValueFloat = new float[4] {
mat.anims[propertyName][0], mat.anims[propertyName][1],
mat.anims[propertyName][2], mat.anims[propertyName][3]};
}
shader.SetVector4(propertyName, Utils.ToVec4(mat.animatedMatParams[propertyName].ValueFloat));
}
if (mat.animatedMatParams[propertyName].Type == ShaderParamType.TexSrt)
{
// Vector 2 Scale
// 1 roation float
// Vector2 translate
TexSrt texSRT = mat.animatedMatParams[propertyName].ValueTexSrt;
shader.SetVector2("SRT_Scale", Utils.ToVec2(texSRT.Scaling));
shader.SetFloat("SRT_Rotate", texSRT.Rotation);
shader.SetVector2("SRT_Translate", Utils.ToVec2(texSRT.Translation));
}
}
}
private void SetVertexAttributes(FSHP m, SF.Shader shader)
{
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
GL.VertexAttribPointer(shader.GetAttribLocation("vPosition"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 0);
GL.VertexAttribPointer(shader.GetAttribLocation("vNormal"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 12);
GL.VertexAttribPointer(shader.GetAttribLocation("vTangent"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 24);
GL.VertexAttribPointer(shader.GetAttribLocation("vBitangent"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 36);
GL.VertexAttribPointer(shader.GetAttribLocation("vUV0"), 2, VertexAttribPointerType.Float, false, DisplayVertex.Size, 48);
GL.VertexAttribPointer(shader.GetAttribLocation("vColor"), 4, VertexAttribPointerType.Float, false, DisplayVertex.Size, 56);
GL.VertexAttribIPointer(shader.GetAttribLocation("vBone"), 4, VertexAttribIntegerType.Int, DisplayVertex.Size, new IntPtr(72));
GL.VertexAttribPointer(shader.GetAttribLocation("vWeight"), 4, VertexAttribPointerType.Float, false, DisplayVertex.Size, 88);
GL.VertexAttribPointer(shader.GetAttribLocation("vUV1"), 2, VertexAttribPointerType.Float, false, DisplayVertex.Size, 104);
GL.VertexAttribPointer(shader.GetAttribLocation("vUV2"), 2, VertexAttribPointerType.Float, false, DisplayVertex.Size, 112);
GL.VertexAttribPointer(shader.GetAttribLocation("vPosition2"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 124);
GL.VertexAttribPointer(shader.GetAttribLocation("vPosition3"), 3, VertexAttribPointerType.Float, false, DisplayVertex.Size, 136);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
}
private static void DrawMdoelHoverSelection(STGenericObject p, SF.Shader shader,
bool IsSelected, bool IsHovered)
{
if (IsHovered && IsSelected)
shader.SetVector4("pickingColor", hoverColor);
else if (IsHovered || IsSelected)
shader.SetVector4("pickingColor", selectColor);
else
shader.SetVector4("pickingColor", new Vector4(1));
}
private static void DrawModelWireframe(STGenericObject p, SF.Shader shader)
{
// use vertex color for wireframe color
shader.SetInt("colorOverride", 1);
GL.PolygonMode(MaterialFace.Front, PolygonMode.Line);
GL.Enable(EnableCap.LineSmooth);
GL.LineWidth(1.5f);
GL.DrawElements(PrimitiveType.Triangles, p.lodMeshes[p.DisplayLODIndex].displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
shader.SetInt("colorOverride", 0);
}
private static void DrawModelSelection(STGenericObject p, SF.Shader shader)
{
//This part needs to be reworked for proper outline. Currently would make model disappear
/* GL.Enable(EnableCap.DepthTest);
GL.StencilOp(StencilOp.Keep, StencilOp.Keep, StencilOp.Replace);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
GL.StencilMask(0x00);
GL.StencilFunc(StencilFunction.Always, 1, 0xFF); // all fragments should update the stencil buffer
GL.StencilMask(0xFF); // enable writing to the stencil buffer
GL.DrawElements(PrimitiveType.Triangles, p.lodMeshes[p.DisplayLODIndex].displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
GL.StencilFunc(StencilFunction.Notequal, 1, 0xFF);
GL.StencilMask(0x00); // enable writing to the stencil buffer
GL.Disable(EnableCap.DepthTest);
shader.SetInt("colorOverride", 1);
GL.PolygonMode(MaterialFace.Front, PolygonMode.Line);
GL.LineWidth(2.0f);
GL.DrawElements(PrimitiveType.Triangles, p.lodMeshes[p.DisplayLODIndex].displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
shader.SetInt("colorOverride", 0);
GL.StencilMask(0xFF);
GL.Enable(EnableCap.DepthTest);*/
// Override the model color with white in the shader.
shader.SetInt("colorOverride", 1);
GL.PolygonMode(MaterialFace.Front, PolygonMode.Line);
GL.Enable(EnableCap.LineSmooth);
GL.LineWidth(1.3f);
GL.DrawElements(PrimitiveType.Triangles, p.lodMeshes[p.DisplayLODIndex].displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
shader.SetInt("colorOverride", 0);
GL.DrawElements(PrimitiveType.Triangles, p.lodMeshes[p.DisplayLODIndex].displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
}
/* public override BoundingBox GetSelectionBox()
{
Vector3 Min = new Vector3(0);
Vector3 Max = new Vector3(0);
foreach (var model in models)
{
foreach (var shape in model.shapes)
{
foreach (var vertex in shape.vertices)
{
Min.X = Math.Min(Min.X, vertex.pos.X);
Min.Y = Math.Min(Min.Y, vertex.pos.Y);
Min.Z = Math.Min(Min.Z, vertex.pos.Z);
Max.X = Math.Max(Max.X, vertex.pos.X);
Max.Y = Math.Max(Max.Y, vertex.pos.Y);
Max.Z = Math.Max(Max.Z, vertex.pos.Z);
}
}
}
return new BoundingBox()
{
minX = Min.X,
minY = Min.Y,
minZ = Min.Z,
maxX = Max.X,
maxY = Max.Y,
maxZ = Max.Z,
};
}
public override uint SelectAll(GL_ControlBase control)
{
Selected = true;
return REDRAW;
}
public override uint SelectDefault(GL_ControlBase control)
{
Selected = true;
return REDRAW;
}
public override uint Select(int partIndex, GL_ControlBase control)
{
Selected = true;
return REDRAW;
}
public override uint Deselect(int partIndex, GL_ControlBase control)
{
Selected = false;
return REDRAW;
}
public override LocalOrientation GetLocalOrientation(int partIndex)
{
return new LocalOrientation(position);
}
public override bool TryStartDragging(DragActionType actionType, int hoveredPart, out LocalOrientation localOrientation, out bool dragExclusively)
{
localOrientation = new LocalOrientation(position);
dragExclusively = false;
return Selected;
}
public override bool IsInRange(float range, float rangeSquared, Vector3 pos)
{
range = 20000; //Make the range large for now. Todo go back to this
BoundingBox box = GetSelectionBox();
if (pos.X < box.maxX + range && pos.X > box.minX - range &&
pos.Y < box.maxY + range && pos.Y > box.minY - range &&
pos.Z < box.maxZ + range && pos.Z > box.minZ - range)
return true;
return false;
}
public override uint DeselectAll(GL_ControlBase control)
{
Selected = false;
return REDRAW;
}
public override Vector3 Position
{
get
{
return position;
}
set
{
position = value;
}
}*/
#endregion
}
}