upd: sync local changes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
iisaevandClaude Opus 5.5 committed 2026-10-16 16:18:18 +00:00
1 parent b8ddf1f0df
commit a9d4417fce
27 files changed
+3446 -1148

No files matched your search

+101 -69
View File
@@ -5,20 +5,29 @@ using Godot;
namespace Cthangover.Live2D.Cubism.Framework
{
/// <summary>
/// Manages the 2D transformation (scale, translation, alignment) for a
/// Cubism model rendered inside a Godot <see cref="Node2D"/>.
///
/// Works with two coordinate systems:
/// Port of CubismModelMatrix.cpp (Cubism SDK for Native 5-r.5).
/// Manages the 2D transformation (scale, translation, alignment) of a Cubism
/// model inside its logical coordinate space.
///
/// SDK semantics to be aware of:
/// <list type="bullet">
/// <item>Cubism canvas coordinates (the model's native coordinate space)</item>
/// <item>Godot node local coordinates (where the model is placed)</item>
/// <item><see cref="SetWidth"/> and <see cref="SetHeight"/> MULTIPLY the
/// current scale by target / canvas-size (they do not assign it),
/// exactly like the C++ original.</item>
/// <item>The (width, height) constructor performs
/// <c>SetHeight(2.0f)</c> like the SDK, i.e. the model is initially
/// scaled to occupy 2 logical units of height.</item>
/// <item>Translation methods are INCREMENTAL in the SDK: SetX/SetY,
/// SetPosition, Top, Left (via TranslateX/Y) add to the current
/// translation. SetupFromLayout is unaffected because it starts from a
/// fresh matrix (translation 0).</item>
/// <item>CenterX/CenterY/Bottom/Right compute their offset from the full
/// scaled size (canvas size × current scale).</item>
/// </list>
///
/// The scale is computed relative to the canvas dimensions stored at construction.
/// <see cref="SetWidth"/> and <see cref="SetHeight"/> set a uniform scale based
/// on the ratio of target size to canvas size. <see cref="SetupFromLayout"/> reads
/// positioning keys from a Cubism .model3.json "Layout" section.
/// <see cref="ApplyToNode"/> writes the final transform to a Godot Node2D.
///
/// <see cref="SetupFromLayout"/> reads positioning keys from a Cubism
/// .model3.json "Layout" section; <see cref="ApplyToNode"/> writes the final
/// transform to a Godot <see cref="Node2D"/>.
/// </summary>
public class CubismModelMatrix
{
@@ -33,68 +42,80 @@ namespace Cthangover.Live2D.Cubism.Framework
public CubismModelMatrix() { }
/// <summary>
/// Creates a matrix referenced to the given canvas pixel dimensions.
/// Subsequent calls to <see cref="SetWidth"/> and <see cref="SetHeight"/>
/// will compute scale as target / canvas.
/// Creates a matrix referenced to the given canvas dimensions.
/// Like the SDK constructor, this calls <see cref="SetHeight"/>(2.0f),
/// so the model initially occupies 2 logical units of height.
/// </summary>
public CubismModelMatrix(float width, float height)
{
_width = width;
_height = height;
SetHeight(2.0f);
}
/// <summary>Current uniform scale on the X axis.</summary>
/// <summary>Current scale on the X axis.</summary>
public float ScaleX => _scaleX;
/// <summary>Current uniform scale on the Y axis.</summary>
/// <summary>Current scale on the Y axis.</summary>
public float ScaleY => _scaleY;
/// <summary>Current X translation offset in Godot local coordinates.</summary>
/// <summary>Current X translation offset.</summary>
public float TranslateX => _translateX;
/// <summary>Current Y translation offset in Godot local coordinates.</summary>
/// <summary>Current Y translation offset.</summary>
public float TranslateY => _translateY;
/// <summary>SDK CubismModelMatrix::Scale — multiplies the current scale.</summary>
public void Scale(float scaleX, float scaleY)
{
_scaleX *= scaleX;
_scaleY *= scaleY;
}
/// <summary>
/// Sets uniform scale to match the given width. Scale = targetWidth / canvasWidth.
/// Does nothing if canvas width is zero or unknown.
/// SDK SetWidth: multiplies the current uniform scale by w / canvasWidth.
/// Ignored when the canvas width is zero or unknown (the SDK would divide by zero).
/// </summary>
public void SetWidth(float w)
{
if (_width > 0f)
{
var scale = w / _width;
_scaleX = scale;
_scaleY = scale;
}
if (_width <= 0f) return;
var scaleX = w / _width;
var scaleY = scaleX;
Scale(scaleX, scaleY);
}
/// <summary>
/// Sets uniform scale to match the given height. Scale = targetHeight / canvasHeight.
/// Does nothing if canvas height is zero or unknown.
/// SDK SetHeight: multiplies the current uniform scale by h / canvasHeight.
/// Ignored when the canvas height is zero or unknown (the SDK would divide by zero).
/// </summary>
public void SetHeight(float h)
{
if (_height > 0f)
{
var scale = h / _height;
_scaleX = scale;
_scaleY = scale;
}
if (_height <= 0f) return;
var scaleX = h / _height;
var scaleY = scaleX;
Scale(scaleX, scaleY);
}
/// <summary>Sets absolute translation position.</summary>
public void SetPosition(float x, float y)
/// <summary>SDK Translate — adds x and y to the current translation
/// (the SDK's TranslateX/TranslateY helpers are folded in here; the
/// TranslateX/TranslateY properties above are the read accessors).</summary>
public void Translate(float x, float y)
{
_translateX = x;
_translateY = y;
_translateX += x;
_translateY += y;
}
/// <summary>Sets absolute X translation.</summary>
public void SetX(float x) => _translateX = x;
/// <summary>SDK SetPosition — incremental (adds to the current translation).</summary>
public void SetPosition(float x, float y) => Translate(x, y);
/// <summary>Sets absolute Y translation.</summary>
public void SetY(float y) => _translateY = y;
/// <summary>SDK SetX — incremental (adds to the current X translation).</summary>
public void SetX(float x) => _translateX += x;
/// <summary>SDK SetY — incremental (adds to the current Y translation).</summary>
public void SetY(float y) => _translateY += y;
/// <summary>
/// Centers the model horizontally and vertically at the given point.
@@ -106,34 +127,45 @@ namespace Cthangover.Live2D.Cubism.Framework
CenterY(y);
}
/// <summary>
/// Centers horizontally: translateX = x - (width * scaleX) / 2.
/// </summary>
public void CenterX(float x) => _translateX = x - (_width * _scaleX) / 2f;
/// <summary>SDK CenterX — adds x - (width × scaleX) / 2 to the X translation.</summary>
public void CenterX(float x)
{
var w = _width * _scaleX;
_translateX += x - (w / 2f);
}
/// <summary>SDK CenterY — adds y - (height × scaleY) / 2 to the Y translation.</summary>
public void CenterY(float y)
{
var h = _height * _scaleY;
_translateY += y - (h / 2f);
}
/// <summary>SDK Top — adds y to the Y translation (via SetY).</summary>
public void Top(float y) => SetY(y);
/// <summary>SDK Bottom — adds y - (height × scaleY) to the Y translation.</summary>
public void Bottom(float y)
{
var h = _height * _scaleY;
_translateY += y - h;
}
/// <summary>SDK Left — adds x to the X translation (via SetX).</summary>
public void Left(float x) => SetX(x);
/// <summary>SDK Right — adds x - (width × scaleX) to the X translation.</summary>
public void Right(float x)
{
var w = _width * _scaleX;
_translateX += x - w;
}
/// <summary>
/// Centers vertically: translateY = y - (height * scaleY) / 2.
/// </summary>
public void CenterY(float y) => _translateY = y - (_height * _scaleY) / 2f;
/// <summary>Aligns the top edge of the model to y.</summary>
public void Top(float y) => _translateY = y;
/// <summary>Aligns the bottom edge of the model to y.</summary>
public void Bottom(float y) => _translateY = y - _height * _scaleY;
/// <summary>Aligns the left edge of the model to x.</summary>
public void Left(float x) => _translateX = x;
/// <summary>Aligns the right edge of the model to x.</summary>
public void Right(float x) => _translateX = x - _width * _scaleX;
/// <summary>
/// Configures scale and position from a layout dictionary.
/// Supported keys: "width", "height", "x", "y", "center_x", "center_y",
/// "top", "bottom", "left", "right".
/// Width/height are applied first (since they affect scale),
/// then position keys are applied.
/// SDK SetupFromLayout — configures scale and position from a layout
/// dictionary (lowercased keys). Width/height are applied first (they
/// affect scale), then the position keys: "x", "y", "center_x",
/// "center_y", "top", "bottom", "left", "right".
/// </summary>
public void SetupFromLayout(Dictionary<string, float> layout)
{