@ -1,12 +1,14 @@
using System ;
using System ;
using System.Collections.Generic ;
using System.Collections.Generic ;
using System.Runtime.InteropServices ;
using UnityEngine ;
using UnityEngine ;
using UnityEngine.Rendering ;
using UnityEngine.Rendering ;
public class BrushModel
public class BrushModel
{
{
private readonly string name ;
private readonly List < Mesh > meshes = new List < Mesh > ( ) ;
public string Name { get ; }
private readonly List < SubModel > subModels = new List < SubModel > ( ) ;
// Reusable temporary data containers
// Reusable temporary data containers
private readonly List < Vector3 > tempVertices = new List < Vector3 > ( ) ;
private readonly List < Vector3 > tempVertices = new List < Vector3 > ( ) ;
@ -14,53 +16,52 @@ public class BrushModel
private readonly List < Vector2 > tempLightmapUVs = new List < Vector2 > ( ) ;
private readonly List < Vector2 > tempLightmapUVs = new List < Vector2 > ( ) ;
private readonly List < ushort > tempIndices = new List < ushort > ( ) ;
private readonly List < ushort > tempIndices = new List < ushort > ( ) ;
private readonly GameObject rootGameObject ;
private readonly Material debugMaterial ;
public BrushModel ( string name )
public BrushModel ( string name )
{
{
this . name = name ;
Name = name ;
}
rootGameObject = new GameObject ( name ) ;
rootGameObject . transform . SetPositionAndRotation ( Vector3 . zero , Quaternion . identity ) ;
public int SubModelCount = > subModels . Count ;
debugMaterial = new Material ( Shader . Find ( "Universal Render Pipeline/Simple Lit" ) ) ;
public SubModel GetSubModel ( int index )
{
return subModels [ index ] ;
}
}
public void ImportMeshData ( QModel model )
public void ImportMeshData ( QModel model )
{
{
var s ubModels = model . SubModels ;
var s urfaces = model . Surfaces ;
var inS ubModels = model . SubModels ;
var inS urfaces = model . Surfaces ;
for ( int modelIdx = 0 ; modelIdx < s ubModels. Length ; + + modelIdx )
for ( int modelIdx = 0 ; modelIdx < inS ubModels. Length ; + + modelIdx )
{
{
var modelGO = new GameObject ( $"SubModel_{modelIdx}" ) ;
modelGO . transform . SetParent ( rootGameObject . transform ) ;
var headNode = subModels [ modelIdx ] . GetHeadNode ( model ) ;
var subModel = new SubModel ( ) ;
subModels . Add ( subModel ) ;
// Traverse the BSP tree and group the surfaces based on their material properties
var headNode = inSubModels [ modelIdx ] . GetHeadNode ( model ) ;
var surfaceGroups = new Dictionary < ( IntPtr , int ) , List < QSurface > > ( ) ;
var surfaceGroups = new Dictionary < ( IntPtr , int ) , List < QSurface > > ( ) ;
GroupSurfaces ( headNode , surfaces , surfaceGroups ) ;
GroupSurfaces ( headNode , inS urfaces, surfaceGroups ) ;
// Create a single mesh for each group of surfaces
foreach ( var group in surfaceGroups )
foreach ( var group in surfaceGroups )
{
{
var key = group . Key ;
var key = group . Key ;
var groupGO = new GameObject ( $"T{key.Item1}_L{key.Item2}" ) ;
groupGO . transform . SetParent ( modelGO . transform ) ;
var mesh = CreateMeshFromSurfaces ( group . Value , $"T{key.Item1}_L{key.Item2}" ) ;
CreateMeshFromSurfaces ( group . Value , groupGO . name , groupGO ) ;
subModel . AddSurfaceMesh ( new SurfaceMesh ( mesh , key . Item1 , key . Item2 ) ) ;
}
}
}
}
}
}
public void Dispose ( )
public void Dispose ( )
{
{
foreach ( var mesh in meshe s)
foreach ( var subModel in subModel s)
{
{
UnityEngine . Object . Destroy ( mesh ) ;
subModel . Dispose ( ) ;
}
}
meshe s. Clear ( ) ;
subModel s. Clear ( ) ;
}
}
private void GroupSurfaces ( QNode node , QSurface [ ] surfaces , Dictionary < ( IntPtr , int ) , List < QSurface > > surfaceGroups )
private void GroupSurfaces ( QNode node , QSurface [ ] surfaces , Dictionary < ( IntPtr , int ) , List < QSurface > > surfaceGroups )
@ -88,7 +89,7 @@ public class BrushModel
}
}
}
}
private void CreateMeshFromSurfaces ( List < QSurface > surfaces , string key , GameObject parentGO )
private Mesh CreateMeshFromSurfaces ( List < QSurface > surfaces , string key )
{
{
tempVertices . Clear ( ) ;
tempVertices . Clear ( ) ;
tempTextureUVs . Clear ( ) ;
tempTextureUVs . Clear ( ) ;
@ -128,21 +129,43 @@ public class BrushModel
mesh . SetIndices ( tempIndices , MeshTopology . Triangles , 0 ) ;
mesh . SetIndices ( tempIndices , MeshTopology . Triangles , 0 ) ;
mesh . RecalculateNormals ( ) ;
mesh . RecalculateNormals ( ) ;
mesh . UploadMeshData ( true ) ;
mesh . UploadMeshData ( true ) ;
meshes . Add ( mesh ) ;
return mesh ;
}
public class SubModel
{
public List < SurfaceMesh > SurfaceMeshes { get ; } = new List < SurfaceMesh > ( ) ;
public void AddSurfaceMesh ( SurfaceMesh surfaceMesh )
{
SurfaceMeshes . Add ( surfaceMesh ) ;
}
CreateMeshObject ( mesh , parentGO ) ;
public void Dispose ( )
{
foreach ( var surfaceMesh in SurfaceMeshes )
{
surfaceMesh . Dispose ( ) ;
}
}
}
}
private void CreateMeshObject ( Mesh mesh , GameObject parentGO )
public class SurfaceMesh
{
{
var mf = parentGO . AddComponent < MeshFilter > ( ) ;
mf . sharedMesh = mesh ;
public Mesh Mesh { get ; }
public QTexture Texture { get ; }
public int Lightmap { get ; }
var mr = parentGO . AddComponent < MeshRenderer > ( ) ;
mr . sharedMaterial = debugMaterial ;
mr . shadowCastingMode = ShadowCastingMode . Off ;
mr . receiveShadows = false ;
mr . lightProbeUsage = LightProbeUsage . Off ;
mr . reflectionProbeUsage = ReflectionProbeUsage . Off ;
public SurfaceMesh ( Mesh mesh , IntPtr texturePtr , int lightmap )
{
Mesh = mesh ;
Texture = Marshal . PtrToStructure < QTexture > ( texturePtr ) ;
Lightmap = lightmap ;
}
public void Dispose ( )
{
UnityEngine . Object . Destroy ( Mesh ) ;
}
}
}
}
}