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-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-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 )
{
RebuildMap ( ) ;
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-24 16:36:32 +00:00
// TODO: This shouldn't be set for things that aren't actually FMs
2024-08-25 09:08:48 +00:00
_textureLoader = new TextureLoader ( _campaignName ) ;
2024-07-21 21:13:31 +00:00
_file = new ( FileName ) ;
2024-08-14 17:39:13 +00:00
UseChunk < TxList > ( "TXLIST" , LoadTextures ) ;
UseChunk < WorldRep > ( "WREXT" , BuildWrMeshes ) ;
2024-08-24 10:33:55 +00:00
if (
2024-08-24 12:37:21 +00:00
_file . Chunks . TryGetValue ( "BRLIST" , out var brListRaw ) & &
_file . Chunks . TryGetValue ( "P$ModelName" , out var modelNamesRaw ) & &
2024-08-25 10:54:33 +00:00
_file . Chunks . TryGetValue ( "P$Scale" , out var scalesRaw ) & &
2024-08-24 12:37:21 +00:00
_file . Chunks . TryGetValue ( "L$MetaProp" , out var metaPropLinksRaw ) & &
_file . Chunks . TryGetValue ( "LD$MetaProp" , out var metaPropLinkDataRaw )
2024-08-24 10:33:55 +00:00
)
{
2024-08-24 12:37:21 +00:00
var brList = ( BrList ) brListRaw ;
2024-08-25 12:07:49 +00:00
var modelNames = ( PropertyChunk < PropModelName > ) modelNamesRaw ;
var scales = ( PropertyChunk < PropScale > ) scalesRaw ;
2024-08-24 12:37:21 +00:00
var metaPropLinks = ( LinkChunk ) metaPropLinksRaw ;
var metaPropLinkData = ( LinkDataMetaProp ) metaPropLinkDataRaw ;
// TODO: Do this somewhere else lol
if ( _file . Chunks . TryGetValue ( "GAM_FILE" , out var gamFileChunk ) )
{
GD . Print ( "GAM_FILE detected" ) ;
var options = new EnumerationOptions { MatchCasing = MatchCasing . CaseInsensitive } ;
var name = ( ( GamFile ) gamFileChunk ) . fileName ;
GD . Print ( $"Searching for GAM: {FileName.GetBaseDir()}/{name}" ) ;
var paths = Directory . GetFiles ( FileName . GetBaseDir ( ) , name , options ) ;
GD . Print ( $"Found paths: {paths.Length}" ) ;
if ( ! paths . IsEmpty ( ) )
{
GD . Print ( $"Attempting to load GAM at: {paths[0]}" ) ;
var gamFile = new DbFile ( paths [ 0 ] ) ;
if ( gamFile . Chunks . TryGetValue ( "P$ModelName" , out var gamChunk1 ) & &
gamFile . Chunks . TryGetValue ( "L$MetaProp" , out var gamChunk2 ) & &
2024-08-25 10:54:33 +00:00
gamFile . Chunks . TryGetValue ( "LD$MetaProp" , out var gamChunk3 ) & &
gamFile . Chunks . TryGetValue ( "P$Scale" , out var gamChunk4 ) )
2024-08-24 12:37:21 +00:00
{
GD . Print ( $"Pre-Merged chunks: {modelNames.properties.Count} {metaPropLinks.links.Count} {metaPropLinkData.linkData.Count}" ) ;
2024-08-25 12:07:49 +00:00
modelNames . properties . AddRange ( ( ( PropertyChunk < PropModelName > ) gamChunk1 ) . properties ) ;
2024-08-24 12:37:21 +00:00
metaPropLinks . links . AddRange ( ( ( LinkChunk ) gamChunk2 ) . links ) ;
metaPropLinkData . linkData . AddRange ( ( ( LinkDataMetaProp ) gamChunk3 ) . linkData ) ;
2024-08-25 12:07:49 +00:00
scales . properties . AddRange ( ( ( PropertyChunk < PropScale > ) gamChunk4 ) . properties ) ;
2024-08-24 12:37:21 +00:00
GD . Print ( $"Post-Merged chunks: {modelNames.properties.Count} {metaPropLinks.links.Count} {metaPropLinkData.linkData.Count}" ) ;
}
}
}
2024-08-25 10:54:33 +00:00
PlaceObjects ( brList , modelNames , scales , metaPropLinks , metaPropLinkData ) ;
2024-08-24 10:33:55 +00:00
}
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-24 10:33:55 +00:00
private void PlaceObjects (
BrList brList ,
2024-08-25 12:07:49 +00:00
PropertyChunk < PropModelName > modelNames ,
PropertyChunk < PropScale > scales ,
2024-08-24 10:33:55 +00:00
LinkChunk metapropLink ,
LinkDataMetaProp metaPropLinkData )
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
// TODO: Build an actual hierarchy and such :)
// TODO: We need to load the gamesys :)
// Determine if we have a model name :))
var id = ( int ) brush . brushInfo ;
var modelName = "" ;
2024-08-25 10:54:33 +00:00
var scale = Vector3 . One ;
var scaleFound = false ;
2024-08-24 10:33:55 +00:00
while ( true )
{
// See if there's a modelname property
2024-08-25 10:54:33 +00:00
if ( modelName = = "" )
2024-08-24 10:33:55 +00:00
{
2024-08-25 10:54:33 +00:00
foreach ( var prop in modelNames . properties )
2024-08-24 10:33:55 +00:00
{
2024-08-25 10:54:33 +00:00
if ( prop . objectId = = id )
{
modelName = prop . modelName ;
break ;
}
}
}
if ( ! scaleFound )
{
foreach ( var prop in scales . properties )
{
if ( prop . objectId = = id )
{
scale = prop . scale . ToGodotVec3 ( false ) ;
scaleFound = true ;
break ;
}
2024-08-24 10:33:55 +00:00
}
}
2024-08-25 10:54:33 +00:00
if ( modelName ! = "" & & scaleFound )
{
break ;
}
// Check for a parent
2024-08-24 10:33:55 +00:00
var length = metapropLink . links . Count ;
var prevId = id ;
for ( var i = 0 ; i < length ; i + + )
{
var link = metapropLink . links [ i ] ;
var linkData = metaPropLinkData . linkData [ i ] ;
if ( link . source = = id & & linkData . priority = = 0 )
{
id = link . destination ;
break ;
}
}
// No parent found
if ( id = = prevId )
{
break ;
}
}
if ( modelName = = "" )
{
continue ;
}
2024-08-24 16:36:32 +00:00
// Let's try and place an object :)
var fmName = FileName . GetBaseDir ( ) . GetFile ( ) ;
var objPath = _installPaths . GetObjectPath ( fmName , modelName + ".bin" ) ;
objPath ? ? = _installPaths . GetObjectPath ( 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 ;
var model = new Model
{
Position = pos ,
2024-08-25 10:54:33 +00:00
RotationDegrees = rot ,
Scale = scale ,
2024-08-25 10:21:00 +00:00
} ;
2024-08-24 16:36:32 +00:00
if ( objPath ! = null )
2024-08-23 17:55:39 +00:00
{
2024-08-24 16:36:32 +00:00
model . BuildModel ( "" , objPath ) ;
}
AddChild ( model ) ;
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 + + )
{
var lightmapRectData = ProcessCellSurfaceData ( surfaceDataMap , cell , cellIdx , polyIdx , cellIdxOffset ) ;
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-11 11:28:24 +00:00
var lightmapTexture = 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 ) ;
}
}
private LightmapRectData ProcessCellSurfaceData ( Dictionary < int , MeshSurfaceData > surfaceDataMap , WorldRep . Cell cell , int cellIdx , int polyIdx , int indicesOffset )
{
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 ] ;
var textureId = CalcBaseUV ( cell , poly , renderPoly , light , textureUvs , lightmapUvs , indicesOffset ) ;
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-07-30 20:50:34 +00:00
RectanglePacker . Pack ( packingRects , out var bounds ) ;
var image = Image . Create ( ( int ) bounds . Width , ( int ) bounds . Height , false , Image . Format . Rgba8 ) ;
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-01 17:23:17 +00:00
var layers = ( uint ) lightmap . Pixels . GetLength ( 0 ) ;
var height = ( uint ) lightmap . Pixels . GetLength ( 1 ) ;
var width = ( uint ) lightmap . Pixels . GetLength ( 2 ) ;
for ( uint y = 0 ; y < height ; y + + )
2024-07-30 20:50:34 +00:00
{
2024-08-01 17:23:17 +00:00
for ( uint x = 0 ; x < width ; x + + )
2024-07-30 20:50:34 +00:00
{
2024-08-01 17:23:17 +00:00
var rawColour = System . Numerics . Vector4 . Zero ;
for ( uint l = 0 ; l < layers ; l + + )
{
rawColour + = lightmap . GetPixel ( l , x , y ) ;
}
2024-08-03 15:09:51 +00:00
2024-08-03 16:24:04 +00:00
var colour = new Color ( MathF . Min ( rawColour . X , 1.0f ) , MathF . Min ( rawColour . Y , 1.0f ) , MathF . Min ( rawColour . Z , 1.0f ) , MathF . Min ( rawColour . W , 1.0f ) ) ;
2024-08-01 17:23:17 +00:00
image . SetPixel ( ( int ) ( rect . X + x ) , ( int ) ( rect . Y + y ) , colour ) ;
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 ,
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-05 18:49:36 +00:00
var txUScale = 64.0f / texture . GetWidth ( ) ;
var txVScale = 64.0f / 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
}