Improve gfmdl support. Fix raw astc exporting

This commit is contained in:
KillzXGaming 2019-06-21 18:18:22 -04:00
parent 6f22257113
commit 067244555a
28 changed files with 2663 additions and 87 deletions

Binary file not shown.

View file

@ -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?

View file

@ -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}");*/
}
}

View 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;
}
}
}

View file

@ -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();

View 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);
}
}
}

View file

@ -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" />

View file

@ -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!");

View file

@ -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
{

View 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;
}
}
}
}

View file

@ -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); }

View 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)}.");
}
}
}

View 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;
}
}
}

View file

@ -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.

View file

@ -1,8 +1,6 @@
#version 330
in vec3 normal;
in vec3 position;
in vec2 f_texcoord0;
in vec2 f_texcoord1;
in vec2 f_texcoord2;

View file

@ -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);

View 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;
}
}

View 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;
}

View 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);
}

View file

@ -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;
}
}

View file

@ -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>