2024-07-21 21:13:31 +00:00
using Godot ;
2024-08-24 16:10:08 +00:00
using KeepersCompound.LGS ;
2024-07-21 21:13:31 +00:00
using KeepersCompound.LGS.Database ;
using KeepersCompound.LGS.Database.Chunks ;
2024-08-03 09:24:45 +00:00
using KeepersCompound.TMV.UI ;
2024-07-30 20:50:34 +00:00
using RectpackSharp ;
2024-07-21 21:13:31 +00:00
using System ;
using System.Collections.Generic ;
2024-08-24 12:37:21 +00:00
using System.IO ;
2024-07-21 21:13:31 +00:00
2024-08-11 08:18:02 +00:00
namespace KeepersCompound.TMV ;
2024-07-21 21:13:31 +00:00
public partial class Mission : Node3D
{
2024-08-11 11:28:24 +00:00
private readonly struct LightmapRectData
{
public readonly int cellIndex ;
public readonly int lightmapIndex ;
public readonly int textureId ;
public readonly int uvStart ;
public readonly int uvEnd ;
public LightmapRectData ( int cellIndex , int lightmapIndex , int textureId , int uvStart , int uvEnd )
{
this . cellIndex = cellIndex ;
this . lightmapIndex = lightmapIndex ;
this . textureId = textureId ;
this . uvStart = uvStart ;
this . uvEnd = uvEnd ;
}
}
2024-07-21 21:13:31 +00:00
[Export(PropertyHint.GlobalFile, "*.mis")]
public string FileName { get ; set ; }
[Export]
public bool Build = false ;
2024-07-22 18:37:27 +00:00
[Export]
public bool Clear = false ;
2024-08-03 15:09:51 +00:00
[Export]
public bool Dump = false ;
2024-07-21 21:13:31 +00:00
2024-08-25 09:08:48 +00:00
string _campaignName ;
string _missionName ;
2024-08-24 16:10:08 +00:00
ResourcePathManager _installPaths ;
2024-07-21 21:13:31 +00:00
DbFile _file ;
2024-08-11 14:23:56 +00:00
TextureLoader _textureLoader ;
2024-08-26 11:38:13 +00:00
ModelLoader _modelLoader ;
2024-07-21 21:13:31 +00:00
public override void _Ready ( )
{
2024-08-24 16:10:08 +00:00
var extractPath = ProjectSettings . GlobalizePath ( $"user://extracted/tmp" ) ;
_installPaths = new ResourcePathManager ( extractPath ) ;
2024-08-26 11:38:13 +00:00
_modelLoader = new ModelLoader ( _installPaths ) ;
2024-08-03 09:24:45 +00:00
var missionSelector = GetNode < Control > ( "%MissionSelector" ) as MissionSelector ;
2024-08-25 08:15:42 +00:00
missionSelector . pathManager = _installPaths ;
2024-08-25 09:01:43 +00:00
missionSelector . MissionSelected + = ( string campaign , string mission ) = >
2024-08-03 09:24:45 +00:00
{
2024-08-25 09:08:48 +00:00
_campaignName = campaign ;
_missionName = mission ;
2024-08-25 09:03:52 +00:00
FileName = _installPaths . GetMissionPath ( campaign , mission ) ;
2024-08-03 09:24:45 +00:00
Build = true ;
} ;
2024-07-21 21:13:31 +00:00
}
public override void _Process ( double delta )
{
if ( Build )
{
2024-08-26 14:24:07 +00:00
Timing . TimeStage ( "Build" , ( ) = > RebuildMap ( ) ) ;
2024-07-21 21:13:31 +00:00
Build = false ;
}
2024-07-22 18:37:27 +00:00
if ( Clear )
{
ClearMap ( ) ;
Clear = false ;
}
2024-07-21 21:13:31 +00:00
}
public override void _Input ( InputEvent @event )
{
if ( @event is InputEventKey keyEvent & & keyEvent . Pressed )
{
if ( keyEvent . Keycode = = Key . R )
{
Build = true ;
}
}
}
2024-07-22 18:37:27 +00:00
public void ClearMap ( )
2024-07-21 21:13:31 +00:00
{
foreach ( var node in GetChildren ( ) )
{
node . QueueFree ( ) ;
}
2024-07-22 18:37:27 +00:00
}
public void RebuildMap ( )
{
ClearMap ( ) ;
2024-07-21 21:13:31 +00:00
2024-08-25 09:08:48 +00:00
_textureLoader = new TextureLoader ( _campaignName ) ;
2024-08-26 12:25:06 +00:00
Timing . TimeStage ( "DbFile Parse" , ( ) = > _file = new ( FileName ) ) ;
Timing . TimeStage ( "Load FAM" , ( ) = > UseChunk < TxList > ( "TXLIST" , LoadTextures ) ) ;
Timing . TimeStage ( "Build WR" , ( ) = > UseChunk < WorldRep > ( "WREXT" , BuildWrMeshes ) ) ;
2024-08-25 14:49:40 +00:00
2024-08-26 14:10:05 +00:00
if ( _file . Chunks . TryGetValue ( "BRLIST" , out var brList ) )
{
2024-08-26 14:24:07 +00:00
var objHierarchy = Timing . TimeStage ( "Hierarchy" , BuildHierarchy ) ;
2024-08-26 14:10:05 +00:00
Timing . TimeStage ( "Object Placement" , ( ) = > PlaceObjects ( ( BrList ) brList , objHierarchy ) ) ;
}
}
// TODO: Make this less of a mess
2024-08-26 14:24:07 +00:00
private ObjectHierarchy BuildHierarchy ( )
2024-08-26 14:10:05 +00:00
{
2024-08-25 14:49:40 +00:00
ObjectHierarchy objHierarchy ;
if ( _file . Chunks . TryGetValue ( "GAM_FILE" , out var gamFileChunk ) )
2024-08-24 10:33:55 +00:00
{
2024-08-24 12:37:21 +00:00
2024-08-25 14:49:40 +00:00
var options = new EnumerationOptions { MatchCasing = MatchCasing . CaseInsensitive } ;
var name = ( ( GamFile ) gamFileChunk ) . fileName ;
var paths = Directory . GetFiles ( FileName . GetBaseDir ( ) , name , options ) ;
if ( ! paths . IsEmpty ( ) )
2024-08-24 12:37:21 +00:00
{
2024-08-25 14:49:40 +00:00
objHierarchy = new ObjectHierarchy ( _file , new DbFile ( paths [ 0 ] ) ) ;
}
else
{
objHierarchy = new ObjectHierarchy ( _file ) ;
2024-08-24 12:37:21 +00:00
}
2024-08-25 14:49:40 +00:00
}
else
{
objHierarchy = new ObjectHierarchy ( _file ) ;
}
2024-08-26 14:10:05 +00:00
return objHierarchy ;
2024-08-14 17:39:13 +00:00
}
2024-08-03 15:09:51 +00:00
2024-08-14 17:39:13 +00:00
private void UseChunk < T > ( string name , Action < T > action )
{
if ( _file . Chunks . TryGetValue ( name , out var value ) )
{
action ( ( T ) value ) ;
}
else
{
GD . Print ( $"No chunk found/loaded: {name}" ) ;
}
2024-07-21 21:13:31 +00:00
}
2024-08-25 14:49:40 +00:00
private void PlaceObjects ( BrList brList , ObjectHierarchy objHierarchy )
2024-08-23 17:55:39 +00:00
{
foreach ( var brush in brList . Brushes )
{
if ( brush . media ! = BrList . Brush . Media . Object )
{
continue ;
}
2024-08-24 10:33:55 +00:00
var id = ( int ) brush . brushInfo ;
2024-08-25 14:49:40 +00:00
var modelNameProp = objHierarchy . GetProperty < PropModelName > ( id , "P$ModelName" ) ;
var scaleProp = objHierarchy . GetProperty < PropScale > ( id , "P$Scale" ) ;
var renderTypeProp = objHierarchy . GetProperty < PropRenderType > ( id , "P$RenderTyp" ) ;
var renderMode = renderTypeProp = = null ? PropRenderType . Mode . Normal : renderTypeProp . mode ;
2024-08-25 10:54:33 +00:00
2024-08-25 14:49:40 +00:00
if ( modelNameProp = = null | | renderMode = = PropRenderType . Mode . NotRendered )
2024-08-24 10:33:55 +00:00
{
continue ;
}
2024-08-24 16:36:32 +00:00
// Let's try and place an object :)
2024-08-25 14:49:40 +00:00
var modelName = modelNameProp . modelName + ".bin" ;
2024-08-23 17:55:39 +00:00
var pos = brush . position . ToGodotVec3 ( ) ;
2024-08-25 10:21:00 +00:00
var rawRot = brush . angle ;
var rot = new Vector3 ( rawRot . Y , rawRot . Z , rawRot . X ) * 360 / ushort . MaxValue ;
2024-08-25 14:49:40 +00:00
var scale = scaleProp = = null ? Vector3 . One : scaleProp . scale . ToGodotVec3 ( false ) ;
2024-08-26 11:38:13 +00:00
var model = _modelLoader . Load ( _campaignName , modelName ) ;
2024-08-25 15:47:05 +00:00
if ( model ! = null )
2024-08-23 17:55:39 +00:00
{
2024-08-25 15:47:05 +00:00
model . Position = pos ;
model . RotationDegrees = rot ;
model . Scale = scale ;
AddChild ( model ) ;
2024-08-24 16:36:32 +00:00
}
2024-08-23 17:55:39 +00:00
}
}
2024-08-14 17:39:13 +00:00
private void BuildWrMeshes ( WorldRep worldRep )
2024-07-21 21:13:31 +00:00
{
2024-08-14 17:39:13 +00:00
var cells = worldRep . Cells ;
var lmHdr = worldRep . DataHeader . LightmapFormat = = 2 ;
GD . Print ( $"HDR Lightmap: {lmHdr}" ) ;
2024-08-13 20:38:00 +00:00
2024-08-11 11:28:24 +00:00
var packingRects = new List < PackingRectangle > ( ) ;
var surfaceDataMap = new Dictionary < int , MeshSurfaceData > ( ) ;
var rectDataMap = new Dictionary < int , LightmapRectData > ( ) ;
2024-07-21 21:13:31 +00:00
2024-08-11 11:28:24 +00:00
for ( var cellIdx = 0 ; cellIdx < cells . Length ; cellIdx + + )
2024-07-22 18:37:27 +00:00
{
2024-08-11 11:28:24 +00:00
var cell = cells [ cellIdx ] ;
var numPolys = cell . PolyCount ;
var numRenderPolys = cell . RenderPolyCount ;
var numPortalPolys = cell . PortalPolyCount ;
// There's nothing to render
if ( numRenderPolys = = 0 | | numPortalPolys > = numPolys )
{
continue ;
}
// You'd think these would be the same number, but apparently not
// I think it's because water counts as a render poly and a portal poly
var maxPolyIdx = Math . Min ( numRenderPolys , numPolys - numPortalPolys ) ;
var cellIdxOffset = 0 ;
for ( int polyIdx = 0 ; polyIdx < maxPolyIdx ; polyIdx + + )
{
2024-08-26 15:53:01 +00:00
var lightmapRectData = ProcessCellSurfaceData ( surfaceDataMap , worldRep , cellIdx , polyIdx , cellIdxOffset ) ;
2024-08-11 11:28:24 +00:00
rectDataMap . Add ( packingRects . Count , lightmapRectData ) ;
2024-07-22 18:37:27 +00:00
2024-08-11 11:28:24 +00:00
var light = cell . LightList [ polyIdx ] ;
var rect = new PackingRectangle ( 0 , 0 , light . Width , light . Height , packingRects . Count ) ;
packingRects . Add ( rect ) ;
2024-08-03 16:22:38 +00:00
2024-08-11 11:28:24 +00:00
cellIdxOffset + = cell . Polys [ polyIdx ] . VertexCount ;
}
}
2024-08-05 18:25:44 +00:00
2024-08-26 13:03:50 +00:00
var lightmapTexture = Timing . TimeStage ( "Build Lightmap" , ( ) = >
{
return BuildLightmapTexture ( cells , packingRects . ToArray ( ) , rectDataMap , surfaceDataMap ) ;
} ) ;
2024-08-11 14:43:44 +00:00
foreach ( var ( textureId , surface ) in surfaceDataMap )
2024-08-03 16:24:04 +00:00
{
2024-08-11 11:28:24 +00:00
if ( surface . Empty )
2024-08-05 18:25:44 +00:00
{
2024-08-11 11:28:24 +00:00
continue ;
2024-08-05 18:25:44 +00:00
}
2024-08-11 14:43:44 +00:00
var albedoTexture = _textureLoader . Get ( textureId ) ;
2024-08-11 11:28:24 +00:00
var mesh = new ArrayMesh ( ) ;
2024-08-11 14:43:44 +00:00
mesh . AddSurfaceFromArrays ( Mesh . PrimitiveType . Triangles , surface . BuildSurfaceArray ( ) ) ;
2024-08-13 20:38:00 +00:00
mesh . SurfaceSetMaterial ( 0 , BuildMaterial ( albedoTexture , lightmapTexture , lmHdr ) ) ;
2024-08-11 11:28:24 +00:00
var meshInstance = new MeshInstance3D { Mesh = mesh } ;
AddChild ( meshInstance ) ;
}
}
2024-08-26 15:53:01 +00:00
private LightmapRectData ProcessCellSurfaceData ( Dictionary < int , MeshSurfaceData > surfaceDataMap , WorldRep worldRep , int cellIdx , int polyIdx , int indicesOffset )
2024-08-11 11:28:24 +00:00
{
2024-08-26 15:53:01 +00:00
var cell = worldRep . Cells [ cellIdx ] ;
2024-08-11 11:28:24 +00:00
var poly = cell . Polys [ polyIdx ] ;
var normal = cell . Planes [ poly . PlaneId ] . Normal . ToGodotVec3 ( ) ;
var vertices = new List < Vector3 > ( ) ;
var textureUvs = new List < Vector2 > ( ) ;
var lightmapUvs = new List < Vector2 > ( ) ;
var numPolyVertices = poly . VertexCount ;
for ( var j = 0 ; j < numPolyVertices ; j + + )
{
var vertex = cell . Vertices [ cell . Indices [ indicesOffset + j ] ] ;
vertices . Add ( vertex . ToGodotVec3 ( ) ) ;
2024-08-05 18:25:44 +00:00
}
2024-08-03 16:24:04 +00:00
2024-08-11 11:28:24 +00:00
var renderPoly = cell . RenderPolys [ polyIdx ] ;
var light = cell . LightList [ polyIdx ] ;
2024-08-26 15:53:01 +00:00
var lightmapScale = worldRep . DataHeader . LightmapScale ;
var textureId = CalcBaseUV ( cell , poly , renderPoly , light , textureUvs , lightmapUvs , lightmapScale , indicesOffset ) ;
2024-08-11 11:28:24 +00:00
if ( ! surfaceDataMap . ContainsKey ( textureId ) )
{
2024-08-11 14:43:44 +00:00
surfaceDataMap . Add ( textureId , new MeshSurfaceData ( ) ) ;
2024-08-11 11:28:24 +00:00
}
var surfaceData = surfaceDataMap [ textureId ] ;
var ( start , end ) = surfaceData . AddPolygon ( vertices , normal , textureUvs , lightmapUvs ) ;
2024-08-03 16:24:04 +00:00
2024-08-11 11:28:24 +00:00
if ( polyIdx > = cell . Lightmaps . Length ) GD . Print ( "HUH" ) ;
2024-08-03 16:24:04 +00:00
2024-08-11 11:28:24 +00:00
return new LightmapRectData ( cellIdx , polyIdx , textureId , start , end ) ;
2024-08-03 16:24:04 +00:00
}
2024-08-11 11:28:24 +00:00
private static Texture BuildLightmapTexture ( WorldRep . Cell [ ] cells , PackingRectangle [ ] packingRects , Dictionary < int , LightmapRectData > rectDataMap , Dictionary < int , MeshSurfaceData > surfaceDataMap )
2024-08-03 16:24:04 +00:00
{
2024-08-26 13:26:45 +00:00
var bounds = Timing . TimeStage ( "RectPack" , ( ) = >
{
2024-08-26 13:30:40 +00:00
RectanglePacker . Pack ( packingRects , out var bounds , PackingHints . FindBest , 0 ) ;
2024-08-26 13:26:45 +00:00
return bounds ;
} ) ;
GD . Print ( $"Creating lightmap with bounds: ({bounds.Width}, {bounds.Height})" ) ;
2024-08-26 11:40:51 +00:00
var image = Image . CreateEmpty ( ( int ) bounds . Width , ( int ) bounds . Height , false , Image . Format . Rgba8 ) ;
2024-07-30 20:50:34 +00:00
foreach ( var rect in packingRects )
{
2024-08-11 11:28:24 +00:00
if ( ! rectDataMap . ContainsKey ( rect . Id ) ) GD . Print ( "Invalid rectDataMap key" ) ;
var info = rectDataMap [ rect . Id ] ;
if ( info . cellIndex > = cells . Length ) GD . Print ( $"CellIndex too big: {info.cellIndex}/{cells.Length}" ) ;
if ( info . lightmapIndex > = cells [ info . cellIndex ] . Lightmaps . Length ) GD . Print ( $"LightmapIndex too big: {info.lightmapIndex}/{cells[info.cellIndex].Lightmaps.Length}" ) ;
var lightmap = cells [ info . cellIndex ] . Lightmaps [ info . lightmapIndex ] ;
2024-08-27 06:46:44 +00:00
var cellLm = Image . CreateFromData ( lightmap . Width , lightmap . Height , false , Image . Format . Rgba8 , lightmap . AsBytesRgba ( ) ) ;
image . BlitRect ( cellLm , new Rect2I ( 0 , 0 , lightmap . Width , lightmap . Height ) , new Vector2I ( ( int ) rect . X , ( int ) rect . Y ) ) ;
2024-07-30 20:50:34 +00:00
2024-08-11 11:28:24 +00:00
if ( ! surfaceDataMap . ContainsKey ( info . textureId ) ) GD . Print ( "Invalid SurfaceDataMap key" ) ;
2024-08-18 10:13:18 +00:00
surfaceDataMap [ info . textureId ] . TransformUv2s ( info . uvStart , info . uvEnd , ( uv ) = >
2024-07-30 20:50:34 +00:00
{
var u = uv . X ;
var v = uv . Y ;
// Clamp uv range to [0..1]
u % = 1 ;
v % = 1 ;
if ( u < 0 ) u = Math . Abs ( u ) ;
if ( v < 0 ) v = Math . Abs ( v ) ;
// Transform!
u = ( rect . X + rect . Width * u ) / ( int ) bounds . Width ;
v = ( rect . Y + rect . Height * v ) / ( int ) bounds . Height ;
2024-08-11 11:28:24 +00:00
return new Vector2 ( u , v ) ;
} ) ;
2024-08-05 17:46:57 +00:00
}
2024-07-22 19:34:12 +00:00
2024-08-11 11:28:24 +00:00
return ImageTexture . CreateFromImage ( image ) ;
2024-07-21 21:13:31 +00:00
}
2024-07-30 20:50:34 +00:00
2024-08-11 11:28:24 +00:00
private int CalcBaseUV (
2024-07-30 20:50:34 +00:00
WorldRep . Cell cell ,
WorldRep . Cell . Poly poly ,
WorldRep . Cell . RenderPoly renderPoly ,
WorldRep . Cell . LightmapInfo light ,
2024-08-05 18:49:36 +00:00
List < Vector2 > textureUvs ,
2024-07-30 20:50:34 +00:00
List < Vector2 > lightmapUvs ,
2024-08-26 15:53:01 +00:00
float lightmapScale ,
2024-07-30 20:50:34 +00:00
int cellIdxOffset )
{
// TODO: This is slightly hardcoded for ND. Check other stuff at some point. Should be handled in LG side imo
// TODO: This is a mess lol
2024-08-05 18:49:36 +00:00
var textureId = renderPoly . TextureId ;
2024-08-11 14:23:56 +00:00
var texture = _textureLoader . Get ( textureId ) ;
2024-08-01 17:29:10 +00:00
var texU = renderPoly . TextureVectors . Item1 . ToGodotVec3 ( ) ;
var texV = renderPoly . TextureVectors . Item2 . ToGodotVec3 ( ) ;
2024-08-05 18:49:36 +00:00
var baseU = renderPoly . TextureBases . Item1 ;
var baseV = renderPoly . TextureBases . Item2 ;
2024-07-30 20:50:34 +00:00
2024-08-26 15:53:01 +00:00
var txUScale = 64.0f / lightmapScale / texture . GetWidth ( ) ;
var txVScale = 64.0f / lightmapScale / texture . GetHeight ( ) ;
2024-07-30 20:50:34 +00:00
var lmUScale = 4.0f / light . Width ;
var lmVScale = 4.0f / light . Height ;
2024-08-05 18:49:36 +00:00
var txUBase = baseU * txUScale ;
var txVBase = baseV * txVScale ;
2024-07-30 20:50:34 +00:00
var lmUBase = lmUScale * ( baseU + ( 0.5f - light . Bases . Item1 ) / 4.0f ) ;
var lmVBase = lmVScale * ( baseV + ( 0.5f - light . Bases . Item2 ) / 4.0f ) ;
2024-08-05 18:49:36 +00:00
var uu = texU . Dot ( texU ) ;
var vv = texV . Dot ( texV ) ;
var uv = texU . Dot ( texV ) ;
var anchor = cell . Vertices [ cell . Indices [ cellIdxOffset + 0 ] ] . ToGodotVec3 ( ) ; // TODO: This probably shouldn't be hardcoded idx 0
2024-07-30 20:50:34 +00:00
if ( uv = = 0.0 )
{
2024-08-05 18:49:36 +00:00
var txUVec = texU * txUScale / uu ;
var txVVec = texV * txVScale / vv ;
2024-07-30 20:50:34 +00:00
var lmUVec = texU * lmUScale / uu ;
var lmVVec = texV * lmVScale / vv ;
for ( var i = 0 ; i < poly . VertexCount ; i + + )
{
2024-08-01 17:29:10 +00:00
var v = cell . Vertices [ cell . Indices [ cellIdxOffset + i ] ] . ToGodotVec3 ( ) ;
2024-07-30 20:50:34 +00:00
var delta = new Vector3 ( v . X - anchor . X , v . Y - anchor . Y , v . Z - anchor . Z ) ;
2024-08-05 18:49:36 +00:00
var txUV = new Vector2 ( delta . Dot ( txUVec ) + txUBase , delta . Dot ( txVVec ) + txVBase ) ;
2024-07-30 20:50:34 +00:00
var lmUV = new Vector2 ( delta . Dot ( lmUVec ) + lmUBase , delta . Dot ( lmVVec ) + lmVBase ) ;
2024-08-05 18:49:36 +00:00
textureUvs . Add ( txUV ) ;
2024-07-30 20:50:34 +00:00
lightmapUvs . Add ( lmUV ) ;
}
}
else
{
var denom = 1.0f / ( uu * vv - uv * uv ) ;
2024-08-05 18:49:36 +00:00
var txUu = uu * txVScale * denom ;
var txVv = vv * txUScale * denom ;
var txUvu = txUScale * denom * uv ;
var txUvv = txVScale * denom * uv ;
2024-07-30 20:50:34 +00:00
var lmUu = uu * lmVScale * denom ;
var lmVv = vv * lmUScale * denom ;
var lmUvu = lmUScale * denom * uv ;
var lmUvv = lmVScale * denom * uv ;
for ( var i = 0 ; i < poly . VertexCount ; i + + )
{
2024-08-01 17:29:10 +00:00
var v = cell . Vertices [ cell . Indices [ cellIdxOffset + i ] ] . ToGodotVec3 ( ) ;
2024-07-30 20:50:34 +00:00
var delta = new Vector3 ( v . X - anchor . X , v . Y - anchor . Y , v . Z - anchor . Z ) ;
var du = delta . Dot ( texU ) ;
var dv = delta . Dot ( texV ) ;
2024-08-05 18:49:36 +00:00
var txUV = new Vector2 ( txUBase + txVv * du - txUvu * dv , txVBase + txUu * dv - txUvv * du ) ;
2024-07-30 20:50:34 +00:00
var lmUV = new Vector2 ( lmUBase + lmVv * du - lmUvu * dv , lmVBase + lmUu * dv - lmUvv * du ) ;
2024-08-05 18:49:36 +00:00
textureUvs . Add ( txUV ) ;
2024-07-30 20:50:34 +00:00
lightmapUvs . Add ( lmUV ) ;
}
}
2024-08-11 11:28:24 +00:00
return textureId ;
2024-07-30 20:50:34 +00:00
}
2024-08-03 15:09:51 +00:00
private void LoadTextures ( TxList textureList )
{
2024-08-07 17:40:46 +00:00
// TODO: Use PathJoin
2024-08-03 15:09:51 +00:00
var count = textureList . ItemCount ;
for ( var i = 0 ; i < count ; i + + )
{
var item = textureList . Items [ i ] ;
2024-08-24 16:10:08 +00:00
var path = "" ;
2024-08-03 15:09:51 +00:00
for ( var j = 0 ; j < item . Tokens . Length ; j + + )
{
var token = item . Tokens [ j ] ;
if ( token = = 0 )
{
break ;
}
path + = $"{textureList.Tokens[token - 1]}/" ;
}
2024-08-07 19:10:45 +00:00
path + = item . Name ;
2024-08-03 15:09:51 +00:00
2024-08-24 16:10:08 +00:00
if ( ! _textureLoader . Load ( _installPaths , i , path ) )
2024-08-03 15:09:51 +00:00
{
2024-08-11 14:23:56 +00:00
GD . Print ( $"Failed to load texture: {path}" ) ;
2024-08-03 15:09:51 +00:00
}
}
2024-08-14 17:39:13 +00:00
if ( Dump ) DumpTextureList ( textureList ) ;
2024-08-03 15:09:51 +00:00
}
private static void DumpTextureList ( TxList textureList )
{
GD . Print ( $"TXLIST:\n BlockSize: {textureList.BlockSize}\n ItemCount: {textureList.ItemCount}\n TokenCount: {textureList.TokenCount}\n Tokens:" ) ;
for ( var i = 0 ; i < textureList . TokenCount ; i + + )
{
GD . Print ( $" {i}: {textureList.Tokens[i]}" ) ;
}
GD . Print ( $" Items:" ) ;
for ( var i = 0 ; i < textureList . ItemCount ; i + + )
{
var item = textureList . Items [ i ] ;
GD . Print ( $" {i}:\n Tokens: [{item.Tokens[0]}, {item.Tokens[1]}, {item.Tokens[2]}, {item.Tokens[3]}]\n Name: {item.Name}" ) ;
}
}
2024-08-11 14:43:44 +00:00
const string MATERIAL_PATH = "res://project/materials/base.tres" ;
2024-08-13 20:38:00 +00:00
private static Material BuildMaterial ( Texture albedoTexture , Texture lightmapTexture , bool lmHdr )
2024-08-11 14:43:44 +00:00
{
var material = ResourceLoader . Load < ShaderMaterial > ( MATERIAL_PATH ) . Duplicate ( ) as ShaderMaterial ;
material . SetShaderParameter ( "texture_albedo" , albedoTexture ) ;
material . SetShaderParameter ( "lightmap_albedo" , lightmapTexture ) ;
2024-08-13 20:38:00 +00:00
material . SetShaderParameter ( "lightmap_2x" , lmHdr ) ;
2024-08-11 14:43:44 +00:00
return material ;
}
2024-07-21 21:13:31 +00:00
}