13
13
using Source2Roblox . Textures ;
14
14
15
15
using RobloxFiles . DataTypes ;
16
+ using System . Threading . Tasks ;
17
+ using System . Collections . Concurrent ;
18
+ using System . Threading ;
19
+ using RobloxFiles ;
16
20
17
21
namespace Source2Roblox . Geometry
18
22
{
@@ -167,40 +171,6 @@ public static void BakeBSP(BSPFile bsp, string exportDir, GameMount game = null)
167
171
vertIndices . Add ( edge ) ;
168
172
}
169
173
170
- var windingToBrushSide = new Dictionary < Winding , BrushSide > ( ) ;
171
- var brushSideToBrush = new Dictionary < BrushSide , Brush > ( ) ;
172
- var windingOctree = new Octree < Winding > ( ) ;
173
-
174
- var brushSides = bsp . BrushSides ;
175
- var brushes = bsp . Brushes ;
176
- int solved = 0 ;
177
-
178
- foreach ( var brush in brushes )
179
- {
180
- var sides = new List < BrushSide > ( ) ;
181
- var firstSide = brush . FirstSide ;
182
- var numSides = brush . NumSides ;
183
-
184
- for ( int i = 0 ; i < numSides ; i ++ )
185
- {
186
- var side = brushSides [ firstSide + i ] ;
187
- brushSideToBrush [ side ] = brush ;
188
- sides . Add ( side ) ;
189
- }
190
-
191
- Console . WriteLine ( $ "Solving Brush { solved ++ } /{ brushes . Count } ") ;
192
- var windings = bsp . SolveFaces ( brush ) ;
193
-
194
- for ( int i = 0 ; i < windings . Count ; i ++ )
195
- {
196
- var winding = windings [ i ] ;
197
- var side = sides [ i ] ;
198
-
199
- Debugger . Break ( ) ;
200
- }
201
- }
202
-
203
-
204
174
var materialSets = new Dictionary < string , ValveMaterial > ( ) ;
205
175
var vertOffsets = new Dictionary < int , Vector3 > ( ) ;
206
176
@@ -309,6 +279,7 @@ public static void BakeBSP(BSPFile bsp, string exportDir, GameMount game = null)
309
279
}
310
280
311
281
var faces = bsp . Faces . OrderBy ( face => face . Material ) ;
282
+ var faceOctree = new Octree < Face > ( ) ;
312
283
numNorms = 0 ;
313
284
314
285
foreach ( Face face in faces )
@@ -492,8 +463,45 @@ public static void BakeBSP(BSPFile bsp, string exportDir, GameMount game = null)
492
463
numUVs += numEdges ;
493
464
numNorms += numEdges ;
494
465
numVerts += numEdges ;
466
+
467
+ faceOctree . CreateNode ( center , face ) ;
468
+ }
469
+
470
+ // Cluster nearby faces by material.
471
+ var facesLeft = faces
472
+ . Where ( face => ! face . Skip )
473
+ . ToHashSet ( ) ;
474
+
475
+ var clusters = new List < HashSet < Face > > ( ) ;
476
+
477
+ while ( facesLeft . Any ( ) )
478
+ {
479
+ var face = facesLeft . First ( ) ;
480
+ facesLeft . Remove ( face ) ;
481
+
482
+ var cluster = new HashSet < Face > ( ) ;
483
+ cluster . Add ( face ) ;
484
+
485
+ var area = face . Area ;
486
+ var sqrtArea = ( float ) Math . Sqrt ( area ) ;
487
+
488
+ var nearby = faceOctree
489
+ . RadiusSearch ( face . Center , sqrtArea * 5 )
490
+ . Where ( other => other . Material == face . Material )
491
+ . Where ( facesLeft . Contains ) ;
492
+
493
+ foreach ( var other in nearby )
494
+ {
495
+ facesLeft . Remove ( other ) ;
496
+ cluster . Add ( other ) ;
497
+ }
498
+
499
+ clusters . Add ( cluster ) ;
495
500
}
496
501
502
+ // Write OBJ files.
503
+ Console . WriteLine ( "Writing OBJ files..." ) ;
504
+
497
505
string objPath = Path . Combine ( exportDir , $ "{ mapName } .obj") ;
498
506
string mtlPath = Path . Combine ( exportDir , $ "{ mapName } .mtl") ;
499
507
@@ -509,25 +517,26 @@ public static void BakeBSP(BSPFile bsp, string exportDir, GameMount game = null)
509
517
foreach ( var uv in uvs )
510
518
objWriter . AppendLine ( $ "vt { uv . X } { 1f - uv . Y } ") ;
511
519
512
- var facesByMaterial = faces
513
- . GroupBy ( face => face . Material )
514
- . OrderBy ( group => group . Key ) ;
515
-
516
- int faceCount = 0 ;
517
-
518
- foreach ( var group in facesByMaterial )
520
+ for ( int i = 0 ; i < clusters . Count ; i ++ )
519
521
{
520
- objWriter . AppendLine ( $ "usemtl { group . Key } ") ;
521
-
522
- foreach ( var face in group )
522
+ bool first = true ;
523
+ var cluster = clusters [ i ] ;
524
+ objWriter . AppendLine ( $ "o cluster_{ i } ") ;
525
+
526
+ foreach ( var face in cluster )
523
527
{
524
528
int dispInfo = face . DispInfo ,
525
529
numEdges = face . NumEdges ,
526
530
firstVert = face . FirstVert ,
527
531
firstNorm = face . FirstNorm ,
528
532
firstUV = face . FirstUV ;
529
533
530
- objWriter . AppendLine ( $ " o face_{ faceCount ++ } ") ;
534
+ if ( first )
535
+ {
536
+ string material = face . Material ;
537
+ objWriter . AppendLine ( $ " usemtl { material } ") ;
538
+ first = false ;
539
+ }
531
540
532
541
if ( dispInfo >= 0 )
533
542
{
@@ -556,19 +565,18 @@ public static void BakeBSP(BSPFile bsp, string exportDir, GameMount game = null)
556
565
}
557
566
else
558
567
{
559
- var material = face . Material ;
560
568
var center = face . Center ;
561
569
562
570
if ( face . Skip )
563
571
continue ;
564
572
565
573
objWriter . Append ( " f" ) ;
566
574
567
- for ( int i = 0 ; i < numEdges ; i ++ )
575
+ for ( int j = 0 ; j < numEdges ; j ++ )
568
576
{
569
- var normIndex = 1 + firstNorm + i ;
570
- var vertIndex = 1 + firstVert + i ;
571
- var uvIndex = 1 + firstUV + i ;
577
+ var normIndex = 1 + firstNorm + j ;
578
+ var vertIndex = 1 + firstVert + j ;
579
+ var uvIndex = 1 + firstUV + j ;
572
580
573
581
objWriter . Append ( $ " { vertIndex } /{ uvIndex } /{ normIndex } ") ;
574
582
}
@@ -583,6 +591,53 @@ public static void BakeBSP(BSPFile bsp, string exportDir, GameMount game = null)
583
591
584
592
string mtl = mtlWriter . ToString ( ) ;
585
593
File . WriteAllText ( mtlPath , mtl ) ;
594
+
595
+ // Write Roblox Files...
596
+ Console . WriteLine ( "Writing Roblox files..." ) ;
597
+
598
+ string gameName = GameMount . GetGameName ( game ) ;
599
+ string localAppData = Environment . GetEnvironmentVariable ( "localappdata" ) ;
600
+
601
+ string sourceDir = Path . Combine ( localAppData , "Roblox Studio" , "content" , "source" , gameName ) ;
602
+ string mapsDir = Path . Combine ( sourceDir , "maps" ) ;
603
+ string mapDir = Path . Combine ( mapsDir , bsp . Name ) ;
604
+
605
+ Directory . CreateDirectory ( sourceDir ) ;
606
+ Directory . CreateDirectory ( mapsDir ) ;
607
+ Directory . CreateDirectory ( mapDir ) ;
608
+
609
+ string savePath = Path . Combine ( mapsDir , bsp . Name + ".rbxm" ) ;
610
+ var map = new BinaryRobloxFile ( ) ;
611
+
612
+ var level = new Model ( )
613
+ {
614
+ Name = bsp . Name ,
615
+ Parent = map
616
+ } ;
617
+
618
+ foreach ( var cluster in clusters )
619
+ {
620
+ var mesh = new RobloxMesh ( ) ;
621
+
622
+ foreach ( var face in cluster )
623
+ {
624
+ var numEdges = face . NumEdges ;
625
+
626
+ int firstNorm = face . FirstNorm ,
627
+ firstVert = face . FirstVert ,
628
+ firstUV = face . FirstUV ;
629
+
630
+ for ( int i = 0 ; i < numEdges ; i ++ )
631
+ {
632
+ var normIndex = 1 + firstNorm + i ;
633
+ var vertIndex = 1 + firstVert + i ;
634
+ var uvIndex = 1 + firstUV + i ;
635
+
636
+ }
637
+ }
638
+ }
639
+
640
+ map . Save ( savePath ) ;
586
641
}
587
642
}
588
643
}
0 commit comments