269 lines
6.3 KiB
C#
269 lines
6.3 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Godot;
|
|
using System;
|
|
|
|
|
|
|
|
namespace Rokojori
|
|
{
|
|
[Tool]
|
|
[GlobalClass]
|
|
public partial class TextureMerger:Node
|
|
{
|
|
public enum SourceMode
|
|
{
|
|
Viewports,
|
|
Textures
|
|
}
|
|
|
|
[Export]
|
|
public bool initialize;
|
|
|
|
[Export]
|
|
public bool createLayout;
|
|
|
|
|
|
[ExportGroup("Source")]
|
|
[Export]
|
|
public SourceMode sourceMode;
|
|
|
|
|
|
[ExportGroup("Source/Viewports")]
|
|
[Export]
|
|
public Node sourceViewportsContainer = null;
|
|
|
|
[Export]
|
|
public SubViewport[] sourceViewports;
|
|
|
|
[ExportGroup("Source/Textures")]
|
|
[Export]
|
|
public Texture2D[] sourceTextures;
|
|
|
|
[ExportGroup("Output")]
|
|
[Export]
|
|
public Node outputTarget;
|
|
|
|
public enum LayoutMode
|
|
{
|
|
Grid,
|
|
Custom
|
|
}
|
|
|
|
[Export]
|
|
public LayoutMode layoutMode = LayoutMode.Grid;
|
|
|
|
[ExportGroup("Output/Custom")]
|
|
[Export]
|
|
public Vector2[] customPositions;
|
|
|
|
[Export]
|
|
public Vector2[] customSizes;
|
|
|
|
[ExportGroup("Viewport")]
|
|
[Export]
|
|
public Vector2 textureSize = new Vector2( 2048, 2048 );
|
|
|
|
[Export]
|
|
public BaseMaterial3D.TransparencyEnum transparencyMode = BaseMaterial3D.TransparencyEnum.AlphaScissor;
|
|
|
|
[ExportGroup("Debugging")]
|
|
[Export]
|
|
public SubViewport X_textureMergerViewport;
|
|
|
|
[Export]
|
|
public Camera3D X_mergerCamera;
|
|
|
|
List<Texture2D> _textures = new List<Texture2D>();
|
|
|
|
public override void _Process( double delta )
|
|
{
|
|
if ( initialize )
|
|
{
|
|
initialize = false;
|
|
Initialize();
|
|
}
|
|
|
|
if ( createLayout )
|
|
{
|
|
createLayout = false;
|
|
CreateLayout();
|
|
}
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
if ( outputTarget == null )
|
|
{
|
|
outputTarget = this;
|
|
}
|
|
|
|
Nodes.RemoveAndDeleteChildren( outputTarget );
|
|
|
|
X_textureMergerViewport = outputTarget.CreateChild<SubViewport>( "Texture Merger Viewport" );
|
|
|
|
X_mergerCamera = X_textureMergerViewport.CreateChild<Camera3D>( "Texture Merger Camera" );
|
|
X_mergerCamera.Projection = Camera3D.ProjectionType.Orthogonal;
|
|
|
|
X_textureMergerViewport.Size = (Vector2I) textureSize;
|
|
X_textureMergerViewport.OwnWorld3D = true;
|
|
X_textureMergerViewport.TransparentBg = true;
|
|
|
|
X_mergerCamera.Size = 1;
|
|
|
|
}
|
|
|
|
void GrabTextures()
|
|
{
|
|
_textures = new List<Texture2D>();
|
|
|
|
if ( SourceMode.Textures == sourceMode )
|
|
{
|
|
_textures.AddRange( sourceTextures );
|
|
return;
|
|
}
|
|
|
|
if ( SourceMode.Viewports == sourceMode )
|
|
{
|
|
if ( sourceViewportsContainer != null )
|
|
{
|
|
sourceViewports = Nodes.AllIn<SubViewport>( sourceViewportsContainer, null, false ).ToArray();
|
|
}
|
|
|
|
var vpTextures = Arrays.Map( sourceViewports,
|
|
s =>
|
|
{
|
|
var vt = new ViewportTexture();
|
|
vt.ViewportPath = s.GetPath();
|
|
return vt;
|
|
}
|
|
);
|
|
|
|
_textures.AddRange( vpTextures );
|
|
}
|
|
}
|
|
|
|
void CreateLayout()
|
|
{
|
|
GrabTextures();
|
|
|
|
if ( LayoutMode.Grid == layoutMode )
|
|
{
|
|
CreateGridLayout();
|
|
}
|
|
else if ( LayoutMode.Custom == layoutMode )
|
|
{
|
|
CreateCustomLayout();
|
|
}
|
|
}
|
|
|
|
Vector2 ConvertUVtoCameraSpace( Vector2 uv )
|
|
{
|
|
var scale = Vector2.One;
|
|
var w = 1;
|
|
var h = 1;
|
|
|
|
if ( X_textureMergerViewport.Size.X != X_textureMergerViewport.Size.Y )
|
|
{
|
|
if ( X_textureMergerViewport.Size.X > X_textureMergerViewport.Size.Y )
|
|
{
|
|
w = X_textureMergerViewport.Size.X / X_textureMergerViewport.Size.Y;
|
|
}
|
|
else
|
|
{
|
|
h = X_textureMergerViewport.Size.Y / X_textureMergerViewport.Size.X;
|
|
}
|
|
}
|
|
|
|
var x = Mathf.Remap( uv.X, 0, 1, -w, w );
|
|
var y = Mathf.Remap( uv.Y, 0, 1, -h, h );
|
|
|
|
return new Vector2( x, y );
|
|
}
|
|
|
|
void CreateGridLayout()
|
|
{
|
|
var alignment = ComputeTextureAlignment( _textures.Count );
|
|
|
|
Nodes.RemoveAndDeleteChildrenOfType<CsgMesh3D>( X_textureMergerViewport );
|
|
|
|
for ( int i = 0; i < _textures.Count; i++ )
|
|
{
|
|
var mesh = X_textureMergerViewport.CreateChild<CsgMesh3D>( "Texture " + ( i + 1 ) );
|
|
|
|
var uvRectangle = GetUVRectangle( alignment, i );
|
|
SetMeshCoordinates( mesh, uvRectangle );
|
|
|
|
var material = new StandardMaterial3D();
|
|
material.Transparency = transparencyMode;
|
|
material.ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded;
|
|
|
|
material.AlbedoTexture = _textures[ i ];
|
|
mesh.Material = material;
|
|
}
|
|
}
|
|
|
|
void CreateCustomLayout()
|
|
{
|
|
for ( int i = 0; i < _textures.Count; i++ )
|
|
{
|
|
var mesh = outputTarget.CreateChild<CsgMesh3D>( "Texture " + ( i + 1 ) );
|
|
|
|
SetMeshCoordinates( mesh, customPositions[ i ], customSizes[ i ] );
|
|
|
|
var material = new StandardMaterial3D();
|
|
material.Transparency = transparencyMode;
|
|
material.ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded;
|
|
|
|
material.AlbedoTexture = _textures[ i ];
|
|
mesh.Material = material;
|
|
}
|
|
}
|
|
|
|
void SetMeshCoordinates( CsgMesh3D mesh, Rect2 rectangle )
|
|
{
|
|
SetMeshCoordinates( mesh, rectangle.Position, rectangle.Size );
|
|
}
|
|
|
|
void SetMeshCoordinates( CsgMesh3D mesh, Vector2 start, Vector2 size )
|
|
{
|
|
start = ConvertUVtoCameraSpace( start );
|
|
var end = ConvertUVtoCameraSpace( start + size );
|
|
|
|
size = end - start;
|
|
|
|
var quadMesh = new QuadMesh();
|
|
quadMesh.Size = size;
|
|
mesh.Mesh = quadMesh;
|
|
|
|
mesh.GlobalPosition = new Vector3( start.X - size.X , start.Y - size.Y, -1 );
|
|
}
|
|
|
|
public static Vector2I ComputeTextureAlignment( int numElements )
|
|
{
|
|
var root = Mathf.Sqrt( numElements );
|
|
|
|
var ceiled = Mathf.CeilToInt( root );
|
|
var floored = ceiled - 1;
|
|
|
|
var weight = Mathf.RoundToInt( root % 1 );
|
|
|
|
var height = weight * ceiled + ( 1 - weight ) * floored;
|
|
|
|
return new Vector2I( ceiled, height );
|
|
}
|
|
|
|
public static Rect2 GetUVRectangle( Vector2I textureAlignment, int index )
|
|
{
|
|
var x = index % textureAlignment.X;
|
|
var y = index / textureAlignment.Y;
|
|
|
|
var xs = 1f / textureAlignment.X;
|
|
var ys = 1f / textureAlignment.Y;
|
|
|
|
return new Rect2( x * xs, y * ys, new Vector2( xs, ys ) );
|
|
}
|
|
|
|
|
|
}
|
|
} |