Skip to content

Commit

Permalink
SM64DSe R103 v2.3.4 2017/06/21
Browse files Browse the repository at this point in the history
Changes:
- Add support in model and collision map editor to set whether bones are rendered always facing the camera ("billboard")
- Fix issue in model and collision map editor whereby the bone/transforms map wasn't being updated when adding or renaming bones
- Fix issue in OBJ exporter whereby models with multiple parent bones (areas) were being incorrectly split up
- Update BMD writer to automatically duplicate and assign materials shared across parent bones
- Allow specifiying the minimum number of areas in a level within the level settings form
  • Loading branch information
Fiachra1993 committed Jun 21, 2017
1 parent c012b77 commit dbcc232
Show file tree
Hide file tree
Showing 16 changed files with 288 additions and 71 deletions.
11 changes: 10 additions & 1 deletion ImportExport/Loaders/ExternalLoaders/DAELoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -563,12 +563,21 @@ private int[] ReadSkinController(string id, string skeletonRoot, string geometry
}
}

if (jointNames.Length > 31) Console.WriteLine("WARN: More than 31 matrices, your model will not import correctly.");
if (jointNames.Length > 31)
{
Console.WriteLine("DAELoader: WARN: More than 31 matrices, your model will not import correctly.");
}

for (int i = 0; i < jointNames.Length; i++)
{
Queue<ModelBase.BoneDef> hierarchy = new Queue<ModelBase.BoneDef>();
ModelBase.BoneDef child = m_Model.m_BoneTree.GetBoneByID(jointNames[i]);
if (child == null)
{
Console.WriteLine("DAELoader: WARN: Skin controller ["+ id + "] contains reference to joint name [" +
jointNames[i] + "] before joint has been read, skipping processing but failure likely");
continue;
}
hierarchy.Enqueue(child);
while (child.m_Parent != null)
{
Expand Down
14 changes: 8 additions & 6 deletions ImportExport/Loaders/ExternalLoaders/OBJLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,15 @@ public override ModelBase LoadModel(float scale)
}

ModelBase.BoneDef bone = m_Model.m_BoneTree.GetBoneByID(currentBone);
if (!bone.m_Geometries.Values.ElementAt(0).m_PolyLists.ContainsKey(curmaterial))
ModelBase.GeometryDef geomDef = bone.m_Geometries.Values.ElementAt(0);
string polyListKey = "polylist-" + curmaterial;
ModelBase.PolyListDef polyList;
if (!geomDef.m_PolyLists.TryGetValue(polyListKey, out polyList))
{
ModelBase.PolyListDef tmp = new ModelBase.PolyListDef(currentBone + "." + curmaterial, curmaterial);
tmp.m_FaceLists.Add(new ModelBase.FaceListDef());
bone.m_Geometries.Values.ElementAt(0).m_PolyLists.Add(curmaterial, tmp);
polyList = new ModelBase.PolyListDef(polyListKey, curmaterial);
polyList.m_FaceLists.Add(new ModelBase.FaceListDef());
geomDef.m_PolyLists.Add(polyList.m_ID, polyList);
}
ModelBase.PolyListDef polyList = bone.m_Geometries.Values.ElementAt(0).m_PolyLists[curmaterial];

ModelBase.FaceDef face = new ModelBase.FaceDef(nvtx);

Expand Down Expand Up @@ -500,7 +502,7 @@ protected void LoadBoneDefinitionsForOBJ(string filename)
bone.SetTranslation(translation);
}
break;
case "billboard": // Always rendered facing camera (not yet implemented)
case "billboard": // Always rendered facing camera
{
if (parts.Length < 2) continue;
bool billboard = (short.Parse(parts[1]) == 1);
Expand Down
3 changes: 2 additions & 1 deletion ImportExport/Loaders/InternalLoaders/BMDLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public override ModelBase LoadModel(float scale)
ModelBase.BoneDef bone = new ModelBase.BoneDef(mdchunk.m_Name);
bone.SetScale(mdchunk.m_20_12Scale);
bone.SetRotation(mdchunk.m_4_12Rotation);
bone.SetTranslation(mdchunk.m_20_12Translation);
bone.SetTranslation(mdchunk.m_20_12Translation);
bone.m_Billboard = mdchunk.m_Billboard;

if (mdchunk.m_ParentOffset == 0)
{
Expand Down
29 changes: 28 additions & 1 deletion ImportExport/ModelBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public class BoneDef

public bool m_HasChildren { get { return m_Children.Count > 0; } }

public bool m_Billboard;// Not used as not working
public bool m_Billboard;

public BoneDef(string id)
{
Expand Down Expand Up @@ -574,6 +574,33 @@ public MaterialDef(string id)
m_TexGenMode = TexGenMode.None;
}

public MaterialDef(string id, MaterialDef that)
{
m_ID = id;
m_TextureDefID = that.m_TextureDefID;
m_Lights = new bool[4];
Array.Copy(that.m_Lights, m_Lights, 4);
m_PolygonDrawingFace = that.m_PolygonDrawingFace;
m_Alpha = that.m_Alpha;
m_WireMode = that.m_WireMode;
m_PolygonMode = that.m_PolygonMode;
m_FogFlag = that.m_FogFlag;
m_DepthTestDecal = that.m_DepthTestDecal;
m_RenderOnePixelPolygons = that.m_RenderOnePixelPolygons;
m_FarClipping = that.m_FarClipping;
m_Diffuse = that.m_Diffuse;
m_Ambient = that.m_Ambient;
m_Specular = that.m_Specular;
m_Emission = that.m_Emission;
m_ShininessTableEnabled = that.m_ShininessTableEnabled;
m_TexTiling = new TexTiling[2];
Array.Copy(that.m_TexTiling, m_TexTiling, 2);
m_TextureScale = that.m_TextureScale;
m_TextureRotation = that.m_TextureRotation;
m_TextureTranslation = that.m_TextureTranslation;
m_TexGenMode = that.m_TexGenMode;
}

public enum PolygonDrawingFace
{
Front,
Expand Down
29 changes: 17 additions & 12 deletions ImportExport/Writers/ExternalWriters/OBJWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,25 @@ public override void WriteModel(bool save = true)
if (objSplitBoneID != boneIndex)
{
ModelBase.BoneDef newBone = flatBoneList[objSplitBoneID];

if (!newBone.m_Geometries.ContainsKey(geometry.m_ID))
newBone.m_Geometries.Add(geometry.m_ID, new ModelBase.GeometryDef(geometry.m_ID));
if (!newBone.m_Geometries[geometry.m_ID].m_PolyLists.ContainsKey(polyList.m_MaterialName))
// For models using "areas" (multiple-parent bones) the vertices all seem to be
// assigned to the first parent bone. We don't want to move faces about in such
// cases so only move faces between bones within the same branch.
if (bone.GetBranch().Contains(newBone))
{
ModelBase.PolyListDef tmp = new ModelBase.PolyListDef(polyList.m_ID, polyList.m_MaterialName);
tmp.m_FaceLists.Add(new ModelBase.FaceListDef());
newBone.m_Geometries[geometry.m_ID].m_PolyLists.Add(polyList.m_MaterialName, tmp);
if (!newBone.m_Geometries.ContainsKey(geometry.m_ID))
newBone.m_Geometries.Add(geometry.m_ID, new ModelBase.GeometryDef(geometry.m_ID));
if (!newBone.m_Geometries[geometry.m_ID].m_PolyLists.ContainsKey(polyList.m_MaterialName))
{
ModelBase.PolyListDef tmp = new ModelBase.PolyListDef(polyList.m_ID, polyList.m_MaterialName);
tmp.m_FaceLists.Add(new ModelBase.FaceListDef());
newBone.m_Geometries[geometry.m_ID].m_PolyLists.Add(polyList.m_MaterialName, tmp);
}
if (!newBone.m_MaterialsInBranch.Contains(polyList.m_MaterialName))
newBone.m_MaterialsInBranch.Add(polyList.m_MaterialName);

newBone.m_Geometries[geometry.m_ID].m_PolyLists[polyList.m_MaterialName].m_FaceLists[0].m_Faces.Add(face);
faceList.m_Faces.RemoveAt(f);
}
if (!newBone.m_MaterialsInBranch.Contains(polyList.m_MaterialName))
newBone.m_MaterialsInBranch.Add(polyList.m_MaterialName);

newBone.m_Geometries[geometry.m_ID].m_PolyLists[polyList.m_MaterialName].m_FaceLists[0].m_Faces.Add(face);
faceList.m_Faces.RemoveAt(f);
}

f++;
Expand Down
64 changes: 64 additions & 0 deletions ImportExport/Writers/InternalWriters/BMDWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,70 @@ public override void WriteModel(bool save = true)
GXDisplayListPacker dlpacker = new GXDisplayListPacker();

ModelBase.BoneDefRoot boneTree = m_Model.m_BoneTree;

// Materials cannot be shared across root-level bones; iterate through each
// pair or root-level bones and duplicate any materials that they share, assigning
// the original to one bone and the duplicate to the other e.g.:
// - r0 has materials matA, matB and matC
// - r1 has materials matC and matD
// - duplicate matC into matC_1
// - assign matB to r0 polylists and matB_1 to r1 polylists so that:
// - r0 has materials matA, matB and matC
// - r1 has materials matC_1 and matD
List<ModelBase.BoneDef> rootBones = boneTree.GetRootBones();
for (int i = 0; i < rootBones.Count; i++)
{
for (int j = i + 1; j < rootBones.Count; j++)
{
ModelBase.BoneDef rootA = rootBones[i];
ModelBase.BoneDef rootB = rootBones[j];

foreach (string materialID in rootA.m_MaterialsInBranch)
{
if (rootB.m_MaterialsInBranch.Contains(materialID))
{
string duplicateMaterialID;
int counter = 1;

do
{
duplicateMaterialID = materialID + '_' + counter++;
}
while (m_Model.m_Materials.ContainsKey(duplicateMaterialID) && counter < 100);

if (counter >= 100)
{
duplicateMaterialID = materialID + '_' + System.Guid.NewGuid().ToString();
}

ModelBase.MaterialDef duplicateMaterial =
new ModelBase.MaterialDef(duplicateMaterialID, m_Model.m_Materials[materialID]);

m_Model.m_Materials.Add(duplicateMaterialID, duplicateMaterial);

foreach (ModelBase.BoneDef bone in rootB.GetBranch())
{
foreach (ModelBase.GeometryDef geometry in bone.m_Geometries.Values)
{
foreach (ModelBase.PolyListDef polyList in geometry.m_PolyLists.Values)
{
polyList.m_MaterialName = duplicateMaterialID;
}
}
}

rootB.m_MaterialsInBranch.Remove(materialID);
rootB.m_MaterialsInBranch.Add(duplicateMaterialID);

string msg = String.Format("Found duplicate material [{0}] between bones " +
"[{1}] and [{2}], replacing with material [{3}] in [{2}]",
materialID, rootA.m_ID, rootB.m_ID, duplicateMaterialID);
Console.WriteLine(msg);
}
}
}
}

List<ModelBase.MaterialDef> materialsInFixedOrder = m_Model.m_Materials.Values.ToList();
Dictionary<string, int> materialFixedIndicesByID = new Dictionary<string, int>();
foreach (ModelBase.MaterialDef material in materialsInFixedOrder)
Expand Down
14 changes: 10 additions & 4 deletions Level.cs
Original file line number Diff line number Diff line change
Expand Up @@ -617,15 +617,21 @@ private void SaveMiscObjs(BinaryWriter binWriter)
SaveObjList(binWriter, m_LevelObjects.Values, k_MiscLevelObjTypeOrder);
}

public int CalculateNumberOfAreas()
{
int numAreas = m_LevelObjects.Max(x => x.Value.m_Area);
numAreas = Math.Max(numAreas, m_LevelObjects.Values.Where(x => x is EntranceObject)
.Select(x => x.Parameters[3] & 7).Max() + 1); //include entrance areas
numAreas = Math.Max(numAreas, m_TexAnims.FindLastIndex(x => x.m_Defs.Count != 0) + 1);
return numAreas;
}

private void SaveRegularObjs(BinaryWriter binWriter, out uint areaTableOffset)
{
List<List<LevelObject>> objsByArea = new List<List<LevelObject>>();
for (int i = 0; i < 8; ++i)
objsByArea.Add(m_LevelObjects.Values.Where(x => x.m_Area == i).ToList());
m_NumAreas = objsByArea.FindLastIndex(x => x.Count != 0) + 1;
m_NumAreas = Math.Max(m_NumAreas, m_LevelObjects.Values.Where(x => x is EntranceObject)
.Select(x => x.Parameters[3] & 7).Max() + 1); //include entrance areas
m_NumAreas = Math.Max(m_NumAreas, m_TexAnims.FindLastIndex(x => x.m_Defs.Count != 0) + 1);
m_NumAreas = Math.Max(m_NumAreas, CalculateNumberOfAreas());

if (m_NumAreas > k_MaxNumAreas)
throw new InvalidDataException("The game can support only " + k_MaxNumAreas + " areas. You have " + m_NumAreas + ".");
Expand Down
2 changes: 1 addition & 1 deletion LevelEditorForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1555,7 +1555,7 @@ private void tvObjectList_DrawNode(object sender, DrawTreeNodeEventArgs e)

private void btnLevelSettings_Click(object sender, EventArgs e)
{
new LevelSettingsForm(m_Level.m_LevelSettings).ShowDialog(this);
new LevelSettingsForm(m_Level).ShowDialog(this);
m_Level.DetermineAvailableObjects();
tvObjectList.Refresh();
}
Expand Down
Loading

0 comments on commit dbcc232

Please sign in to comment.