mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2024-11-10 07:04:36 +00:00
Improve gfmdl support. Fix raw astc exporting
This commit is contained in:
parent
6f22257113
commit
067244555a
28 changed files with 2663 additions and 87 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -191,7 +191,7 @@ namespace FirstPlugin
|
|||
reader.Seek((long)FileInfoOffset, SeekOrigin.Begin);
|
||||
for (int i = 0; i < FileCount; i++)
|
||||
{
|
||||
FileEntry fileEntry = new FileEntry();
|
||||
FileEntry fileEntry = new FileEntry(this);
|
||||
fileEntry.Read(reader);
|
||||
fileEntry.FileName = GetString(hashes[i], fileEntry.FileData);
|
||||
files.Add(fileEntry);
|
||||
|
@ -320,6 +320,34 @@ namespace FirstPlugin
|
|||
public uint CompressedFileSize;
|
||||
public uint padding;
|
||||
|
||||
private IArchiveFile ArchiveFile;
|
||||
|
||||
public FileEntry(IArchiveFile archiveFile) {
|
||||
ArchiveFile = archiveFile;
|
||||
}
|
||||
|
||||
private bool IsTexturesLoaded = false;
|
||||
public override IFileFormat OpenFile()
|
||||
{
|
||||
var FileFormat = base.OpenFile();
|
||||
bool IsModel = FileFormat is GFBMDL;
|
||||
|
||||
if (IsModel && !IsTexturesLoaded)
|
||||
{
|
||||
IsTexturesLoaded = true;
|
||||
foreach (var file in ArchiveFile.Files)
|
||||
{
|
||||
if (Utils.GetExtension(file.FileName) == ".bntx")
|
||||
{
|
||||
file.FileFormat = file.OpenFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return base.OpenFile();
|
||||
}
|
||||
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
unkown = reader.ReadUInt16(); //Usually 9?
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Switch_Toolbox;
|
||||
using System.Windows.Forms;
|
||||
using Switch_Toolbox.Library;
|
||||
using Switch_Toolbox.Library.IO;
|
||||
using Switch_Toolbox.Library.Forms;
|
||||
using Switch_Toolbox.Library.Rendering;
|
||||
using OpenTK;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
|
@ -83,12 +85,15 @@ namespace FirstPlugin
|
|||
}
|
||||
|
||||
public Header header;
|
||||
public GFBMDL_Render Renderer;
|
||||
|
||||
public DrawableContainer DrawableContainer = new DrawableContainer();
|
||||
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
Text = FileName;
|
||||
DrawableContainer.Name = FileName;
|
||||
Renderer = new GFBMDL_Render();
|
||||
|
||||
header = new Header();
|
||||
header.Read(new FileReader(stream), this);
|
||||
|
@ -105,6 +110,7 @@ namespace FirstPlugin
|
|||
return mem.ToArray();
|
||||
}
|
||||
|
||||
//Todo replace tedius offset handling with a class to store necessary data and methods to execute
|
||||
public class Header
|
||||
{
|
||||
public STSkeleton Skeleton { get; set; }
|
||||
|
@ -112,12 +118,18 @@ namespace FirstPlugin
|
|||
public uint Version { get; set; }
|
||||
public float[] Boundings { get; set; }
|
||||
public List<string> TextureMaps = new List<string>();
|
||||
public List<string> Materials = new List<string>();
|
||||
public List<string> MaterialNames = new List<string>();
|
||||
public List<VertexBuffer> VertexBuffers = new List<VertexBuffer>();
|
||||
public List<VisGroup> VisualGroups = new List<VisGroup>();
|
||||
public List<MaterialShaderData> Materials = new List<MaterialShaderData>();
|
||||
|
||||
public List<GFBMaterial> GenericMaterials = new List<GFBMaterial>();
|
||||
|
||||
public void Read(FileReader reader, GFBMDL Root)
|
||||
{
|
||||
Skeleton = new STSkeleton();
|
||||
Root.DrawableContainer.Drawables.Add(Skeleton);
|
||||
Root.DrawableContainer.Drawables.Add(Root.Renderer);
|
||||
|
||||
reader.SetByteOrder(false);
|
||||
|
||||
|
@ -125,34 +137,71 @@ namespace FirstPlugin
|
|||
Boundings = reader.ReadSingles(9);
|
||||
long TextureOffset = reader.ReadOffset(true, typeof(uint));
|
||||
long MaterialOffset = reader.ReadOffset(true, typeof(uint));
|
||||
long UnknownOffset = reader.ReadOffset(true, typeof(uint));
|
||||
long Unknown1ffset = reader.ReadOffset(true, typeof(uint));
|
||||
long Unknown2Offset = reader.ReadOffset(true, typeof(uint));
|
||||
long ShaderOffset = reader.ReadOffset(true, typeof(uint));
|
||||
long VisGroupOffset = reader.ReadOffset(true, typeof(uint));
|
||||
long VertexDataOffset = reader.ReadOffset(true, typeof(uint));
|
||||
long VerteBufferOffset = reader.ReadOffset(true, typeof(uint));
|
||||
long BoneDataOffset = reader.ReadOffset(true, typeof(uint));
|
||||
|
||||
if (TextureOffset != 0)
|
||||
{
|
||||
reader.Seek(TextureOffset, SeekOrigin.Begin);
|
||||
reader.SeekBegin(TextureOffset);
|
||||
uint Count = reader.ReadUInt32();
|
||||
TextureMaps = reader.ReadNameOffsets(Count, true, typeof(uint), true);
|
||||
}
|
||||
|
||||
if (MaterialOffset != 0)
|
||||
{
|
||||
reader.Seek(MaterialOffset, SeekOrigin.Begin);
|
||||
reader.SeekBegin(MaterialOffset);
|
||||
uint Count = reader.ReadUInt32();
|
||||
Materials = reader.ReadNameOffsets(Count, true, typeof(uint));
|
||||
MaterialNames = reader.ReadNameOffsets(Count, true, typeof(uint));
|
||||
}
|
||||
|
||||
|
||||
if (ShaderOffset != 0)
|
||||
{
|
||||
reader.SeekBegin(ShaderOffset);
|
||||
uint Count = reader.ReadUInt32();
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
MaterialShaderData shaderData = new MaterialShaderData();
|
||||
shaderData.Read(reader);
|
||||
Materials.Add(shaderData);
|
||||
}
|
||||
}
|
||||
|
||||
if (VisGroupOffset != 0)
|
||||
{
|
||||
reader.SeekBegin(VisGroupOffset);
|
||||
uint Count = reader.ReadUInt32();
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
VisGroup visualGroup = new VisGroup();
|
||||
visualGroup.Read(reader);
|
||||
VisualGroups.Add(visualGroup);
|
||||
}
|
||||
}
|
||||
|
||||
if (VerteBufferOffset != 0)
|
||||
{
|
||||
reader.SeekBegin(VerteBufferOffset);
|
||||
uint Count = reader.ReadUInt32();
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
VertexBuffer vertexBuffer = new VertexBuffer();
|
||||
vertexBuffer.Read(reader);
|
||||
VertexBuffers.Add(vertexBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (BoneDataOffset != 0)
|
||||
{
|
||||
Root.Nodes.Add("Skeleton");
|
||||
TreeNode SkeletonWrapper = new TreeNode("Skeleton");
|
||||
Root.Nodes.Add(SkeletonWrapper);
|
||||
|
||||
reader.Seek(BoneDataOffset, SeekOrigin.Begin);
|
||||
reader.SeekBegin(BoneDataOffset);
|
||||
uint Count = reader.ReadUInt32();
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
var bone = new Bone(Skeleton);
|
||||
|
@ -163,10 +212,105 @@ namespace FirstPlugin
|
|||
foreach (var bone in Skeleton.bones)
|
||||
{
|
||||
if (bone.Parent == null)
|
||||
Root.Nodes[0].Nodes.Add(bone);
|
||||
SkeletonWrapper.Nodes.Add(bone);
|
||||
}
|
||||
}
|
||||
|
||||
TreeNode MaterialFolderWrapper = new TreeNode("Materials");
|
||||
Root.Nodes.Add(MaterialFolderWrapper);
|
||||
|
||||
for (int i = 0; i < Materials.Count; i++)
|
||||
{
|
||||
GFBMaterial mat = new GFBMaterial(Root);
|
||||
mat.Text = Materials[i].Name;
|
||||
|
||||
int textureUnit = 1;
|
||||
foreach (var textureMap in Materials[i].TextureMaps)
|
||||
{
|
||||
textureMap.Name = TextureMaps[(int)textureMap.Index];
|
||||
|
||||
STGenericMatTexture matTexture = new STGenericMatTexture();
|
||||
matTexture.Name = textureMap.Name;
|
||||
matTexture.textureUnit = textureUnit++;
|
||||
matTexture.wrapModeS = 0;
|
||||
matTexture.wrapModeT = 0;
|
||||
|
||||
if (textureMap.Effect == "Col0Tex")
|
||||
{
|
||||
matTexture.Type = STGenericMatTexture.TextureType.Diffuse;
|
||||
}
|
||||
|
||||
mat.TextureMaps.Add(matTexture);
|
||||
|
||||
if (textureMap.Effect != string.Empty)
|
||||
mat.Nodes.Add($"{textureMap.Name} ({textureMap.Effect})");
|
||||
else
|
||||
mat.Nodes.Add($"{textureMap.Name}");
|
||||
}
|
||||
|
||||
GenericMaterials.Add(mat);
|
||||
MaterialFolderWrapper.Nodes.Add(mat);
|
||||
}
|
||||
|
||||
TreeNode VisualGroupWrapper = new TreeNode("Visual Groups");
|
||||
Root.Nodes.Add(VisualGroupWrapper);
|
||||
|
||||
for (int i = 0; i < VisualGroups.Count; i++)
|
||||
{
|
||||
GFBMesh mesh = new GFBMesh(Root);
|
||||
mesh.Checked = true;
|
||||
mesh.ImageKey = "model";
|
||||
mesh.SelectedImageKey = "model";
|
||||
|
||||
mesh.BoneIndex = (int)VisualGroups[i].BoneIndex;
|
||||
mesh.Text = Skeleton.bones[(int)VisualGroups[i].BoneIndex].Text;
|
||||
Root.Renderer.Meshes.Add(mesh);
|
||||
|
||||
var Buffer = VertexBuffers[i];
|
||||
for (int v= 0; v < Buffer.Positions.Count; v++)
|
||||
{
|
||||
Vertex vertex = new Vertex();
|
||||
vertex.pos = Buffer.Positions[v];
|
||||
|
||||
if (Buffer.Normals.Count > 0)
|
||||
vertex.nrm = Buffer.Normals[v];
|
||||
if (Buffer.TexCoord1.Count > 0)
|
||||
vertex.uv0 = Buffer.TexCoord1[v];
|
||||
if (Buffer.TexCoord2.Count > 0)
|
||||
vertex.uv1 = Buffer.TexCoord2[v];
|
||||
if (Buffer.TexCoord3.Count > 0)
|
||||
vertex.uv2 = Buffer.TexCoord3[v];
|
||||
if (Buffer.Weights.Count > 0)
|
||||
vertex.boneWeights = new List<float>(Buffer.Weights[v]);
|
||||
if (Buffer.BoneIndex.Count > 0)
|
||||
vertex.boneIds = new List<int>(Buffer.BoneIndex[v]);
|
||||
if (Buffer.Colors1.Count > 0)
|
||||
vertex.col = Buffer.Colors1[v];
|
||||
if (Buffer.Binormals.Count > 0)
|
||||
vertex.bitan = Buffer.Binormals[v];
|
||||
|
||||
mesh.vertices.Add(vertex);
|
||||
}
|
||||
|
||||
int polyIndex = 0;
|
||||
foreach (var group in Buffer.PolygonGroups)
|
||||
{
|
||||
TreeNode polyWrapper = new TreeNode($"Polygon Group {polyIndex++}");
|
||||
polyWrapper.ImageKey = "mesh";
|
||||
polyWrapper.SelectedImageKey = "mesh";
|
||||
|
||||
var polygonGroup = new STGenericPolygonGroup();
|
||||
polygonGroup.faces = group.Faces.ToList();
|
||||
polygonGroup.MaterialIndex = group.MaterialID;
|
||||
mesh.PolygonGroups.Add(polygonGroup);
|
||||
|
||||
mesh.Nodes.Add(polyWrapper);
|
||||
}
|
||||
|
||||
VisualGroupWrapper.Nodes.Add(mesh);
|
||||
}
|
||||
|
||||
|
||||
Skeleton.update();
|
||||
Skeleton.reset();
|
||||
}
|
||||
|
@ -177,6 +321,630 @@ namespace FirstPlugin
|
|||
}
|
||||
}
|
||||
|
||||
public class VisGroup
|
||||
{
|
||||
public Vector3 BoundingBoxMax = new Vector3(0);
|
||||
public Vector3 BoundingBoxMin = new Vector3(0);
|
||||
|
||||
public uint BoneIndex { get; set; }
|
||||
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
long DataPosition = reader.Position;
|
||||
var DataOffset = reader.ReadOffset(true, typeof(uint));
|
||||
|
||||
reader.SeekBegin(DataOffset);
|
||||
long InfoPosition = reader.Position;
|
||||
|
||||
int InfoOffset = reader.ReadInt32();
|
||||
|
||||
//Read the info section for position data
|
||||
reader.SeekBegin(InfoPosition - InfoOffset);
|
||||
ushort HeaderLength = reader.ReadUInt16();
|
||||
ushort UnknownPosition = 0;
|
||||
ushort VisBonePosition = 0;
|
||||
ushort Unknown2Position = 0;
|
||||
ushort VisBoundsPosition = 0;
|
||||
ushort Unknown3Position = 0;
|
||||
|
||||
if (HeaderLength == 0x0A)
|
||||
{
|
||||
UnknownPosition = reader.ReadUInt16();
|
||||
VisBonePosition = reader.ReadUInt16();
|
||||
Unknown2Position = reader.ReadUInt16();
|
||||
VisBoundsPosition = reader.ReadUInt16();
|
||||
}
|
||||
else if (HeaderLength == 0x0C)
|
||||
{
|
||||
UnknownPosition = reader.ReadUInt16();
|
||||
VisBonePosition = reader.ReadUInt16();
|
||||
Unknown2Position = reader.ReadUInt16();
|
||||
VisBoundsPosition = reader.ReadUInt16();
|
||||
Unknown3Position = reader.ReadUInt16();
|
||||
}
|
||||
else
|
||||
throw new Exception("Unexpected Header Length! " + HeaderLength);
|
||||
|
||||
if (VisBoundsPosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + VisBoundsPosition);
|
||||
BoundingBoxMin = reader.ReadVec3();
|
||||
BoundingBoxMax = reader.ReadVec3();
|
||||
}
|
||||
|
||||
if (VisBonePosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + VisBonePosition);
|
||||
BoneIndex = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
//Seek back to next in array
|
||||
reader.SeekBegin(DataPosition + sizeof(uint));
|
||||
}
|
||||
}
|
||||
|
||||
public class MaterialShaderData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string ShaderName { get; set; }
|
||||
|
||||
public List<TextureMap> TextureMaps = new List<TextureMap>();
|
||||
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
long DataPosition = reader.Position;
|
||||
var DataOffset = reader.ReadOffset(true, typeof(uint));
|
||||
|
||||
reader.SeekBegin(DataOffset);
|
||||
long InfoPosition = reader.Position;
|
||||
|
||||
int InfoOffset = reader.ReadInt32();
|
||||
|
||||
//Read the info section for position data
|
||||
reader.SeekBegin(InfoPosition - InfoOffset);
|
||||
ushort HeaderLength = reader.ReadUInt16();
|
||||
ushort ShaderPropertyPosition = reader.ReadUInt16();
|
||||
ushort MaterialStringNamePosition = reader.ReadUInt16();
|
||||
ushort ShaderStringNamePosition = reader.ReadUInt16();
|
||||
ushort Unknown1Position = reader.ReadUInt16();
|
||||
ushort Unknown2Position = reader.ReadUInt16();
|
||||
ushort Unknown3Position = reader.ReadUInt16();
|
||||
ushort ShaderParam1Position = reader.ReadUInt16();
|
||||
ushort ShaderParam2Position = reader.ReadUInt16();
|
||||
ushort ShaderParam3Position = reader.ReadUInt16();
|
||||
ushort ShaderParam4Position = reader.ReadUInt16();
|
||||
ushort ShaderParam5Position = reader.ReadUInt16();
|
||||
ushort ShaderParam6Position = reader.ReadUInt16();
|
||||
ushort TextureMapsPosition = reader.ReadUInt16();
|
||||
ushort ShaderParamAPosition = reader.ReadUInt16();
|
||||
ushort ShaderParamBPosition = reader.ReadUInt16();
|
||||
ushort ShaderParamCPosition = reader.ReadUInt16();
|
||||
ushort Unknown4Position = reader.ReadUInt16();
|
||||
ushort Unknown5Position = reader.ReadUInt16();
|
||||
ushort Unknown6Position = reader.ReadUInt16();
|
||||
ushort Unknown7Position = reader.ReadUInt16();
|
||||
ushort Unknown8Position = reader.ReadUInt16();
|
||||
ushort ShaderProperty2Position = reader.ReadUInt16();
|
||||
|
||||
if (MaterialStringNamePosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + MaterialStringNamePosition);
|
||||
Name = reader.ReadNameOffset(true, typeof(uint), true);
|
||||
}
|
||||
|
||||
if (ShaderStringNamePosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + ShaderStringNamePosition);
|
||||
ShaderName = reader.ReadNameOffset(true, typeof(uint), true);
|
||||
}
|
||||
|
||||
if (TextureMapsPosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + TextureMapsPosition);
|
||||
var TextureMapOffset = reader.ReadOffset(true, typeof(uint));
|
||||
reader.SeekBegin(TextureMapOffset);
|
||||
|
||||
uint Count = reader.ReadUInt32();
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
TextureMap textureMap = new TextureMap();
|
||||
textureMap.Read(reader);
|
||||
TextureMaps.Add(textureMap);
|
||||
}
|
||||
}
|
||||
|
||||
//Seek back to next in array
|
||||
reader.SeekBegin(DataPosition + sizeof(uint));
|
||||
}
|
||||
}
|
||||
|
||||
public class TextureMap
|
||||
{
|
||||
public string Effect { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public uint Index { get; set; } = 0;
|
||||
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
long DataPosition = reader.Position;
|
||||
var DataOffset = reader.ReadOffset(true, typeof(uint));
|
||||
|
||||
reader.SeekBegin(DataOffset);
|
||||
long InfoPosition = reader.Position;
|
||||
int InfoOffset = reader.ReadInt32();
|
||||
|
||||
//Read the info section for position data
|
||||
reader.SeekBegin(InfoPosition - InfoOffset);
|
||||
ushort HeaderSize = reader.ReadUInt16();
|
||||
ushort EffectPosition = 0;
|
||||
ushort UnknownPosition = 0;
|
||||
ushort IdPosition = 0;
|
||||
ushort UnknownPosition2 = 0;
|
||||
|
||||
if (HeaderSize == 0x0A)
|
||||
{
|
||||
EffectPosition = reader.ReadUInt16();
|
||||
UnknownPosition = reader.ReadUInt16();
|
||||
IdPosition = reader.ReadUInt16();
|
||||
UnknownPosition2 = reader.ReadUInt16();
|
||||
}
|
||||
else
|
||||
throw new Exception("Unexpected header size! " + HeaderSize);
|
||||
|
||||
if (EffectPosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + EffectPosition);
|
||||
uint NameLength = reader.ReadUInt32();
|
||||
Effect = reader.ReadString((int)NameLength);
|
||||
}
|
||||
|
||||
if (IdPosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + IdPosition);
|
||||
Index = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
//Seek back to next in array
|
||||
reader.SeekBegin(DataPosition + sizeof(uint));
|
||||
}
|
||||
}
|
||||
|
||||
public class VertexBuffer
|
||||
{
|
||||
public List<VertexAttribute> Attributes = new List<VertexAttribute>();
|
||||
public List<PolygonGroup> PolygonGroups = new List<PolygonGroup>();
|
||||
|
||||
public List<Vector3> Positions = new List<Vector3>();
|
||||
public List<Vector3> Normals = new List<Vector3>();
|
||||
public List<Vector2> TexCoord1 = new List<Vector2>();
|
||||
public List<Vector2> TexCoord2 = new List<Vector2>();
|
||||
public List<Vector2> TexCoord3 = new List<Vector2>();
|
||||
public List<Vector2> TexCoord4 = new List<Vector2>();
|
||||
public List<int[]> BoneIndex = new List<int[]>();
|
||||
public List<float[]> Weights = new List<float[]>();
|
||||
public List<Vector4> Colors1 = new List<Vector4>();
|
||||
public List<Vector4> Colors2 = new List<Vector4>();
|
||||
public List<Vector4> Binormals = new List<Vector4>();
|
||||
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
long DataPosition = reader.Position;
|
||||
var VertexBufferDataOffset = reader.ReadOffset(true, typeof(uint));
|
||||
|
||||
reader.SeekBegin(VertexBufferDataOffset);
|
||||
long InfoPosition = reader.Position;
|
||||
int InfoOffset = reader.ReadInt32();
|
||||
|
||||
//Read the info section for position data
|
||||
reader.SeekBegin(InfoPosition - InfoOffset);
|
||||
ushort InfoSize = reader.ReadUInt16();
|
||||
ushort VerticesPosition = 0;
|
||||
ushort FacesPosition = 0;
|
||||
ushort AttributeInfoPosition = 0;
|
||||
ushort BufferUnknownPosition = 0;
|
||||
|
||||
if (InfoSize == 0x0A)
|
||||
{
|
||||
BufferUnknownPosition = reader.ReadUInt16();
|
||||
FacesPosition = reader.ReadUInt16();
|
||||
AttributeInfoPosition = reader.ReadUInt16();
|
||||
VerticesPosition = reader.ReadUInt16();
|
||||
}
|
||||
else
|
||||
throw new Exception("Unexpected Vertex Buffer Info Header Size! " + InfoSize);
|
||||
|
||||
uint VertBufferStride = 0;
|
||||
|
||||
if (AttributeInfoPosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + AttributeInfoPosition);
|
||||
var AttributeOffset = reader.ReadOffset(true, typeof(uint));
|
||||
|
||||
reader.SeekBegin(AttributeOffset);
|
||||
uint AttributeCount = reader.ReadUInt32();
|
||||
|
||||
for (int i = 0; i < AttributeCount; i++)
|
||||
{
|
||||
var attribute = new VertexAttribute();
|
||||
attribute.Read(reader);
|
||||
Attributes.Add(attribute);
|
||||
|
||||
switch (attribute.Type)
|
||||
{
|
||||
case VertexAttribute.BufferType.Position:
|
||||
if (attribute.Format == VertexAttribute.BufferFormat.HalfFloat)
|
||||
VertBufferStride += 0x08;
|
||||
else if (attribute.Format == VertexAttribute.BufferFormat.Float)
|
||||
VertBufferStride += 0x0C;
|
||||
else
|
||||
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
||||
break;
|
||||
case VertexAttribute.BufferType.Normal:
|
||||
if (attribute.Format == VertexAttribute.BufferFormat.HalfFloat)
|
||||
VertBufferStride += 0x08;
|
||||
else if (attribute.Format == VertexAttribute.BufferFormat.Float)
|
||||
VertBufferStride += 0x0C;
|
||||
else
|
||||
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
||||
break;
|
||||
case VertexAttribute.BufferType.Binormal:
|
||||
if (attribute.Format == VertexAttribute.BufferFormat.HalfFloat)
|
||||
VertBufferStride += 0x08;
|
||||
else if (attribute.Format == VertexAttribute.BufferFormat.Float)
|
||||
VertBufferStride += 0x0C;
|
||||
else
|
||||
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
||||
break;
|
||||
case VertexAttribute.BufferType.TexCoord1:
|
||||
case VertexAttribute.BufferType.TexCoord2:
|
||||
case VertexAttribute.BufferType.TexCoord3:
|
||||
case VertexAttribute.BufferType.TexCoord4:
|
||||
if (attribute.Format == VertexAttribute.BufferFormat.HalfFloat)
|
||||
VertBufferStride += 0x04;
|
||||
else if (attribute.Format == VertexAttribute.BufferFormat.Float)
|
||||
VertBufferStride += 0x08;
|
||||
else
|
||||
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
||||
break;
|
||||
case VertexAttribute.BufferType.Color1:
|
||||
case VertexAttribute.BufferType.Color2:
|
||||
if (attribute.Format == VertexAttribute.BufferFormat.Byte)
|
||||
VertBufferStride += 0x04;
|
||||
else
|
||||
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
||||
break;
|
||||
case VertexAttribute.BufferType.BoneIndex:
|
||||
if (attribute.Format == VertexAttribute.BufferFormat.Short)
|
||||
VertBufferStride += 0x08;
|
||||
else if (attribute.Format == VertexAttribute.BufferFormat.Byte)
|
||||
VertBufferStride += 0x04;
|
||||
else
|
||||
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
||||
break;
|
||||
case VertexAttribute.BufferType.Weights:
|
||||
if (attribute.Format == VertexAttribute.BufferFormat.BytesAsFloat)
|
||||
VertBufferStride += 0x04;
|
||||
else
|
||||
throw new Exception($"Unknown Combination! {attribute.Type} {attribute.Format}");
|
||||
break;
|
||||
}
|
||||
|
||||
Console.WriteLine($"{attribute.Format} {attribute.Type} VertBufferStride {VertBufferStride}");
|
||||
}
|
||||
}
|
||||
|
||||
if (FacesPosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + FacesPosition);
|
||||
var BufferOffset = reader.ReadOffset(true, typeof(uint));
|
||||
|
||||
reader.SeekBegin(BufferOffset);
|
||||
uint GroupCount = reader.ReadUInt32();
|
||||
|
||||
for (int i = 0; i < GroupCount; i++)
|
||||
{
|
||||
var polygonGroup = new PolygonGroup();
|
||||
polygonGroup.Read(reader);
|
||||
PolygonGroups.Add(polygonGroup);
|
||||
}
|
||||
}
|
||||
|
||||
if (VerticesPosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + VerticesPosition);
|
||||
var VertexOffset = reader.ReadOffset(true, typeof(uint));
|
||||
|
||||
reader.SeekBegin(VertexOffset);
|
||||
uint VertexBufferSize = reader.ReadUInt32();
|
||||
|
||||
for (int v = 0; v < VertexBufferSize / VertBufferStride; v++)
|
||||
{
|
||||
for (int att = 0; att < Attributes.Count; att++)
|
||||
{
|
||||
switch (Attributes[att].Type)
|
||||
{
|
||||
case VertexAttribute.BufferType.Position:
|
||||
var pos = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
||||
Positions.Add(new Vector3(pos.X, pos.Y, pos.Z));
|
||||
break;
|
||||
case VertexAttribute.BufferType.Normal:
|
||||
var normal = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
||||
Normals.Add(new Vector3(normal.X, normal.Y, normal.Z));
|
||||
break;
|
||||
case VertexAttribute.BufferType.TexCoord1:
|
||||
var texcoord1 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
||||
TexCoord1.Add(new Vector2(texcoord1.X, texcoord1.Y));
|
||||
break;
|
||||
case VertexAttribute.BufferType.TexCoord2:
|
||||
var texcoord2 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
||||
TexCoord2.Add(new Vector2(texcoord2.X, texcoord2.Y));
|
||||
break;
|
||||
case VertexAttribute.BufferType.TexCoord3:
|
||||
var texcoord3 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
||||
TexCoord3.Add(new Vector2(texcoord3.X, texcoord3.Y));
|
||||
break;
|
||||
case VertexAttribute.BufferType.TexCoord4:
|
||||
var texcoord4 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
||||
TexCoord4.Add(new Vector2(texcoord4.X, texcoord4.Y));
|
||||
break;
|
||||
case VertexAttribute.BufferType.Weights:
|
||||
var weights = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
||||
Weights.Add(new float[] { weights.X, weights.Y, weights.Z, weights.W });
|
||||
break;
|
||||
case VertexAttribute.BufferType.BoneIndex:
|
||||
var boneIndices = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
||||
BoneIndex.Add(new int[] { (int)boneIndices.X, (int)boneIndices.Y, (int)boneIndices.Z, (int)boneIndices.W });
|
||||
break;
|
||||
case VertexAttribute.BufferType.Color1:
|
||||
var colors1 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
||||
Colors1.Add(new Vector4(colors1.X, colors1.Y, colors1.Z, colors1.W));
|
||||
break;
|
||||
case VertexAttribute.BufferType.Color2:
|
||||
var colors2 = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
||||
Colors2.Add(new Vector4(colors2.X, colors2.Y, colors2.Z, colors2.W));
|
||||
break;
|
||||
case VertexAttribute.BufferType.Binormal:
|
||||
var binormals = ParseBuffer(reader, Attributes[att].Format, Attributes[att].Type);
|
||||
Binormals.Add(new Vector4(binormals.X, binormals.Y, binormals.Z, binormals.W));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Seek back to next in array
|
||||
reader.SeekBegin(DataPosition + sizeof(uint));
|
||||
}
|
||||
|
||||
private Vector4 ParseBuffer(FileReader reader, VertexAttribute.BufferFormat Format, VertexAttribute.BufferType AttributeType)
|
||||
{
|
||||
if (AttributeType == VertexAttribute.BufferType.Position)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case VertexAttribute.BufferFormat.Float:
|
||||
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), 0);
|
||||
case VertexAttribute.BufferFormat.HalfFloat:
|
||||
return new Vector4(reader.ReadHalfSingle(), reader.ReadHalfSingle(),
|
||||
reader.ReadHalfSingle(), reader.ReadHalfSingle());
|
||||
default:
|
||||
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
||||
}
|
||||
}
|
||||
else if (AttributeType == VertexAttribute.BufferType.Normal)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case VertexAttribute.BufferFormat.Float:
|
||||
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), 0);
|
||||
case VertexAttribute.BufferFormat.HalfFloat:
|
||||
return new Vector4(reader.ReadHalfSingle(), reader.ReadHalfSingle(),
|
||||
reader.ReadHalfSingle(), reader.ReadHalfSingle());
|
||||
default:
|
||||
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
||||
}
|
||||
}
|
||||
else if (AttributeType == VertexAttribute.BufferType.Binormal)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case VertexAttribute.BufferFormat.Float:
|
||||
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), 0);
|
||||
case VertexAttribute.BufferFormat.HalfFloat:
|
||||
return new Vector4(reader.ReadHalfSingle(), reader.ReadHalfSingle(),
|
||||
reader.ReadHalfSingle(), reader.ReadHalfSingle());
|
||||
default:
|
||||
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
||||
}
|
||||
}
|
||||
else if (AttributeType == VertexAttribute.BufferType.TexCoord1 ||
|
||||
AttributeType == VertexAttribute.BufferType.TexCoord2 ||
|
||||
AttributeType == VertexAttribute.BufferType.TexCoord3 ||
|
||||
AttributeType == VertexAttribute.BufferType.TexCoord4)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case VertexAttribute.BufferFormat.Float:
|
||||
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), 0, 0);
|
||||
case VertexAttribute.BufferFormat.HalfFloat:
|
||||
return new Vector4(reader.ReadHalfSingle(), reader.ReadHalfSingle(), 0, 0);
|
||||
default:
|
||||
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
||||
}
|
||||
}
|
||||
else if (AttributeType == VertexAttribute.BufferType.Color1 ||
|
||||
AttributeType == VertexAttribute.BufferType.Color2)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case VertexAttribute.BufferFormat.Byte:
|
||||
return new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
|
||||
default:
|
||||
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
||||
}
|
||||
}
|
||||
else if (AttributeType == VertexAttribute.BufferType.BoneIndex)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case VertexAttribute.BufferFormat.Short:
|
||||
return new Vector4(reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16());
|
||||
case VertexAttribute.BufferFormat.Byte:
|
||||
return new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
|
||||
default:
|
||||
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
||||
}
|
||||
}
|
||||
else if (AttributeType == VertexAttribute.BufferType.Weights)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case VertexAttribute.BufferFormat.BytesAsFloat:
|
||||
return new Vector4(reader.ReadByteAsFloat(), reader.ReadByteAsFloat(),
|
||||
reader.ReadByteAsFloat(), reader.ReadByteAsFloat());
|
||||
default:
|
||||
throw new Exception($"Unknown Combination! {AttributeType} {Format}");
|
||||
}
|
||||
}
|
||||
|
||||
return new Vector4(0);
|
||||
}
|
||||
}
|
||||
|
||||
//Represents an offset which points to another
|
||||
public class OffsetInfo
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class PolygonGroup
|
||||
{
|
||||
public int MaterialID { get; set; }
|
||||
public int[] Faces { get; set; }
|
||||
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
long DataPosition = reader.Position;
|
||||
var DataOffset = reader.ReadOffset(true, typeof(uint));
|
||||
|
||||
reader.SeekBegin(DataOffset);
|
||||
long InfoPosition = reader.Position;
|
||||
|
||||
int InfoOffset = reader.ReadInt32();
|
||||
|
||||
//Read the info section for position data
|
||||
reader.SeekBegin(InfoPosition - InfoOffset);
|
||||
ushort PolygonHeaderSize = reader.ReadUInt16();
|
||||
ushort PolygonStartPosition = 0;
|
||||
ushort PolgonMaterialId = 0;
|
||||
ushort PolygonUnknown = 0;
|
||||
|
||||
if (PolygonHeaderSize == 0x08)
|
||||
{
|
||||
PolygonStartPosition = reader.ReadUInt16();
|
||||
PolgonMaterialId = reader.ReadUInt16();
|
||||
PolygonUnknown = reader.ReadUInt16();
|
||||
}
|
||||
else
|
||||
throw new Exception("Unexpected Polygon Buffer Info Header Size! " + PolygonHeaderSize);
|
||||
|
||||
if (PolgonMaterialId != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + PolgonMaterialId);
|
||||
MaterialID = reader.ReadInt32();
|
||||
}
|
||||
|
||||
if (PolygonStartPosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + PolygonStartPosition);
|
||||
uint FaceCount = reader.ReadUInt32();
|
||||
Faces = new int[FaceCount];
|
||||
for (int i = 0; i < FaceCount; i++)
|
||||
Faces[i] = reader.ReadUInt16();
|
||||
}
|
||||
|
||||
//Seek back to next in array
|
||||
reader.SeekBegin(DataPosition + sizeof(uint));
|
||||
}
|
||||
}
|
||||
|
||||
public class VertexAttribute
|
||||
{
|
||||
public BufferFormat Format { get; set; } = BufferFormat.Float;
|
||||
public BufferType Type { get; set; } = BufferType.Position;
|
||||
|
||||
public enum BufferType
|
||||
{
|
||||
Position = 0,
|
||||
Normal = 1,
|
||||
Binormal = 2,
|
||||
TexCoord1 = 3,
|
||||
TexCoord2 = 4,
|
||||
TexCoord3 = 5,
|
||||
TexCoord4 = 6,
|
||||
Color1 = 7,
|
||||
Color2 = 8,
|
||||
BoneIndex = 11,
|
||||
Weights = 12,
|
||||
}
|
||||
|
||||
public enum BufferFormat
|
||||
{
|
||||
Float = 0,
|
||||
HalfFloat = 1,
|
||||
Byte = 3,
|
||||
Short = 5,
|
||||
BytesAsFloat = 8,
|
||||
}
|
||||
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
long DataPosition = reader.Position;
|
||||
var DataOffset = reader.ReadOffset(true, typeof(uint));
|
||||
|
||||
reader.SeekBegin(DataOffset);
|
||||
long InfoPosition = reader.Position;
|
||||
int InfoOffset = reader.ReadInt32();
|
||||
|
||||
//Read the info section for position data
|
||||
reader.SeekBegin(InfoPosition - InfoOffset);
|
||||
ushort LayoutHeaderLength = reader.ReadUInt16();
|
||||
ushort LayoutSizePosition = 0;
|
||||
ushort LayoutTypePosition = 0;
|
||||
ushort LayoutFormatPosition = 0;
|
||||
ushort LayoutUnknownPosition = 0;
|
||||
|
||||
if (LayoutHeaderLength == 0x0A)
|
||||
{
|
||||
LayoutSizePosition = reader.ReadUInt16();
|
||||
LayoutTypePosition = reader.ReadUInt16();
|
||||
LayoutFormatPosition = reader.ReadUInt16();
|
||||
LayoutUnknownPosition = reader.ReadUInt16();
|
||||
}
|
||||
else
|
||||
throw new Exception("Unexpected Attribute Layout Header Size! " + LayoutHeaderLength);
|
||||
|
||||
if (LayoutFormatPosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + LayoutFormatPosition);
|
||||
Format = reader.ReadEnum<BufferFormat>(true);
|
||||
}
|
||||
|
||||
if (LayoutTypePosition != 0)
|
||||
{
|
||||
reader.SeekBegin(InfoPosition + LayoutTypePosition);
|
||||
Type = reader.ReadEnum<BufferType>(true);
|
||||
}
|
||||
|
||||
//Seek back to next in array
|
||||
reader.SeekBegin(DataPosition + sizeof(uint));
|
||||
}
|
||||
}
|
||||
|
||||
public class Bone : STBone
|
||||
{
|
||||
internal BoneInfo BoneInfo { get; set; }
|
||||
|
@ -216,8 +984,6 @@ namespace FirstPlugin
|
|||
float RotationY = reader.ReadSingle();
|
||||
float RotationZ = reader.ReadSingle();
|
||||
rotation = new float[] { RotationX,RotationY, RotationZ };
|
||||
|
||||
Console.WriteLine($"RotationX {RotationX} RotationY {RotationY} RotationX {RotationX} ");
|
||||
}
|
||||
|
||||
if (BoneInfo.TranslationPosition != 0)
|
||||
|
@ -227,8 +993,6 @@ namespace FirstPlugin
|
|||
float TranslateY = reader.ReadSingle();
|
||||
float TranslateZ = reader.ReadSingle();
|
||||
position = new float[] { TranslateX, TranslateY, TranslateZ };
|
||||
|
||||
Console.WriteLine($"TranslateX {TranslateX} TranslateY {TranslateY} TranslateZ {TranslateZ} ");
|
||||
}
|
||||
|
||||
if (BoneInfo.ScalePosition != 0)
|
||||
|
@ -238,8 +1002,6 @@ namespace FirstPlugin
|
|||
float ScaleY = reader.ReadSingle();
|
||||
float ScaleZ = reader.ReadSingle();
|
||||
scale = new float[] { ScaleX, ScaleY, ScaleZ };
|
||||
|
||||
Console.WriteLine($"ScaleX {ScaleX} ScaleY {ScaleX} ScaleZ {ScaleX} ");
|
||||
}
|
||||
|
||||
if (BoneInfo.ParentPosition != 0)
|
||||
|
@ -248,8 +1010,6 @@ namespace FirstPlugin
|
|||
parentIndex = reader.ReadInt32();
|
||||
}
|
||||
|
||||
Console.WriteLine($"parentIndex {parentIndex} {Text}");
|
||||
|
||||
//Seek back to next bone in array
|
||||
reader.SeekBegin(DataPosition + sizeof(uint));
|
||||
}
|
||||
|
@ -285,19 +1045,6 @@ namespace FirstPlugin
|
|||
TranslationPosition = reader.ReadUInt16();
|
||||
Unknown4Position = reader.ReadUInt16(); //Padding
|
||||
Unknown5Position = reader.ReadUInt16(); //Padding
|
||||
|
||||
/* Console.WriteLine($"SectionSize {SectionSize}");
|
||||
Console.WriteLine($"NamePosition {NamePosition}");
|
||||
Console.WriteLine($"UnknownPosition {UnknownPosition}");
|
||||
Console.WriteLine($"Unknown2Position {Unknown2Position}");
|
||||
Console.WriteLine($"ParentPosition {ParentPosition}");
|
||||
Console.WriteLine($"Unknown3Position {Unknown3Position}");
|
||||
Console.WriteLine($"IsVisiblePosition {IsVisiblePosition}");
|
||||
Console.WriteLine($"ScalePosition {ScalePosition}");
|
||||
Console.WriteLine($"RotationPosition {RotationPosition}");
|
||||
Console.WriteLine($"TranslationPosition {TranslationPosition}");
|
||||
Console.WriteLine($"Unknown4Position {Unknown4Position}");
|
||||
Console.WriteLine($"Unknown5Position {Unknown5Position}");*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
109
Switch_FileFormatsMain/FileFormats/GFBMDL/GFBMDL_Wrappers.cs
Normal file
109
Switch_FileFormatsMain/FileFormats/GFBMDL/GFBMDL_Wrappers.cs
Normal file
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Switch_Toolbox.Library;
|
||||
using Switch_Toolbox.Library.Rendering;
|
||||
using OpenTK;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
public class GFBMaterial : STGenericMaterial
|
||||
{
|
||||
public GFBMDL ParentModel { get; set; }
|
||||
|
||||
public GFBMaterial(GFBMDL model) {
|
||||
ParentModel = model;
|
||||
}
|
||||
}
|
||||
|
||||
public class GFBMesh : STGenericObject
|
||||
{
|
||||
public int[] display;
|
||||
public int DisplayId;
|
||||
|
||||
public GFBMDL ParentModel { get; set; }
|
||||
|
||||
public GFBMaterial GetMaterial(STGenericPolygonGroup polygroup)
|
||||
{
|
||||
return ParentModel.header.GenericMaterials[polygroup.MaterialIndex];
|
||||
}
|
||||
|
||||
public struct DisplayVertex
|
||||
{
|
||||
// Used for rendering.
|
||||
public Vector3 pos;
|
||||
public Vector3 nrm;
|
||||
public Vector3 tan;
|
||||
public Vector2 uv;
|
||||
public Vector4 col;
|
||||
public Vector4 node;
|
||||
public Vector4 weight;
|
||||
public Vector2 uv2;
|
||||
public Vector2 uv3;
|
||||
public Vector3 binorm;
|
||||
|
||||
public static int Size = 4 * (3 + 3 + 3 + 2 + 4 + 4 + 4 + 2 + 2 + 3);
|
||||
}
|
||||
|
||||
public GFBMesh(GFBMDL model) {
|
||||
ParentModel = model;
|
||||
}
|
||||
|
||||
public List<DisplayVertex> CreateDisplayVertices()
|
||||
{
|
||||
List<int> Faces = new List<int>();
|
||||
foreach (var group in PolygonGroups)
|
||||
Faces.AddRange(group.GetDisplayFace());
|
||||
|
||||
display = Faces.ToArray();
|
||||
|
||||
List<DisplayVertex> displayVertList = new List<DisplayVertex>();
|
||||
|
||||
if (display.Length <= 3)
|
||||
return displayVertList;
|
||||
|
||||
foreach (Vertex v in vertices)
|
||||
{
|
||||
DisplayVertex displayVert = new DisplayVertex()
|
||||
{
|
||||
pos = v.pos,
|
||||
nrm = v.nrm,
|
||||
tan = v.tan.Xyz,
|
||||
binorm = v.bitan.Xyz,
|
||||
col = v.col,
|
||||
uv = v.uv0,
|
||||
uv2 = v.uv1,
|
||||
uv3 = v.uv2,
|
||||
node = new Vector4(
|
||||
v.boneIds.Count > 0 ? v.boneIds[0] : -1,
|
||||
v.boneIds.Count > 1 ? v.boneIds[1] : -1,
|
||||
v.boneIds.Count > 2 ? v.boneIds[2] : -1,
|
||||
v.boneIds.Count > 3 ? v.boneIds[3] : -1),
|
||||
weight = new Vector4(
|
||||
v.boneWeights.Count > 0 ? v.boneWeights[0] : 0,
|
||||
v.boneWeights.Count > 1 ? v.boneWeights[1] : 0,
|
||||
v.boneWeights.Count > 2 ? v.boneWeights[2] : 0,
|
||||
v.boneWeights.Count > 3 ? v.boneWeights[3] : 0),
|
||||
};
|
||||
|
||||
displayVertList.Add(displayVert);
|
||||
|
||||
/* Console.WriteLine($"---------------------------------------------------------------------------------------");
|
||||
Console.WriteLine($"Position {displayVert.pos.X} {displayVert.pos.Y} {displayVert.pos.Z}");
|
||||
Console.WriteLine($"Normal {displayVert.nrm.X} {displayVert.nrm.Y} {displayVert.nrm.Z}");
|
||||
Console.WriteLine($"Tanget {displayVert.tan.X} {displayVert.tan.Y} {displayVert.tan.Z}");
|
||||
Console.WriteLine($"Color {displayVert.col.X} {displayVert.col.Y} {displayVert.col.Z} {displayVert.col.W}");
|
||||
Console.WriteLine($"UV Layer 1 {displayVert.uv.X} {displayVert.uv.Y}");
|
||||
Console.WriteLine($"UV Layer 2 {displayVert.uv2.X} {displayVert.uv2.Y}");
|
||||
Console.WriteLine($"UV Layer 3 {displayVert.uv3.X} {displayVert.uv3.Y}");
|
||||
Console.WriteLine($"Bone Index {displayVert.node.X} {displayVert.node.Y} {displayVert.node.Z} {displayVert.node.W}");
|
||||
Console.WriteLine($"Weights {displayVert.weight.X} {displayVert.weight.Y} {displayVert.weight.Z} {displayVert.weight.W}");
|
||||
Console.WriteLine($"---------------------------------------------------------------------------------------");*/
|
||||
}
|
||||
|
||||
return displayVertList;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,14 +24,10 @@ namespace FirstPlugin
|
|||
int vbo_position;
|
||||
int ibo_elements;
|
||||
|
||||
//Uniform block buffers
|
||||
int TexCoord1Buffer;
|
||||
|
||||
private void GenerateBuffers()
|
||||
{
|
||||
GL.GenBuffers(1, out vbo_position);
|
||||
GL.GenBuffers(1, out ibo_elements);
|
||||
GL.GenBuffers(1, out TexCoord1Buffer);
|
||||
|
||||
UpdateVertexData();
|
||||
UpdateTextureMaps();
|
||||
|
|
414
Switch_FileFormatsMain/GL/GFBMDL_Render.cs
Normal file
414
Switch_FileFormatsMain/GL/GFBMDL_Render.cs
Normal file
|
@ -0,0 +1,414 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GL_EditorFramework.GL_Core;
|
||||
using GL_EditorFramework.Interfaces;
|
||||
using Switch_Toolbox.Library.IO;
|
||||
using Switch_Toolbox.Library;
|
||||
using Switch_Toolbox.Library.Rendering;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
public class GFBMDL_Render : AbstractGlDrawable
|
||||
{
|
||||
public List<GFBMesh> Meshes = new List<GFBMesh>();
|
||||
|
||||
public Matrix4 ModelTransform = Matrix4.Identity;
|
||||
|
||||
// gl buffer objects
|
||||
int vbo_position;
|
||||
int ibo_elements;
|
||||
|
||||
private void GenerateBuffers()
|
||||
{
|
||||
GL.GenBuffers(1, out vbo_position);
|
||||
GL.GenBuffers(1, out ibo_elements);
|
||||
|
||||
UpdateVertexData();
|
||||
UpdateTextureMaps();
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
GL.DeleteBuffer(vbo_position);
|
||||
GL.DeleteBuffer(ibo_elements);
|
||||
}
|
||||
|
||||
public void UpdateVertexData()
|
||||
{
|
||||
if (!Runtime.OpenTKInitialized)
|
||||
return;
|
||||
|
||||
GFBMesh.DisplayVertex[] Vertices;
|
||||
int[] Faces;
|
||||
|
||||
int poffset = 0;
|
||||
int voffset = 0;
|
||||
List<GFBMesh.DisplayVertex> Vs = new List<GFBMesh.DisplayVertex>();
|
||||
List<int> Ds = new List<int>();
|
||||
|
||||
foreach (GFBMesh shape in Meshes)
|
||||
{
|
||||
List<GFBMesh.DisplayVertex> pv = shape.CreateDisplayVertices();
|
||||
Vs.AddRange(pv);
|
||||
|
||||
int GroupOffset = 0;
|
||||
int groupIndex = 0;
|
||||
foreach (var group in shape.PolygonGroups)
|
||||
{
|
||||
group.Offset = poffset * 4;
|
||||
|
||||
for (int i = 0; i < group.displayFaceSize; i++)
|
||||
{
|
||||
Ds.Add(shape.display[GroupOffset + i] + voffset);
|
||||
}
|
||||
|
||||
poffset += group.displayFaceSize;
|
||||
GroupOffset += group.displayFaceSize;
|
||||
|
||||
Console.WriteLine($"GroupOffset {groupIndex++} " + GroupOffset);
|
||||
}
|
||||
|
||||
voffset += pv.Count;
|
||||
}
|
||||
|
||||
// Binds
|
||||
Vertices = Vs.ToArray();
|
||||
Faces = Ds.ToArray();
|
||||
|
||||
// Bind only once!
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
|
||||
GL.BufferData<GFBMesh.DisplayVertex>(BufferTarget.ArrayBuffer, (IntPtr)(Vertices.Length * GFBMesh.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();
|
||||
}
|
||||
|
||||
public void UpdateTextureMaps()
|
||||
{
|
||||
if (!Runtime.OpenTKInitialized)
|
||||
return;
|
||||
|
||||
LibraryGUI.Instance.UpdateViewport();
|
||||
}
|
||||
|
||||
public ShaderProgram defaultShaderProgram;
|
||||
|
||||
public override void Prepare(GL_ControlModern control)
|
||||
{
|
||||
string pathFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "GFBModel.frag");
|
||||
string pathVert = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "GFBModel.vert");
|
||||
string pathUtiltyFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Utility") + "\\Utility.frag";
|
||||
string pathPbrUtiltyFrag = System.IO.Path.Combine(Runtime.ExecutableDir, "Shader", "Utility") + "\\PbrUtility.frag";
|
||||
|
||||
|
||||
var defaultFrag = new FragmentShader(File.ReadAllText(pathFrag));
|
||||
var defaultVert = new VertexShader(File.ReadAllText(pathVert));
|
||||
var utiltyFrag = new FragmentShader(System.IO.File.ReadAllText(pathUtiltyFrag));
|
||||
var pbrUtiltyFrag = new FragmentShader(System.IO.File.ReadAllText(pathPbrUtiltyFrag));
|
||||
|
||||
defaultShaderProgram = new ShaderProgram(new Shader[]
|
||||
{ utiltyFrag, pbrUtiltyFrag, defaultVert, defaultFrag }, control);
|
||||
}
|
||||
|
||||
public override void Prepare(GL_ControlLegacy control)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Draw(GL_ControlLegacy control, Pass pass)
|
||||
{
|
||||
if (!Runtime.OpenTKInitialized)
|
||||
return;
|
||||
}
|
||||
|
||||
public override void Draw(GL_ControlModern control, Pass pass)
|
||||
{
|
||||
if (!Runtime.OpenTKInitialized || pass == Pass.TRANSPARENT)
|
||||
return;
|
||||
|
||||
bool buffersWereInitialized = ibo_elements != 0 && vbo_position != 0;
|
||||
if (!buffersWereInitialized)
|
||||
GenerateBuffers();
|
||||
|
||||
ShaderProgram shader = defaultShaderProgram;
|
||||
control.CurrentShader = shader;
|
||||
control.UpdateModelMatrix(Matrix4.CreateScale(Runtime.previewScale) * ModelTransform);
|
||||
|
||||
Matrix4 camMat = control.ModelMatrix * control.CameraMatrix * control.ProjectionMatrix;
|
||||
|
||||
Matrix4 invertedCamera = Matrix4.Identity;
|
||||
if (invertedCamera.Determinant != 0)
|
||||
invertedCamera = camMat.Inverted();
|
||||
|
||||
Vector3 lightDirection = new Vector3(0f, 0f, -1f);
|
||||
|
||||
shader.SetVector3("difLightDirection", Vector3.TransformNormal(lightDirection, invertedCamera).Normalized());
|
||||
|
||||
// GL.Enable(EnableCap.AlphaTest);
|
||||
// GL.AlphaFunc(AlphaFunction.Gequal, 0.1f);
|
||||
|
||||
SetRenderSettings(shader);
|
||||
|
||||
DrawModels(shader, control);
|
||||
|
||||
|
||||
GL.UseProgram(0);
|
||||
GL.Disable(EnableCap.DepthTest);
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
GL.Enable(EnableCap.CullFace);
|
||||
}
|
||||
|
||||
private static void SetBoneUniforms(GLControl control, ShaderProgram shader, GFBMesh mesh)
|
||||
{
|
||||
int i = 0;
|
||||
foreach (var bone in mesh.ParentModel.header.Skeleton.bones)
|
||||
{
|
||||
Matrix4 transform = bone.invert * bone.Transform;
|
||||
|
||||
GL.UniformMatrix4(GL.GetUniformLocation(shader.programs[control], String.Format("bones[{0}]", i++)), false, ref transform);
|
||||
}
|
||||
|
||||
/* foreach (var FaceGroup in fshp.Shape.FaceGroups)
|
||||
{
|
||||
if (FaceGroup.BoneIndexList == null)
|
||||
continue;
|
||||
|
||||
for (int i = 0; i < FaceGroup.BoneIndexList.Length; i++)
|
||||
{
|
||||
GL.Uniform1(GL.GetUniformLocation(shader.programs[control], String.Format("boneIds[{0}]", i)), FaceGroup.BoneIndexList[i]);
|
||||
|
||||
Matrix4 transform = fmdl.Skeleton.Renderable.bones[(int)FaceGroup.BoneIndexList[i]].invert * fmdl.Skeleton.Renderable.bones[(int)FaceGroup.BoneIndexList[i]].Transform;
|
||||
GL.UniformMatrix4(GL.GetUniformLocation(shader.programs[control], String.Format("bones[{0}]", i)), false, ref transform);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private void SetUniformBlocks(GFBMaterial mat, ShaderProgram shader, GFBMesh m, int id)
|
||||
{
|
||||
/* shader.UniformBlockBinding("TexCoord1", 3);
|
||||
GL.GetActiveUniformBlock(shader.program,
|
||||
shader.GetUniformBlockIndex("TexCoord1"),
|
||||
ActiveUniformBlockParameter.UniformBlockBinding, out int binding);*/
|
||||
|
||||
/* GL.BindBuffer(BufferTarget.UniformBuffer, TexCoord1Buffer);
|
||||
GL.BufferData(BufferTarget.UniformBuffer,
|
||||
(IntPtr)MTOBWrapper.TexCoord1.Size,
|
||||
ref mat.TexCoord1Buffer,
|
||||
BufferUsageHint.StaticDraw);
|
||||
GL.BindBuffer(BufferTarget.UniformBuffer, 0);
|
||||
GL.BindBufferRange(BufferRangeTarget.UniformBuffer, 0, TexCoord1Buffer, (IntPtr)0,
|
||||
MTOBWrapper.TexCoord1.Size);
|
||||
GL.BindBuffer(BufferTarget.UniformBuffer, TexCoord1Buffer);
|
||||
GL.BINDBUFFER*/
|
||||
}
|
||||
|
||||
private static void SetUniforms(GFBMaterial mat, ShaderProgram shader, GFBMesh m, int id)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private static void SetTextureUniforms(GFBMaterial mat, GFBMesh m, ShaderProgram shader)
|
||||
{
|
||||
SetDefaultTextureAttributes(mat, shader);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + 1);
|
||||
GL.BindTexture(TextureTarget.Texture2D, RenderTools.defaultTex.RenderableTex.TexID);
|
||||
|
||||
GL.Uniform1(shader["debugOption"], 2);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture11);
|
||||
GL.Uniform1(shader["weightRamp1"], 11);
|
||||
GL.BindTexture(TextureTarget.Texture2D, RenderTools.BoneWeightGradient.Id);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture12);
|
||||
GL.Uniform1(shader["weightRamp2"], 12);
|
||||
GL.BindTexture(TextureTarget.Texture2D, RenderTools.BoneWeightGradient2.Id);
|
||||
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture10);
|
||||
GL.Uniform1(shader["UVTestPattern"], 10);
|
||||
GL.BindTexture(TextureTarget.Texture2D, RenderTools.uvTestPattern.RenderableTex.TexID);
|
||||
|
||||
shader.SetInt("RedChannel", 0);
|
||||
shader.SetInt("GreenChannel", 1);
|
||||
shader.SetInt("BlueChannel", 2);
|
||||
shader.SetInt("AlphaChannel", 3);
|
||||
|
||||
LoadPBRMaps(shader);
|
||||
|
||||
foreach (STGenericMatTexture matex in mat.TextureMaps)
|
||||
{
|
||||
if (matex.Type == STGenericMatTexture.TextureType.Diffuse)
|
||||
{
|
||||
shader.SetBoolToInt("HasDiffuse", true);
|
||||
TextureUniform(shader, mat, true, "DiffuseMap", matex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadPBRMaps(ShaderProgram shader)
|
||||
{
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + 26);
|
||||
RenderTools.specularPbr.Bind();
|
||||
shader.SetInt("specularIbl", 26);
|
||||
// GL.GenerateMipmap(GenerateMipmapTarget.TextureCubeMap);
|
||||
|
||||
// PBR IBL
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + 25);
|
||||
RenderTools.diffusePbr.Bind();
|
||||
shader.SetInt("irradianceMap", 25);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + 27);
|
||||
RenderTools.brdfPbr.Bind();
|
||||
shader.SetInt("brdfLUT", 27);
|
||||
}
|
||||
|
||||
private static void TextureUniform(ShaderProgram shader, GFBMaterial mat, bool hasTex, string name, STGenericMatTexture 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[name], BindTexture(mattex, shader));
|
||||
}
|
||||
}
|
||||
|
||||
public static int BindTexture(STGenericMatTexture tex, ShaderProgram shader)
|
||||
{
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + tex.textureUnit + 1);
|
||||
GL.BindTexture(TextureTarget.Texture2D, RenderTools.defaultTex.RenderableTex.TexID);
|
||||
|
||||
string activeTex = tex.Name;
|
||||
|
||||
foreach (var bntx in PluginRuntime.bntxContainers)
|
||||
{
|
||||
if (bntx.Textures.ContainsKey(activeTex))
|
||||
{
|
||||
BindBNTX(bntx, tex, shader, activeTex);
|
||||
return tex.textureUnit + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return tex.textureUnit + 1;
|
||||
}
|
||||
|
||||
private static void BindBNTX(BNTX bntx, STGenericMatTexture tex, ShaderProgram shader, string activeTex)
|
||||
{
|
||||
if (bntx.Textures[activeTex].RenderableTex == null ||
|
||||
!bntx.Textures[activeTex].RenderableTex.GLInitialized)
|
||||
{
|
||||
bntx.Textures[activeTex].LoadOpenGLTexture();
|
||||
}
|
||||
|
||||
BindGLTexture(tex, shader, bntx.Textures[activeTex]);
|
||||
}
|
||||
|
||||
private static void BindGLTexture(STGenericMatTexture tex, ShaderProgram shader, STGenericTexture texture)
|
||||
{
|
||||
if (tex.Type == STGenericMatTexture.TextureType.Diffuse)
|
||||
{
|
||||
shader.SetInt("RedChannel", (int)texture.RedChannel);
|
||||
shader.SetInt("GreenChannel", (int)texture.GreenChannel);
|
||||
shader.SetInt("BlueChannel", (int)texture.BlueChannel);
|
||||
shader.SetInt("AlphaChannel", (int)texture.AlphaChannel);
|
||||
}
|
||||
|
||||
// GL.ActiveTexture(TextureUnit.Texture0 + texid);
|
||||
GL.BindTexture(TextureTarget.Texture2D, texture.RenderableTex.TexID);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)STGenericMatTexture.wrapmode[tex.wrapModeS]);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)STGenericMatTexture.wrapmode[tex.wrapModeT]);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)STGenericMatTexture.minfilter[tex.minFilter]);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)STGenericMatTexture.magfilter[tex.magFilter]);
|
||||
GL.TexParameter(TextureTarget.Texture2D, (TextureParameterName)ExtTextureFilterAnisotropic.TextureMaxAnisotropyExt, 0.0f);
|
||||
}
|
||||
|
||||
private static void SetDefaultTextureAttributes(GFBMaterial mat, ShaderProgram shader)
|
||||
{
|
||||
}
|
||||
|
||||
private void SetRenderSettings(ShaderProgram shader)
|
||||
{
|
||||
shader.SetInt("renderType", (int)Runtime.viewportShading);
|
||||
shader.SetInt("selectedBoneIndex", Runtime.SelectedBoneIndex);
|
||||
shader.SetBoolToInt("renderVertColor", Runtime.renderVertColor);
|
||||
}
|
||||
|
||||
private void DrawModels(ShaderProgram shader, GL_ControlModern control)
|
||||
{
|
||||
shader.EnableVertexAttributes();
|
||||
foreach (GFBMesh shp in Meshes)
|
||||
{
|
||||
if (shp.Checked)
|
||||
DrawModel(control, shp, shader);
|
||||
}
|
||||
shader.DisableVertexAttributes();
|
||||
}
|
||||
|
||||
private void SetVertexAttributes(GFBMesh m, ShaderProgram shader)
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
|
||||
GL.VertexAttribPointer(shader.GetAttribute("vPosition"), 3, VertexAttribPointerType.Float, false, GFBMesh.DisplayVertex.Size, 0); //+12
|
||||
GL.VertexAttribPointer(shader.GetAttribute("vNormal"), 3, VertexAttribPointerType.Float, false, GFBMesh.DisplayVertex.Size, 12); //+12
|
||||
GL.VertexAttribPointer(shader.GetAttribute("vTangent"), 3, VertexAttribPointerType.Float, false, GFBMesh.DisplayVertex.Size, 24); //+12
|
||||
GL.VertexAttribPointer(shader.GetAttribute("vUV0"), 2, VertexAttribPointerType.Float, false, GFBMesh.DisplayVertex.Size, 36); //+8
|
||||
GL.VertexAttribPointer(shader.GetAttribute("vColor"), 4, VertexAttribPointerType.Float, false, GFBMesh.DisplayVertex.Size, 44); //+16
|
||||
GL.VertexAttribIPointer(shader.GetAttribute("vBone"), 4, VertexAttribIntegerType.Int, GFBMesh.DisplayVertex.Size, new IntPtr(60)); //+16
|
||||
GL.VertexAttribPointer(shader.GetAttribute("vWeight"), 4, VertexAttribPointerType.Float, false, GFBMesh.DisplayVertex.Size, 76);//+16
|
||||
GL.VertexAttribPointer(shader.GetAttribute("vUV1"), 2, VertexAttribPointerType.Float, false, GFBMesh.DisplayVertex.Size, 92);//+8
|
||||
GL.VertexAttribPointer(shader.GetAttribute("vUV2"), 2, VertexAttribPointerType.Float, false, GFBMesh.DisplayVertex.Size, 100);//+8
|
||||
GL.VertexAttribPointer(shader.GetAttribute("vBinormal"), 3, VertexAttribPointerType.Float, false, GFBMesh.DisplayVertex.Size, 108); //+12
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
|
||||
}
|
||||
|
||||
private void DrawModel(GLControl control, GFBMesh m, ShaderProgram shader)
|
||||
{
|
||||
foreach (var group in m.PolygonGroups)
|
||||
{
|
||||
if (group.faces.Count <= 3)
|
||||
return;
|
||||
|
||||
var Material = m.ParentModel.header.Materials[group.MaterialIndex];
|
||||
|
||||
SetUniforms(m.GetMaterial(group), shader, m, m.DisplayId);
|
||||
SetUniformBlocks(m.GetMaterial(group), shader, m, m.DisplayId);
|
||||
SetBoneUniforms(control, shader, m);
|
||||
SetVertexAttributes(m, shader);
|
||||
SetTextureUniforms(m.GetMaterial(group), m, shader);
|
||||
|
||||
if (m.IsSelected)
|
||||
{
|
||||
DrawModelSelection(group, shader);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Runtime.RenderModels)
|
||||
{
|
||||
GL.DrawElements(PrimitiveType.Triangles, group.displayFaceSize, DrawElementsType.UnsignedInt, group.Offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawModelSelection(STGenericPolygonGroup p, ShaderProgram shader)
|
||||
{
|
||||
GL.Uniform1(shader["colorOverride"], 1);
|
||||
GL.PolygonMode(MaterialFace.Front, PolygonMode.Line);
|
||||
GL.Enable(EnableCap.LineSmooth);
|
||||
GL.LineWidth(1.3f);
|
||||
GL.DrawElements(PrimitiveType.Triangles, p.displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
|
||||
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
|
||||
GL.Uniform1(shader["colorOverride"], 0);
|
||||
|
||||
GL.DrawElements(PrimitiveType.Triangles, p.displayFaceSize, DrawElementsType.UnsignedInt, p.Offset);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -240,6 +240,7 @@
|
|||
<Compile Include="FileFormats\Font\BFFNT.cs" />
|
||||
<Compile Include="FileFormats\Audio\Archives\BFGRP.cs" />
|
||||
<Compile Include="FileFormats\GFBMDL\GFBMDL.cs" />
|
||||
<Compile Include="FileFormats\GFBMDL\GFBMDL_Wrappers.cs" />
|
||||
<Compile Include="FileFormats\Hashes\SAHT.cs" />
|
||||
<Compile Include="FileFormats\MKAGPDX\MKAGPDX_Model.cs" />
|
||||
<Compile Include="FileFormats\Rom\RomfsNodeWrapper.cs" />
|
||||
|
@ -257,6 +258,7 @@
|
|||
<Compile Include="FileFormats\Texture\TEX3DS.cs" />
|
||||
<Compile Include="FileFormats\XLINK\XLINK.cs" />
|
||||
<Compile Include="GL\BCRES_Render.cs" />
|
||||
<Compile Include="GL\GFBMDL_Render.cs" />
|
||||
<Compile Include="GL\Helpers\DepthGLControl.cs" />
|
||||
<Compile Include="GL\ShaderData\AglShaderOdyssey.cs" />
|
||||
<Compile Include="GL\ShaderData\AglShaderTurbo.cs" />
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -177,46 +177,32 @@ namespace Switch_Toolbox.Library
|
|||
var mem = new System.IO.MemoryStream();
|
||||
using (FileWriter writer = new FileWriter(mem))
|
||||
{
|
||||
int sizeX = (int)Width;
|
||||
int sizeY = (int)Height;
|
||||
int sizeZ = (int)Depth;
|
||||
if (Depth == 0)
|
||||
Depth = 1;
|
||||
|
||||
writer.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
|
||||
|
||||
magic = new byte[4];
|
||||
xsize = new byte[3];
|
||||
ysize = new byte[3];
|
||||
zsize = new byte[3];
|
||||
|
||||
magic[0] = MagicFileConstant & 0xFF;
|
||||
magic[1] = (MagicFileConstant >> 8) & 0xFF;
|
||||
magic[2] = (MagicFileConstant >> 16) & 0xFF;
|
||||
magic[3] = (byte)(MagicFileConstant >> 24) & 0xFF;
|
||||
|
||||
writer.Write(magic);
|
||||
writer.Write(MagicFileConstant);
|
||||
writer.Write(BlockDimX);
|
||||
writer.Write(BlockDimY);
|
||||
writer.Write(BlockDimZ);
|
||||
|
||||
xsize[0] = (byte)(sizeX & 0xFF);
|
||||
xsize[1] = (byte)((sizeX >> 8) & 0xFF);
|
||||
xsize[2] = (byte)((sizeX >> 16) & 0xFF);
|
||||
ysize[0] = (byte)(sizeY & 0xFF);
|
||||
ysize[1] = (byte)((sizeY >> 8) & 0xFF);
|
||||
ysize[2] = (byte)((sizeY >> 16) & 0xFF);
|
||||
zsize[0] = (byte)(sizeZ & 0xFF);
|
||||
zsize[1] = (byte)((sizeZ >> 8) & 0xFF);
|
||||
zsize[2] = (byte)((sizeZ >> 16) & 0xFF);
|
||||
|
||||
writer.Write(xsize);
|
||||
writer.Write(ysize);
|
||||
writer.Write(zsize);
|
||||
writer.Write(IntTo3Bytes((int)Width));
|
||||
writer.Write(IntTo3Bytes((int)Height));
|
||||
writer.Write(IntTo3Bytes((int)Depth));
|
||||
writer.Write(DataBlock);
|
||||
}
|
||||
|
||||
return mem.ToArray();
|
||||
}
|
||||
|
||||
private static byte[] IntTo3Bytes(int value)
|
||||
{
|
||||
byte[] newValue = new byte[3];
|
||||
newValue[0] = (byte)(value & 0xFF);
|
||||
newValue[1] = (byte)((value >> 8) & 0xFF);
|
||||
newValue[2] = (byte)((value >> 16) & 0xFF);
|
||||
return newValue;
|
||||
}
|
||||
|
||||
public override void SetImageData(Bitmap bitmap, int ArrayLevel)
|
||||
{
|
||||
throw new NotImplementedException("Cannot set image data! Operation not implemented!");
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace Switch_Toolbox.Library
|
|||
|
||||
}
|
||||
|
||||
public List<STGenericPolygonGroup> PolygonGroups = new List<STGenericPolygonGroup>();
|
||||
|
||||
public bool HasPos;
|
||||
public bool HasNrm;
|
||||
public bool HasUv0;
|
||||
|
@ -75,6 +77,7 @@ namespace Switch_Toolbox.Library
|
|||
|
||||
public List<string> boneList = new List<string>();
|
||||
public List<Vertex> vertices = new List<Vertex>();
|
||||
|
||||
public List<LOD_Mesh> lodMeshes = new List<LOD_Mesh>();
|
||||
public class LOD_Mesh
|
||||
{
|
||||
|
|
75
Switch_Toolbox_Library/Generics/GenericPolygonGroup.cs
Normal file
75
Switch_Toolbox_Library/Generics/GenericPolygonGroup.cs
Normal file
|
@ -0,0 +1,75 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Switch_Toolbox.Library
|
||||
{
|
||||
public class STGenericPolygonGroup
|
||||
{
|
||||
public int Offset { get; set; }
|
||||
public int MaterialIndex { get; set; }
|
||||
public int Index { get; set; }
|
||||
|
||||
public List<int> faces = new List<int>();
|
||||
|
||||
public int strip = 0x40;
|
||||
public int displayFaceSize = 0;
|
||||
|
||||
public List<int> GetDisplayFace()
|
||||
{
|
||||
if ((strip >> 4) == 4)
|
||||
{
|
||||
displayFaceSize = faces.Count;
|
||||
return faces;
|
||||
}
|
||||
else
|
||||
{
|
||||
List<int> f = new List<int>();
|
||||
|
||||
int startDirection = 1;
|
||||
int p = 0;
|
||||
int f1 = faces[p++];
|
||||
int f2 = faces[p++];
|
||||
int faceDirection = startDirection;
|
||||
int f3;
|
||||
do
|
||||
{
|
||||
f3 = faces[p++];
|
||||
if (f3 == 0xFFFF)
|
||||
{
|
||||
f1 = faces[p++];
|
||||
f2 = faces[p++];
|
||||
faceDirection = startDirection;
|
||||
}
|
||||
else
|
||||
{
|
||||
faceDirection *= -1;
|
||||
if ((f1 != f2) && (f2 != f3) && (f3 != f1))
|
||||
{
|
||||
if (faceDirection > 0)
|
||||
{
|
||||
f.Add(f3);
|
||||
f.Add(f2);
|
||||
f.Add(f1);
|
||||
}
|
||||
else
|
||||
{
|
||||
f.Add(f2);
|
||||
f.Add(f3);
|
||||
f.Add(f1);
|
||||
}
|
||||
}
|
||||
f1 = f2;
|
||||
f2 = f3;
|
||||
}
|
||||
} while (p < faces.Count);
|
||||
|
||||
displayFaceSize = f.Count;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -44,7 +44,7 @@ namespace Switch_Toolbox.Library.IO
|
|||
return signature == Identifier;
|
||||
}
|
||||
|
||||
public string ReadNameOffset(bool IsRelative, Type OffsetType, bool UseNameLength = false)
|
||||
public string ReadNameOffset(bool IsRelative, Type OffsetType, bool ReadNameLength = false, bool IsNameLengthShort = false)
|
||||
{
|
||||
long pos = Position;
|
||||
long offset = 0;
|
||||
|
@ -66,8 +66,13 @@ namespace Switch_Toolbox.Library.IO
|
|||
using (TemporarySeek(offset, SeekOrigin.Begin))
|
||||
{
|
||||
uint NameLength = 0;
|
||||
if (UseNameLength)
|
||||
NameLength = ReadUInt32();
|
||||
if (ReadNameLength)
|
||||
{
|
||||
if (IsNameLengthShort)
|
||||
NameLength = ReadUInt16();
|
||||
else
|
||||
NameLength = ReadUInt32();
|
||||
}
|
||||
|
||||
return ReadString(BinaryStringFormat.ZeroTerminated);
|
||||
}
|
||||
|
@ -76,11 +81,11 @@ namespace Switch_Toolbox.Library.IO
|
|||
return "";
|
||||
}
|
||||
|
||||
public List<string> ReadNameOffsets(uint Count, bool IsRelative, Type OffsetType, bool UseNameLength = false)
|
||||
public List<string> ReadNameOffsets(uint Count, bool IsRelative, Type OffsetType, bool ReadNameLength = false)
|
||||
{
|
||||
List<string> Names = new List<string>();
|
||||
for (int i = 0; i < Count; i++)
|
||||
Names.Add(ReadNameOffset(IsRelative, OffsetType, UseNameLength));
|
||||
Names.Add(ReadNameOffset(IsRelative, OffsetType, ReadNameLength));
|
||||
|
||||
return Names;
|
||||
}
|
||||
|
@ -118,6 +123,16 @@ namespace Switch_Toolbox.Library.IO
|
|||
return RealSignature;
|
||||
}
|
||||
|
||||
public float ReadByteAsFloat()
|
||||
{
|
||||
return ReadByte() / 255.0f;
|
||||
}
|
||||
|
||||
public float ReadHalfSingle()
|
||||
{
|
||||
return new Syroot.IOExtension.Half(ReadUInt16());
|
||||
}
|
||||
|
||||
public void SeekBegin(uint Offset) { Seek(Offset, SeekOrigin.Begin); }
|
||||
public void SeekBegin(int Offset) { Seek(Offset, SeekOrigin.Begin); }
|
||||
public void SeekBegin(long Offset) { Seek(Offset, SeekOrigin.Begin); }
|
||||
|
|
271
Switch_Toolbox_Library/IO/SyrootCommon/DWord.cs
Normal file
271
Switch_Toolbox_Library/IO/SyrootCommon/DWord.cs
Normal file
|
@ -0,0 +1,271 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Syroot.IOExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a 4-byte value which can hold differently typed data.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{" + nameof(Int32) + "} / {" + nameof(Single) + "}")]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct DWord : IConvertible
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// The data as an <see cref="Int32"/>.
|
||||
/// </summary>
|
||||
[FieldOffset(0)]
|
||||
public Int32 Int32;
|
||||
|
||||
/// <summary>
|
||||
/// The data as a <see cref="Single"/>.
|
||||
/// </summary>
|
||||
[FieldOffset(0)]
|
||||
public Single Single;
|
||||
|
||||
/// <summary>
|
||||
/// The data as an <see cref="UInt32"/>.
|
||||
/// </summary>
|
||||
[FieldOffset(0)]
|
||||
public UInt32 UInt32;
|
||||
|
||||
// ---- OPERATORS ----------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to a <see cref="DWord"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Int32"/> value to represent in the new <see cref="DWord"/> instance.
|
||||
/// </param>
|
||||
public static implicit operator DWord(int value)
|
||||
{
|
||||
return new DWord() { Int32 = value };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to a <see cref="DWord"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Single"/> value to represent in the new <see cref="DWord"/> instance.
|
||||
/// </param>
|
||||
public static implicit operator DWord(float value)
|
||||
{
|
||||
return new DWord() { Single = value };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to a <see cref="DWord"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="UInt32"/> value to represent in the new <see cref="DWord"/> instance.
|
||||
/// </param>
|
||||
public static implicit operator DWord(uint value)
|
||||
{
|
||||
return new DWord() { UInt32 = value };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to an <see cref="Int32"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="DWord"/> value to represent in the new <see cref="Int32"/> instance.
|
||||
/// </param>
|
||||
public static implicit operator int(DWord value)
|
||||
{
|
||||
return value.Int32;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to a <see cref="Single"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="DWord"/> value to represent in the new <see cref="Single"/> instance.
|
||||
/// </param>
|
||||
public static implicit operator float(DWord value)
|
||||
{
|
||||
return value.Single;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to an <see cref="UInt32"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="DWord"/> value to represent in the new <see cref="UInt32"/> instance.
|
||||
/// </param>
|
||||
public static implicit operator uint(DWord value)
|
||||
{
|
||||
return value.UInt32;
|
||||
}
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="TypeCode"/> for this instance.
|
||||
/// </summary>
|
||||
/// <returns>The enumerated constant that is the <see cref="TypeCode"/> of the class or value type that
|
||||
/// implements this interface.</returns>
|
||||
public TypeCode GetTypeCode()
|
||||
{
|
||||
// These are sadly not flags, so just return the value for Int32 at least.
|
||||
return TypeCode.Int32;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This operation is not supported.
|
||||
/// </summary>
|
||||
public bool ToBoolean(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot convert {nameof(DWord)} to type {typeof(bool)}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This operation is not supported.
|
||||
/// </summary>
|
||||
public byte ToByte(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot convert {nameof(DWord)} to type {typeof(byte)}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This operation is not supported.
|
||||
/// </summary>
|
||||
public char ToChar(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot convert {nameof(DWord)} to type {typeof(char)}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This operation is not supported.
|
||||
/// </summary>
|
||||
public DateTime ToDateTime(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot convert {nameof(DWord)} to type {typeof(DateTime)}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This operation is not supported.
|
||||
/// </summary>
|
||||
public decimal ToDecimal(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot convert {nameof(DWord)} to type {typeof(decimal)}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the value of this instance to an equivalent double-precision floating-point number using the
|
||||
/// specified culture-specific formatting information.
|
||||
/// </summary>
|
||||
/// <param name="provider">An <see cref="IFormatProvider"/> interface implementation that supplies
|
||||
/// culture-specific formatting information.</param>
|
||||
/// <returns>A double-precision floating-point number equivalent to the value of this instance.</returns>
|
||||
public double ToDouble(IFormatProvider provider)
|
||||
{
|
||||
return Single;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This operation is not supported.
|
||||
/// </summary>
|
||||
public short ToInt16(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot convert {nameof(DWord)} to type {typeof(short)}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the value of this instance to an equivalent 32-bit signed integer using the specified
|
||||
/// culture-specific formatting information.
|
||||
/// </summary>
|
||||
/// <param name="provider">An <see cref="IFormatProvider"/> interface implementation that supplies
|
||||
/// culture-specific formatting information.</param>
|
||||
/// <returns>An 32-bit signed integer equivalent to the value of this instance.</returns>
|
||||
public int ToInt32(IFormatProvider provider)
|
||||
{
|
||||
return Int32;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the value of this instance to an equivalent 64-bit signed integer using the specified
|
||||
/// culture-specific formatting information.
|
||||
/// </summary>
|
||||
/// <param name="provider">An <see cref="IFormatProvider"/> interface implementation that supplies
|
||||
/// culture-specific formatting information.</param>
|
||||
/// <returns>An 64-bit signed integer equivalent to the value of this instance.</returns>
|
||||
public long ToInt64(IFormatProvider provider)
|
||||
{
|
||||
return Int32;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This operation is not supported.
|
||||
/// </summary>
|
||||
public sbyte ToSByte(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot convert {nameof(DWord)} to type {nameof(String)}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the value of this instance to an equivalent single-precision floating-point number using the
|
||||
/// specified culture-specific formatting information.
|
||||
/// </summary>
|
||||
/// <param name="provider">An <see cref="IFormatProvider"/> interface implementation that supplies
|
||||
/// culture-specific formatting information.</param>
|
||||
/// <returns>A single-precision floating-point number equivalent to the value of this instance.</returns>
|
||||
public float ToSingle(IFormatProvider provider)
|
||||
{
|
||||
return Single;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This operation is not supported.
|
||||
/// </summary>
|
||||
public string ToString(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot convert {nameof(DWord)} to type {nameof(String)}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the value of this instance to an <see cref="Object"/> of the specified <see cref="Type"/> that has
|
||||
/// an equivalent value, using the specified culture-specific formatting information.
|
||||
/// </summary>
|
||||
/// <param name="conversionType">The <see cref="Type"/> to which the value of this instance is converted.
|
||||
/// </param>
|
||||
/// <param name="provider">An <see cref="IFormatProvider"/> interface implementation that supplies
|
||||
/// culture-specific formatting information.</param>
|
||||
/// <returns>An <see cref="Object"/> instance of type conversionType whose value is equivalent to the value of
|
||||
/// this instance.</returns>
|
||||
public object ToType(Type conversionType, IFormatProvider provider)
|
||||
{
|
||||
if (conversionType == typeof(Int32) || conversionType == typeof(Int64))
|
||||
{
|
||||
return Int32;
|
||||
}
|
||||
else if (conversionType == typeof(Single) || conversionType == typeof(Double))
|
||||
{
|
||||
return Single;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Cannot convert {nameof(DWord)} to type {conversionType}.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This operation is not supported.
|
||||
/// </summary>
|
||||
public ushort ToUInt16(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot convert {nameof(DWord)} to type {nameof(UInt16)}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This operation is not supported.
|
||||
/// </summary>
|
||||
public uint ToUInt32(IFormatProvider provider)
|
||||
{
|
||||
return UInt32;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This operation is not supported.
|
||||
/// </summary>
|
||||
public ulong ToUInt64(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot convert {nameof(DWord)} to type {nameof(UInt64)}.");
|
||||
}
|
||||
}
|
||||
}
|
438
Switch_Toolbox_Library/IO/SyrootCommon/Half.cs
Normal file
438
Switch_Toolbox_Library/IO/SyrootCommon/Half.cs
Normal file
|
@ -0,0 +1,438 @@
|
|||
using System;
|
||||
|
||||
namespace Syroot.IOExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a 16-bit half-precision floating point value according to the IEEE 754 standard.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Examples:
|
||||
/// SEEEEEFF_FFFFFFFF
|
||||
/// 0b00000000_00000000 = 0
|
||||
/// 1b00000000_00000000 = -0
|
||||
/// 0b00111100_00000000 = 1
|
||||
/// 0b11000000_00000000 = -2
|
||||
/// 0b11111011_11111111 = 65504 (MaxValue)
|
||||
/// 0b01111100_00000000 = PositiveInfinity
|
||||
/// 0b11111100_00000000 = NegativeInfinity
|
||||
/// </remarks>
|
||||
public struct Half
|
||||
{
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Represents the smallest positive <see cref="Half"/> value greater than zero.
|
||||
/// </summary>
|
||||
public static readonly Half Epsilon = new Half(1);
|
||||
|
||||
/// <summary>
|
||||
/// Represents the largest possible value of <see cref="Half"/>.
|
||||
/// </summary>
|
||||
public static readonly Half MaxValue = new Half(0b01111011_11111111);
|
||||
|
||||
/// <summary>
|
||||
/// Represents the smallest possible value of <see cref="Half"/>.
|
||||
/// </summary>
|
||||
public static readonly Half MinValue = new Half(0b11111011_11111111);
|
||||
|
||||
/// <summary>
|
||||
/// Represents not a number (NaN).
|
||||
/// </summary>
|
||||
public static readonly Half NaN = new Half(0b11111110_00000000);
|
||||
|
||||
/// <summary>
|
||||
/// Represents negative infinity.
|
||||
/// </summary>
|
||||
public static readonly Half NegativeInfinity = new Half(0b11111100_00000000);
|
||||
|
||||
/// <summary>
|
||||
/// Represents positive infinity.
|
||||
/// </summary>
|
||||
public static readonly Half PositiveInfinity = new Half(0b01111100_00000000);
|
||||
|
||||
private static readonly uint[] _mantissaTable;
|
||||
private static readonly uint[] _exponentTable;
|
||||
private static readonly uint[] _offsetTable;
|
||||
private static readonly ushort[] _baseTable;
|
||||
private static readonly byte[] _shiftTable;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Half"/> struct from the given <paramref name="raw"/>
|
||||
/// representation.
|
||||
/// </summary>
|
||||
/// <param name="raw">The raw representation of the internally stored bits.</param>
|
||||
internal Half(ushort raw)
|
||||
{
|
||||
Raw = raw;
|
||||
}
|
||||
|
||||
static Half()
|
||||
{
|
||||
int i;
|
||||
|
||||
// Generate tables for Half to Single conversions.
|
||||
|
||||
// Generate the mantissa table.
|
||||
_mantissaTable = new uint[2048];
|
||||
|
||||
// 0 => 0
|
||||
_mantissaTable[0] = 0;
|
||||
|
||||
// Transform subnormal to normalized.
|
||||
for (i = 1; i < 1024; i++)
|
||||
{
|
||||
uint m = ((uint)i) << 13;
|
||||
uint e = 0;
|
||||
|
||||
while ((m & 0x00800000) == 0)
|
||||
{
|
||||
e -= 0x00800000;
|
||||
m <<= 1;
|
||||
}
|
||||
m &= ~0x00800000U;
|
||||
e += 0x38800000;
|
||||
_mantissaTable[i] = m | e;
|
||||
}
|
||||
|
||||
// Normal case.
|
||||
for (i = 1024; i < 2048; i++)
|
||||
{
|
||||
_mantissaTable[i] = 0x38000000 + (((uint)(i - 1024)) << 13);
|
||||
}
|
||||
|
||||
// Generate the exponent table.
|
||||
_exponentTable = new uint[64];
|
||||
|
||||
// 0 => 0
|
||||
_exponentTable[0] = 0;
|
||||
|
||||
for (i = 1; i < 63; i++)
|
||||
{
|
||||
if (i < 31)
|
||||
{
|
||||
// Positive numbers.
|
||||
_exponentTable[i] = ((uint)i) << 23;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Negative numbers.
|
||||
_exponentTable[i] = 0x80000000 + (((uint)(i - 32)) << 23);
|
||||
}
|
||||
}
|
||||
_exponentTable[31] = 0x47800000;
|
||||
_exponentTable[32] = 0x80000000;
|
||||
_exponentTable[63] = 0xC7800000;
|
||||
|
||||
// Generate the offset table.
|
||||
_offsetTable = new uint[64];
|
||||
_offsetTable[0] = 0;
|
||||
for (i = 1; i < 64; i++)
|
||||
{
|
||||
_offsetTable[i] = 1024;
|
||||
}
|
||||
_offsetTable[32] = 0;
|
||||
|
||||
// Generate tables for Single to Half conversions.
|
||||
|
||||
//Generate the base and shift tables.
|
||||
_baseTable = new ushort[512];
|
||||
_shiftTable = new byte[512];
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
int e = i - 127;
|
||||
if (e < -24)
|
||||
{
|
||||
// Very small numbers map to zero.
|
||||
_baseTable[i | 0x000] = 0x0000;
|
||||
_baseTable[i | 0x100] = 0x8000;
|
||||
_shiftTable[i | 0x000] = 24;
|
||||
_shiftTable[i | 0x100] = 24;
|
||||
}
|
||||
else if (e < -14)
|
||||
{
|
||||
// Small numbers map to denorms.
|
||||
_baseTable[i | 0x000] = (ushort)(0x0400 >> (-e - 14));
|
||||
_baseTable[i | 0x100] = (ushort)((0x0400 >> (-e - 14)) | 0x8000);
|
||||
_shiftTable[i | 0x000] = (byte)(-e - 1);
|
||||
_shiftTable[i | 0x100] = (byte)(-e - 1);
|
||||
}
|
||||
else if (e <= 15)
|
||||
{
|
||||
// Normal numbers just lose precision.
|
||||
_baseTable[i | 0x000] = (ushort)((e + 15) << 10);
|
||||
_baseTable[i | 0x100] = (ushort)(((e + 15) << 10) | 0x8000);
|
||||
_shiftTable[i | 0x000] = 13;
|
||||
_shiftTable[i | 0x100] = 13;
|
||||
}
|
||||
else if (e < 128)
|
||||
{
|
||||
// Large numbers map to Infinity.
|
||||
_baseTable[i | 0x000] = 0x7C00;
|
||||
_baseTable[i | 0x100] = 0xFC00;
|
||||
_shiftTable[i | 0x000] = 24;
|
||||
_shiftTable[i | 0x100] = 24;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Infinity and NaN's stay Infinity and NaN's.
|
||||
_baseTable[i | 0x000] = 0x7C00;
|
||||
_baseTable[i | 0x100] = 0xFC00;
|
||||
_shiftTable[i | 0x000] = 13;
|
||||
_shiftTable[i | 0x100] = 13;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets the internally stored value to represent the instance.
|
||||
/// </summary>
|
||||
/// <remarks>Signed to get arithmetic rather than logical shifts.</remarks>
|
||||
internal ushort Raw { get; private set; }
|
||||
|
||||
// ---- OPERATORS ----------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Returns the given <see cref="Half"/>.
|
||||
/// </summary>
|
||||
/// <param name="a">The <see cref="Half"/>.</param>
|
||||
/// <returns>The result.</returns>
|
||||
public static Half operator +(Half a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the first <see cref="Half"/> to the second one.
|
||||
/// </summary>
|
||||
/// <param name="a">The first <see cref="Half"/>.</param>
|
||||
/// <param name="b">The second <see cref="Half"/>.</param>
|
||||
/// <returns>The addition result.</returns>
|
||||
public static Half operator +(Half a, Half b)
|
||||
{
|
||||
return (Half)((float)a + (float)b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Negates the given <see cref="Half"/>.
|
||||
/// </summary>
|
||||
/// <param name="a">The <see cref="Half"/> to negate.</param>
|
||||
/// <returns>The negated result.</returns>
|
||||
public static Half operator -(Half a)
|
||||
{
|
||||
return new Half((ushort)(a.Raw ^ 0x8000));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts the first <see cref="Half"/> from the second one.
|
||||
/// </summary>
|
||||
/// <param name="a">The first <see cref="Half"/>.</param>
|
||||
/// <param name="b">The second <see cref="Half"/>.</param>
|
||||
/// <returns>The subtraction result.</returns>
|
||||
public static Half operator -(Half a, Half b)
|
||||
{
|
||||
return (Half)((float)a - (float)b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplicates the first <see cref="Half"/> by the second one.
|
||||
/// </summary>
|
||||
/// <param name="a">The first <see cref="Half"/>.</param>
|
||||
/// <param name="b">The second <see cref="Half"/>.</param>
|
||||
/// <returns>The multiplication result.</returns>
|
||||
public static Half operator *(Half a, Half b)
|
||||
{
|
||||
return (Half)((float)a * (float)b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Divides the first <see cref="Half"/> through the second one.
|
||||
/// </summary>
|
||||
/// <param name="a">The first <see cref="Half"/>.</param>
|
||||
/// <param name="b">The second <see cref="Half"/>.</param>
|
||||
/// <returns>The division result.</returns>
|
||||
public static Half operator /(Half a, Half b)
|
||||
{
|
||||
return (Half)((float)a / (float)b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the first specified <see cref="Half"/> is the same as the second
|
||||
/// specified <see cref="Half"/>.
|
||||
/// </summary>
|
||||
/// <param name="a">The first <see cref="Half"/> to compare.</param>
|
||||
/// <param name="b">The second <see cref="Half"/> to compare.</param>
|
||||
/// <returns>true, if both <see cref="Half"/> are the same.</returns>
|
||||
public static bool operator ==(Half a, Half b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the first specified <see cref="Half"/> is not the same as the second
|
||||
/// specified <see cref="Half"/>.
|
||||
/// </summary>
|
||||
/// <param name="a">The first <see cref="Half"/> to compare.</param>
|
||||
/// <param name="b">The second <see cref="Half"/> to compare.</param>
|
||||
/// <returns>true, if both <see cref="Half"/> are not the same.</returns>
|
||||
public static bool operator !=(Half a, Half b)
|
||||
{
|
||||
return !a.Equals(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to a <see cref="Half"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Int32"/> value to represent in the new <see cref="Half"/>
|
||||
/// instance.</param>
|
||||
public static explicit operator Half(Int32 value)
|
||||
{
|
||||
return (Half)(float)value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to a <see cref="Half"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Double"/> value to represent in the new <see cref="Half"/>
|
||||
/// instance.</param>
|
||||
public static explicit operator Half(Double value)
|
||||
{
|
||||
return (Half)(float)value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to a <see cref="Half"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Single"/> value to represent in the new <see cref="Half"/>
|
||||
/// instance.</param>
|
||||
public static explicit operator Half(Single value)
|
||||
{
|
||||
uint uint32 = ((DWord)value).UInt32;
|
||||
return new Half((ushort)(_baseTable[(uint32 >> 23) & 0x01FF]
|
||||
+ ((uint32 & 0x007FFFFF) >> _shiftTable[(uint32 >> 23) & 0x01FF])));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to a <see cref="Double"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Half"/> value to represent in the new <see cref="Double"/>
|
||||
/// instance.</param>
|
||||
public static implicit operator Double(Half value)
|
||||
{
|
||||
return (float)value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to a <see cref="Int32"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Half"/> value to represent in the new <see cref="Int32"/>
|
||||
/// instance.</param>
|
||||
public static explicit operator Int32(Half value)
|
||||
{
|
||||
return (int)(float)value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given <paramref name="value"/> value to a <see cref="Single"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Half"/> value to represent in the new <see cref="Single"/>
|
||||
/// instance.</param>
|
||||
public static implicit operator Single(Half value)
|
||||
{
|
||||
DWord result = _mantissaTable[_offsetTable[value.Raw >> 10] + (((uint)value.Raw) & 0x03FF)]
|
||||
+ _exponentTable[value.Raw >> 10];
|
||||
return result.Single;
|
||||
}
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="Half"/> is the same as the second specified
|
||||
/// <see cref="Half"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare, if it is a <see cref="Half"/>.</param>
|
||||
/// <returns>true, if both <see cref="Half"/> are the same.</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is Half))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Half half = (Half)obj;
|
||||
return Equals(half);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a hash code as an indication for object equality.
|
||||
/// </summary>
|
||||
/// <returns>The hash code.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Raw;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string describing this <see cref="Half"/>.
|
||||
/// </summary>
|
||||
/// <returns>A string describing this <see cref="Half"/>.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return ((double)this).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current <see cref="Half"/> is equal to another <see cref="Half"/>.
|
||||
/// </summary>
|
||||
/// <param name="other">A <see cref="Half"/> to compare with this <see cref="Half"/>.</param>
|
||||
/// <returns>true if the current <see cref="Half"/> is equal to the other parameter; otherwise, false.
|
||||
/// </returns>
|
||||
public bool Equals(Half other)
|
||||
{
|
||||
return Equals(Raw == other.Raw);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified number evaluates to not a number (<see cref="NaN"/>).
|
||||
/// </summary>
|
||||
/// <param name="half">A half-precision floating-point number.</param>
|
||||
/// <returns><c>true</c> if value evaluates to not a number (<see cref="NaN"/>); otherwise <c>false</c>.</returns>
|
||||
public static bool IsNaN(Half half)
|
||||
{
|
||||
return (half.Raw & 0x7FFF) > PositiveInfinity.Raw;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified number evaluates to negative or positive infinity.
|
||||
/// </summary>
|
||||
/// <param name="half">A half-precision floating-point number.</param>
|
||||
/// <returns><c>true</c> if half evaluates to <see cref="PositiveInfinity"/> or <see cref="NegativeInfinity"/>;
|
||||
/// otherwise <c>false</c>.</returns>
|
||||
public static bool IsInfinity(Half half)
|
||||
{
|
||||
return (half.Raw & 0x7FFF) == PositiveInfinity.Raw;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified number evaluates to negative infinity.
|
||||
/// </summary>
|
||||
/// <param name="half">A half-precision floating-point number.</param>
|
||||
/// <returns><c>true</c> if half evaluates to <see cref="NegativeInfinity"/>; otherwise <c>false</c>.</returns>
|
||||
public static bool IsNegativeInfinity(Half half)
|
||||
{
|
||||
return half.Raw == NegativeInfinity.Raw;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified number evaluates to positive infinity.
|
||||
/// </summary>
|
||||
/// <param name="half">A half-precision floating-point number.</param>
|
||||
/// <returns><c>true</c> if half evaluates to <see cref="PositiveInfinity"/>; otherwise <c>false</c>.</returns>
|
||||
public static bool IsPositiveInfinity(Half half)
|
||||
{
|
||||
return half.Raw == PositiveInfinity.Raw;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -557,6 +557,7 @@
|
|||
<Compile Include="Generics\GenericMatTexture.cs" />
|
||||
<Compile Include="Generics\GenericModel.cs" />
|
||||
<Compile Include="Generics\GenericObject.cs" />
|
||||
<Compile Include="Generics\GenericPolygonGroup.cs" />
|
||||
<Compile Include="Generics\GenericTexture.cs" />
|
||||
<Compile Include="Generics\OpenGLTexture.cs" />
|
||||
<Compile Include="Generics\RenderableTex.cs" />
|
||||
|
@ -613,6 +614,8 @@
|
|||
<Compile Include="IO\DWord.cs" />
|
||||
<Compile Include="IO\FileReader.cs" />
|
||||
<Compile Include="IO\FileWriter.cs" />
|
||||
<Compile Include="IO\SyrootCommon\DWord.cs" />
|
||||
<Compile Include="IO\SyrootCommon\Half.cs" />
|
||||
<Compile Include="IO\IOExtensions.cs" />
|
||||
<Compile Include="IO\Matrix4x4.cs" />
|
||||
<Compile Include="IO\STFileLoader.cs" />
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,8 +1,6 @@
|
|||
#version 330
|
||||
in vec3 normal;
|
||||
in vec3 position;
|
||||
|
||||
|
||||
in vec2 f_texcoord0;
|
||||
in vec2 f_texcoord1;
|
||||
in vec2 f_texcoord2;
|
||||
|
|
|
@ -54,20 +54,6 @@ vec3 SpecularPass(vec3 I, vec3 normal, int HasSpecularMap, sampler2D SpecularMap
|
|||
return result * intensity;
|
||||
}
|
||||
|
||||
float GetComponent(int Type, vec4 Texture)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case 0: return Texture.r;
|
||||
case 1: return Texture.g;
|
||||
case 2: return Texture.b;
|
||||
case 3: return Texture.a;
|
||||
case 4: return 1;
|
||||
case 5: return 0;
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 EmissionPass(sampler2D EmissionMap, float emission_intensity, VertexAttributes vert, float texCoordIndex, vec3 emission_color)
|
||||
{
|
||||
vec3 result = vec3(0);
|
||||
|
|
289
Toolbox/Shader/GFBModel.frag
Normal file
289
Toolbox/Shader/GFBModel.frag
Normal file
|
@ -0,0 +1,289 @@
|
|||
#version 330
|
||||
in vec3 objectPosition;
|
||||
in vec2 f_texcoord0;
|
||||
in vec2 f_texcoord1;
|
||||
in vec2 f_texcoord2;
|
||||
in vec2 f_texcoord3;
|
||||
|
||||
|
||||
in vec3 normal;
|
||||
in vec4 vertexColor;
|
||||
in vec3 tangent;
|
||||
in vec3 binormal;
|
||||
|
||||
in vec3 boneWeightsColored;
|
||||
|
||||
// Viewport Camera/Lighting
|
||||
uniform mat4 mtxCam;
|
||||
uniform mat4 mtxMdl;
|
||||
|
||||
uniform vec3 specLightDirection;
|
||||
uniform vec3 difLightDirection;
|
||||
uniform mat4 projMatrix;
|
||||
uniform mat4 normalMatrix;
|
||||
uniform mat4 modelViewMatrix;
|
||||
uniform mat4 rotationMatrix;
|
||||
|
||||
uniform int colorOverride;
|
||||
uniform int renderType;
|
||||
uniform int renderVertColor;
|
||||
uniform mat4 modelview;
|
||||
uniform int uvChannel;
|
||||
|
||||
// Texture Samplers
|
||||
uniform sampler2D DiffuseMap;
|
||||
uniform sampler2D BakeShadowMap;
|
||||
uniform sampler2D NormalMap;
|
||||
uniform sampler2D BakeLightMap;
|
||||
uniform sampler2D UVTestPattern;
|
||||
uniform sampler2D EmissionMap;
|
||||
uniform sampler2D SpecularMap;
|
||||
uniform sampler2D DiffuseLayer;
|
||||
uniform sampler2D MetalnessMap;
|
||||
uniform sampler2D RoughnessMap;
|
||||
uniform sampler2D ProjectionMap;
|
||||
uniform sampler2D SphereMap;
|
||||
|
||||
// Texture Map Toggles
|
||||
uniform int HasDiffuse;
|
||||
uniform int HasNormalMap;
|
||||
uniform int HasSpecularMap;
|
||||
uniform int HasShadowMap;
|
||||
uniform int HasAmbientOcclusionMap;
|
||||
uniform int HasLightMap;
|
||||
uniform int HasEmissionMap;
|
||||
uniform int HasDiffuseLayer;
|
||||
uniform int HasMetalnessMap;
|
||||
uniform int HasRoughnessMap;
|
||||
uniform int HasProjectionMap;
|
||||
|
||||
// Diffuse Channel Toggles
|
||||
uniform int RedChannel;
|
||||
uniform int GreenChannel;
|
||||
uniform int BlueChannel;
|
||||
uniform int AlphaChannel;
|
||||
|
||||
uniform samplerCube irradianceMap;
|
||||
uniform samplerCube specularIbl;
|
||||
uniform sampler2D brdfLUT;
|
||||
|
||||
int isTransparent;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
struct VertexAttributes {
|
||||
vec3 objectPosition;
|
||||
vec2 texCoord;
|
||||
vec2 texCoord2;
|
||||
vec2 texCoord3;
|
||||
vec4 vertexColor;
|
||||
vec3 normal;
|
||||
vec3 viewNormal;
|
||||
vec3 tangent;
|
||||
vec3 binormal;
|
||||
};
|
||||
|
||||
#define gamma 2.2
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
// Shader code adapted from learnopengl.com's PBR tutorial:
|
||||
// https://learnopengl.com/PBR/Theory
|
||||
|
||||
//Defined in PBR Utilty
|
||||
vec3 FresnelSchlick(float cosTheta, vec3 F0);
|
||||
vec3 FresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness);
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness);
|
||||
float GeometrySchlickGGX(float NdotV, float roughness);
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness);
|
||||
vec3 saturation(vec3 rgb, float adjustment);
|
||||
|
||||
//In Utility.frag
|
||||
float GetComponent(int Type, vec4 Texture);
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor = vec4(1);
|
||||
|
||||
// Create a struct for passing all the vertex attributes to other functions.
|
||||
VertexAttributes vert;
|
||||
vert.objectPosition = objectPosition;
|
||||
vert.texCoord = f_texcoord0;
|
||||
vert.texCoord2 = f_texcoord1;
|
||||
vert.texCoord3 = f_texcoord2;
|
||||
vert.vertexColor = vertexColor;
|
||||
vert.normal = normal;
|
||||
vert.tangent = tangent;
|
||||
vert.binormal = binormal;
|
||||
|
||||
float specIntensity = 1;
|
||||
|
||||
// Wireframe color.
|
||||
if (colorOverride == 1)
|
||||
{
|
||||
fragColor = vec4(1);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 albedo = vec3(1);
|
||||
if (HasDiffuse == 1)
|
||||
{
|
||||
vec4 DiffuseTex = pow(texture(DiffuseMap, f_texcoord0).rgba, vec4(gamma));
|
||||
|
||||
//Comp Selectors
|
||||
albedo.r = GetComponent(RedChannel, DiffuseTex);
|
||||
albedo.g = GetComponent(GreenChannel, DiffuseTex);
|
||||
albedo.b = GetComponent(BlueChannel, DiffuseTex);
|
||||
}
|
||||
|
||||
float metallic = 0;
|
||||
if (HasMetalnessMap == 1)
|
||||
metallic = texture(MetalnessMap, f_texcoord0).r;
|
||||
|
||||
float roughness = 0.5;
|
||||
if (HasRoughnessMap == 1)
|
||||
roughness = texture(RoughnessMap, f_texcoord0).r;
|
||||
|
||||
float ao = 1;
|
||||
if (HasShadowMap == 1)
|
||||
ao = texture(BakeShadowMap, f_texcoord1).r;
|
||||
|
||||
vec3 emissionTerm = vec3(0);
|
||||
|
||||
// Calculate shading vectors.
|
||||
vec3 I = vec3(0,0,-1) * mat3(mtxCam);
|
||||
vec3 N = normal;
|
||||
|
||||
|
||||
vec3 V = normalize(I); // view
|
||||
vec3 L = normalize(specLightDirection); // Light
|
||||
vec3 H = normalize(specLightDirection + I); // half angle
|
||||
vec3 R = reflect(-I, N); // reflection
|
||||
|
||||
vec3 f0 = mix(vec3(0.04), albedo, metallic); // dialectric
|
||||
vec3 kS = FresnelSchlickRoughness(max(dot(N, V), 0.0), f0, roughness);
|
||||
|
||||
vec3 kD = 1.0 - kS;
|
||||
kD *= 1.0 - metallic;
|
||||
|
||||
// Diffuse pass
|
||||
vec3 diffuseIblColor = texture(irradianceMap, N).rgb;
|
||||
vec3 diffuseTerm = diffuseIblColor * albedo;
|
||||
diffuseTerm *= kD;
|
||||
diffuseTerm *= ao;
|
||||
|
||||
// Adjust for metalness.
|
||||
diffuseTerm *= clamp(1 - metallic, 0, 1);
|
||||
diffuseTerm *= vec3(1) - kS.xxx;
|
||||
//
|
||||
// Specular pass.
|
||||
int maxSpecularLod = 8;
|
||||
vec3 specularIblColor = textureLod(specularIbl, R, roughness * maxSpecularLod).rgb;
|
||||
|
||||
|
||||
vec2 envBRDF = texture(brdfLUT, vec2(max(dot(N, V), 0.0), roughness)).rg;
|
||||
vec3 brdfTerm = (kS * envBRDF.x + envBRDF.y);
|
||||
// vec3 specularTerm = specularIblColor * (kS * brdfTerm.x + brdfTerm.y) * specIntensity;
|
||||
vec3 specularTerm = specularIblColor * brdfTerm * specIntensity;
|
||||
|
||||
// Add render passes.
|
||||
fragColor.rgb = vec3(0);
|
||||
fragColor.rgb += diffuseTerm;
|
||||
fragColor.rgb += specularTerm;
|
||||
fragColor.rgb += emissionTerm;
|
||||
|
||||
|
||||
// Global brightness adjustment.
|
||||
fragColor.rgb *= 2.5;
|
||||
|
||||
fragColor.rgb *= min(boneWeightsColored, vec3(1));
|
||||
|
||||
// HDR tonemapping
|
||||
fragColor.rgb = fragColor.rgb / (fragColor.rgb + vec3(1.0));
|
||||
|
||||
// Convert back to sRGB.
|
||||
fragColor.rgb = pow(fragColor.rgb, vec3(1 / gamma));
|
||||
|
||||
// Alpha calculations.
|
||||
if (isTransparent == 1)
|
||||
{
|
||||
float alpha = GetComponent(AlphaChannel, texture(DiffuseMap, f_texcoord0));
|
||||
fragColor.a = alpha;
|
||||
}
|
||||
|
||||
|
||||
//Debug Shading
|
||||
vec2 displayTexCoord = f_texcoord0;
|
||||
|
||||
if (uvChannel == 1)
|
||||
displayTexCoord = f_texcoord0;
|
||||
if (uvChannel == 2)
|
||||
displayTexCoord = f_texcoord2;
|
||||
if (uvChannel == 3)
|
||||
displayTexCoord = f_texcoord3;
|
||||
|
||||
vec3 displayNormal = (normal.xyz * 0.5) + 0.5;
|
||||
if (renderType == 1) // normals color
|
||||
fragColor = vec4(displayNormal.rgb,1);
|
||||
else if (renderType == 2)
|
||||
{
|
||||
diffuseIblColor = texture(irradianceMap, N).rgb;
|
||||
diffuseTerm = diffuseIblColor * vec3(0.5);
|
||||
diffuseTerm *= kD;
|
||||
diffuseTerm *= ao;
|
||||
|
||||
// Adjust for metalness.
|
||||
diffuseTerm *= clamp(1 - metallic, 0, 1);
|
||||
diffuseTerm *= vec3(1) - kS.xxx;
|
||||
|
||||
fragColor.rgb = vec3(0);
|
||||
fragColor.rgb += diffuseTerm;
|
||||
fragColor.rgb += specularTerm;
|
||||
fragColor.rgb += emissionTerm;
|
||||
// Global brightness adjustment.
|
||||
fragColor.rgb *= 1.5;
|
||||
// HDR tonemapping
|
||||
fragColor.rgb = fragColor.rgb / (fragColor.rgb + vec3(1.0));
|
||||
// Convert back to sRGB.
|
||||
fragColor.rgb = pow(fragColor.rgb, vec3(1 / gamma));
|
||||
}
|
||||
else if (renderType == 3) //DiffuseColor
|
||||
{
|
||||
//Comp Selectors
|
||||
vec4 diffuseMapColor = vec4(texture(DiffuseMap, displayTexCoord).rgb, 1);
|
||||
diffuseMapColor.r = GetComponent(RedChannel, diffuseMapColor);
|
||||
diffuseMapColor.g = GetComponent(GreenChannel, diffuseMapColor);
|
||||
diffuseMapColor.b = GetComponent(BlueChannel, diffuseMapColor);
|
||||
|
||||
fragColor = vec4(diffuseMapColor.rgb, 1);
|
||||
}
|
||||
else if (renderType == 5) // vertexColor
|
||||
fragColor = vertexColor;
|
||||
else if (renderType == 6) //Display Ambient Occlusion
|
||||
fragColor = vec4(vec3(ao), 1);
|
||||
else if (renderType == 7) // uv coords
|
||||
fragColor = vec4(displayTexCoord.x, displayTexCoord.y, 1, 1);
|
||||
else if (renderType == 8) // uv test pattern
|
||||
{
|
||||
fragColor = vec4(texture(UVTestPattern, displayTexCoord).rgb, 1);
|
||||
}
|
||||
else if (renderType == 9) //Display tangents
|
||||
{
|
||||
vec3 displayTangent = (tangent * 0.5) + 0.5;
|
||||
if (dot(tangent, vec3(1)) == 0)
|
||||
displayTangent = vec3(0);
|
||||
|
||||
fragColor = vec4(displayTangent,1);
|
||||
}
|
||||
else if (renderType == 10) //Display binormals
|
||||
{
|
||||
vec3 displayBinormal = (binormal * 0.5) + 0.5;
|
||||
if (dot(binormal, vec3(1)) == 0)
|
||||
displayBinormal = vec3(0);
|
||||
|
||||
fragColor = vec4(displayBinormal,1);
|
||||
}
|
||||
else if (renderType == 12)
|
||||
{
|
||||
fragColor.rgb = boneWeightsColored;
|
||||
}
|
||||
}
|
138
Toolbox/Shader/GFBModel.vert
Normal file
138
Toolbox/Shader/GFBModel.vert
Normal file
|
@ -0,0 +1,138 @@
|
|||
#version 330
|
||||
|
||||
const int MY_ARRAY_SIZE = 200;
|
||||
|
||||
in vec3 vPosition;
|
||||
in vec3 vNormal;
|
||||
in vec3 vTangent;
|
||||
in vec3 vBinormal;
|
||||
|
||||
in vec2 vUV0;
|
||||
in vec4 vColor;
|
||||
in vec4 vBone;
|
||||
in vec4 vWeight;
|
||||
in vec2 vUV1;
|
||||
in vec2 vUV2;
|
||||
|
||||
out vec3 objectPosition;
|
||||
out vec2 f_texcoord0;
|
||||
out vec2 f_texcoord1;
|
||||
out vec2 f_texcoord2;
|
||||
out vec2 f_texcoord3;
|
||||
|
||||
out vec3 normal;
|
||||
out vec4 vertexColor;
|
||||
out vec3 position;
|
||||
out vec3 tangent;
|
||||
out vec3 binormal;
|
||||
|
||||
out vec3 boneWeightsColored;
|
||||
|
||||
// Skinning uniforms
|
||||
uniform mat4 bones[190];
|
||||
|
||||
uniform mat4 mtxCam;
|
||||
uniform mat4 mtxMdl;
|
||||
uniform mat4 previewScale;
|
||||
|
||||
// Bone Weight Display
|
||||
uniform sampler2D weightRamp1;
|
||||
uniform sampler2D weightRamp2;
|
||||
uniform int selectedBoneIndex;
|
||||
uniform int debugOption;
|
||||
|
||||
uniform int NoSkinning;
|
||||
uniform int RigidSkinning;
|
||||
uniform int SingleBoneIndex;
|
||||
|
||||
vec2 ST0_Translate;
|
||||
float ST0_Rotate;
|
||||
vec2 ST0_Scale;
|
||||
|
||||
vec4 skin(vec3 pos, ivec4 index)
|
||||
{
|
||||
vec4 newPosition = vec4(pos.xyz, 1.0);
|
||||
|
||||
newPosition = bones[index.x] * vec4(pos, 1.0) * vWeight.x;
|
||||
newPosition += bones[index.y] * vec4(pos, 1.0) * vWeight.y;
|
||||
newPosition += bones[index.z] * vec4(pos, 1.0) * vWeight.z;
|
||||
if (vWeight.w < 1) //Necessary. Bones may scale weirdly without
|
||||
newPosition += bones[index.w] * vec4(pos, 1.0) * vWeight.w;
|
||||
|
||||
return newPosition;
|
||||
}
|
||||
|
||||
vec3 skinNRM(vec3 nr, ivec4 index)
|
||||
{
|
||||
vec3 newNormal = vec3(0);
|
||||
|
||||
newNormal = mat3(bones[index.x]) * nr * vWeight.x;
|
||||
newNormal += mat3(bones[index.y]) * nr * vWeight.y;
|
||||
newNormal += mat3(bones[index.z]) * nr * vWeight.z;
|
||||
newNormal += mat3(bones[index.w]) * nr * vWeight.w;
|
||||
|
||||
return newNormal;
|
||||
}
|
||||
|
||||
vec3 BoneWeightColor(float weights)
|
||||
{
|
||||
float rampInputLuminance = weights;
|
||||
rampInputLuminance = clamp((rampInputLuminance), 0.001, 0.999);
|
||||
if (debugOption == 1) // Greyscale
|
||||
return vec3(weights);
|
||||
else if (debugOption == 2) // Color 1
|
||||
return texture(weightRamp1, vec2(1 - rampInputLuminance, 0.50)).rgb;
|
||||
else // Color 2
|
||||
return texture(weightRamp2, vec2(1 - rampInputLuminance, 0.50)).rgb;
|
||||
}
|
||||
|
||||
float BoneWeightDisplay(ivec4 index)
|
||||
{
|
||||
float weight = 0;
|
||||
if (selectedBoneIndex == index.x)
|
||||
weight += vWeight.x;
|
||||
if (selectedBoneIndex == index.y)
|
||||
weight += vWeight.y;
|
||||
if (selectedBoneIndex == index.z)
|
||||
weight += vWeight.z;
|
||||
if (selectedBoneIndex == index.w)
|
||||
weight += vWeight.w;
|
||||
|
||||
if (selectedBoneIndex == index.x && RigidSkinning == 1)
|
||||
weight = 1;
|
||||
if (selectedBoneIndex == SingleBoneIndex && NoSkinning == 1)
|
||||
weight = 1;
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec4 index = ivec4(vBone);
|
||||
|
||||
vec4 objPos = vec4(vPosition.xyz, 1.0);
|
||||
if (vBone.x != -1.0)
|
||||
objPos = skin(vPosition, index);
|
||||
if(vBone.x != -1.0)
|
||||
normal = normalize((skinNRM(vNormal.xyz, index)).xyz);
|
||||
|
||||
vec4 position = mtxCam * mtxMdl * vec4(objPos.xyz, 1.0);
|
||||
|
||||
normal = vNormal;
|
||||
vertexColor = vColor;
|
||||
position = objPos;
|
||||
f_texcoord0 = vUV0;
|
||||
f_texcoord1 = vUV1;
|
||||
f_texcoord2 = vUV2;
|
||||
tangent = vTangent;
|
||||
|
||||
position = mtxCam * mtxMdl * vec4(vPosition.xyz, 1.0);
|
||||
|
||||
gl_Position = position;
|
||||
|
||||
objectPosition = position.xyz;
|
||||
|
||||
float totalWeight = BoneWeightDisplay(index);
|
||||
boneWeightsColored = BoneWeightColor(totalWeight).rgb;
|
||||
|
||||
}
|
55
Toolbox/Shader/Utility/PbrUtility.frag
Normal file
55
Toolbox/Shader/Utility/PbrUtility.frag
Normal file
|
@ -0,0 +1,55 @@
|
|||
#version 330
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
vec3 FresnelSchlick(float cosTheta, vec3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
vec3 FresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
|
||||
{
|
||||
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
float a = roughness*roughness;
|
||||
float a2 = a*a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH*NdotH;
|
||||
|
||||
float num = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
|
||||
return num / denom;
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r*r) / 8.0;
|
||||
|
||||
float num = NdotV;
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
|
||||
return num / denom;
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||
{
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
vec3 saturation(vec3 rgb, float adjustment)
|
||||
{
|
||||
const vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
vec3 intensity = vec3(dot(rgb, W));
|
||||
return mix(intensity, rgb, adjustment);
|
||||
}
|
|
@ -19,3 +19,17 @@ float SrgbToLinear(float x)
|
|||
vec3 SrgbToLinear(vec3 color) {
|
||||
return vec3(SrgbToLinear(color.r), SrgbToLinear(color.g), SrgbToLinear(color.b));
|
||||
}
|
||||
|
||||
float GetComponent(int Type, vec4 Texture)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case 0: return Texture.r;
|
||||
case 1: return Texture.g;
|
||||
case 2: return Texture.b;
|
||||
case 3: return Texture.a;
|
||||
case 4: return 1;
|
||||
case 5: return 0;
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -217,6 +217,12 @@
|
|||
<None Include="Shader\Bone.vert">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Shader\GFBModel.frag">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Shader\GFBModel.vert">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Shader\HDRSkyBox\HDRSkyBox.frag">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
@ -492,6 +498,9 @@
|
|||
</Content>
|
||||
<None Include="Resources\Save.png" />
|
||||
<None Include="Resources\UpdateIcon.png" />
|
||||
<None Include="Shader\Utility\PbrUtility.frag">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Include="Switch_Toolbox.csproj.user" />
|
||||
<Content Include="System.Numerics.Vectors.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
|
Loading…
Reference in a new issue