mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Merge branch '3.8' into 3.9-beta
This commit is contained in:
commit
95e147d898
@ -383,6 +383,7 @@
|
|||||||
* Updated to latest MonoGame version 3.7.1
|
* Updated to latest MonoGame version 3.7.1
|
||||||
* Rewrote example project to be cleaner and better demonstrate basic Spine features.
|
* Rewrote example project to be cleaner and better demonstrate basic Spine features.
|
||||||
* Added mix-and-match example to demonstrate the new Skin API.
|
* Added mix-and-match example to demonstrate the new Skin API.
|
||||||
|
* Added normalmap support via `SpineEffectNormalmap` and support for loading multiple texture layers following a suffix-pattern. Please see the example code on how to use them.
|
||||||
|
|
||||||
## Java
|
## Java
|
||||||
* **Breaking changes**
|
* **Breaking changes**
|
||||||
|
|||||||
115
spine-xna/example-content/SpineEffectNormalmap.fx
Normal file
115
spine-xna/example-content/SpineEffectNormalmap.fx
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
float4x4 World;
|
||||||
|
float4x4 View;
|
||||||
|
float4x4 Projection;
|
||||||
|
|
||||||
|
// Light0 parameters.
|
||||||
|
// Default values set below, change them via spineEffect.Parameters["Light0_Direction"] and similar.
|
||||||
|
float3 Light0_Direction = float3(-0.5265408f, -0.5735765f, -0.6275069f);
|
||||||
|
float3 Light0_Diffuse = float3(1, 1, 1);
|
||||||
|
float3 Light0_Specular = float3(1, 1, 1);
|
||||||
|
float Light0_SpecularExponent = 2.0; // also called "shininess", "specular hardness"
|
||||||
|
|
||||||
|
sampler TextureSampler : register(s0);
|
||||||
|
sampler NormalmapSampler : register(s1);
|
||||||
|
|
||||||
|
// TODO: add effect parameters here.
|
||||||
|
|
||||||
|
float NormalmapIntensity = 1;
|
||||||
|
|
||||||
|
float3 GetNormal(sampler normalmapSampler, float2 uv, float3 worldPos, float3 vertexNormal)
|
||||||
|
{
|
||||||
|
// Reconstruct tangent space TBN matrix
|
||||||
|
float3 pos_dx = ddx(worldPos);
|
||||||
|
float3 pos_dy = ddy(worldPos);
|
||||||
|
float3 tex_dx = float3(ddx(uv), 0.0);
|
||||||
|
float3 tex_dy = float3(ddy(uv), 0.0);
|
||||||
|
float divisor = (tex_dx.x * tex_dy.y - tex_dy.x * tex_dx.y);
|
||||||
|
float3 t = (tex_dy.y * pos_dx - tex_dx.y * pos_dy) / divisor;
|
||||||
|
|
||||||
|
float divisorBinormal = (tex_dy.y * tex_dx.x - tex_dx.y * tex_dy.x);
|
||||||
|
float3 b = (tex_dx.x * pos_dy - tex_dy.x * pos_dx) / divisorBinormal;
|
||||||
|
|
||||||
|
t = normalize(t - vertexNormal * dot(vertexNormal, t));
|
||||||
|
b = normalize(b - vertexNormal * dot(vertexNormal, b));
|
||||||
|
float3x3 tbn = float3x3(t, b, vertexNormal);
|
||||||
|
|
||||||
|
float3 n = 2.0 * tex2D(normalmapSampler, uv).rgb - 1.0;
|
||||||
|
#ifdef INVERT_NORMALMAP_Y
|
||||||
|
n.y = -n.y;
|
||||||
|
#endif
|
||||||
|
n = normalize(mul(n * float3(NormalmapIntensity, NormalmapIntensity, 1.0), tbn));
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetLightContributionBlinnPhong(inout float3 diffuseResult, inout float3 specularResult,
|
||||||
|
float3 lightDirection, float3 lightDiffuse, float3 lightSpecular, float specularExponent, float3 normal, float3 viewDirection)
|
||||||
|
{
|
||||||
|
diffuseResult += lightDiffuse * max(0.0, dot(normal, -lightDirection));
|
||||||
|
half3 halfVector = normalize(-lightDirection + viewDirection);
|
||||||
|
float nDotH = max(0, dot(normal, halfVector));
|
||||||
|
specularResult += lightSpecular * pow(nDotH, specularExponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VertexShaderInput
|
||||||
|
{
|
||||||
|
float4 Position : POSITION0;
|
||||||
|
float4 Color : COLOR0;
|
||||||
|
float4 TextureCoordinate : TEXCOORD0;
|
||||||
|
float4 Color2 : COLOR1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexShaderOutput
|
||||||
|
{
|
||||||
|
float4 Position : POSITION0;
|
||||||
|
float4 Color : COLOR0;
|
||||||
|
float4 TextureCoordinate : TEXCOORD0;
|
||||||
|
float4 Color2 : COLOR1;
|
||||||
|
float3 WorldNormal : TEXCOORD1;
|
||||||
|
float4 WorldPosition : TEXCOORD2; // for tangent reconstruction
|
||||||
|
};
|
||||||
|
|
||||||
|
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
|
||||||
|
{
|
||||||
|
VertexShaderOutput output;
|
||||||
|
|
||||||
|
float4 worldPosition = mul(input.Position, World);
|
||||||
|
float4 viewPosition = mul(worldPosition, View);
|
||||||
|
output.Position = mul(viewPosition, Projection);
|
||||||
|
output.TextureCoordinate = input.TextureCoordinate;
|
||||||
|
output.Color = input.Color;
|
||||||
|
output.Color2 = input.Color2;
|
||||||
|
|
||||||
|
output.WorldNormal = mul(transpose(View), float4(0, 0, 1, 0)).xyz;
|
||||||
|
output.WorldPosition = worldPosition;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
|
||||||
|
{
|
||||||
|
float4 texColor = tex2D(TextureSampler, input.TextureCoordinate);
|
||||||
|
float3 normal = GetNormal(NormalmapSampler, input.TextureCoordinate, input.WorldPosition, input.WorldNormal);
|
||||||
|
float3 viewDirection = -input.WorldNormal;
|
||||||
|
|
||||||
|
float alpha = texColor.a * input.Color.a;
|
||||||
|
float4 output;
|
||||||
|
output.a = alpha;
|
||||||
|
output.rgb = ((texColor.a - 1.0) * input.Color2.a + 1.0 - texColor.rgb) * input.Color2.rgb + texColor.rgb * input.Color.rgb;
|
||||||
|
|
||||||
|
float3 diffuseLight = float3(0, 0, 0);
|
||||||
|
float3 specularLight = float3(0, 0, 0);
|
||||||
|
GetLightContributionBlinnPhong(diffuseLight, specularLight,
|
||||||
|
Light0_Direction, Light0_Diffuse, Light0_Specular, Light0_SpecularExponent, normal, viewDirection);
|
||||||
|
output.rgb = diffuseLight * output.rgb + specularLight;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
technique Technique1
|
||||||
|
{
|
||||||
|
pass Pass1
|
||||||
|
{
|
||||||
|
// TODO: set renderstates here.
|
||||||
|
|
||||||
|
VertexShader = compile vs_3_0 VertexShaderFunction();
|
||||||
|
PixelShader = compile ps_3_0 PixelShaderFunction();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,6 +26,20 @@
|
|||||||
<Processor>EffectProcessor</Processor>
|
<Processor>EffectProcessor</Processor>
|
||||||
</Compile>
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="SpineEffectNormalmap.fx">
|
||||||
|
<Name>SpineEffectNormalmap</Name>
|
||||||
|
<Importer>EffectImporter</Importer>
|
||||||
|
<Processor>EffectProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="SpineEffectOutline.fx">
|
||||||
|
<Name>SpineEffectOutline</Name>
|
||||||
|
<Importer>EffectImporter</Importer>
|
||||||
|
<Processor>EffectProcessor</Processor>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\$(XnaFrameworkVersion)\Microsoft.Xna.GameStudio.ContentPipeline.targets" />
|
<Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\$(XnaFrameworkVersion)\Microsoft.Xna.GameStudio.ContentPipeline.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
|||||||
@ -122,18 +122,15 @@
|
|||||||
<None Include="data\coin-pro.skel">
|
<None Include="data\coin-pro.skel">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Include="data\goblins-mesh.atlas">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Include="data\goblins.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Include="data\raptor.png">
|
<None Include="data\raptor.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Include="data\spineboy.png">
|
<None Include="data\spineboy.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="data\raptor_normals.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<Content Include="data\tank.png">
|
<Content Include="data\tank.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
|||||||
@ -70,8 +70,20 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadContent () {
|
protected override void LoadContent () {
|
||||||
// Two color tint effect, comment line 80 to disable
|
|
||||||
var spineEffect = Content.Load<Effect>("spine-xna-example-content\\SpineEffect");
|
bool useNormalmapShader = false;
|
||||||
|
Effect spineEffect;
|
||||||
|
if (!useNormalmapShader) {
|
||||||
|
// Two color tint effect. Note that you can also use the default BasicEffect instead.
|
||||||
|
spineEffect = Content.Load<Effect>("spine-xna-example-content\\SpineEffect");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spineEffect = Content.Load<Effect>("spine-xna-example-content\\SpineEffectNormalmap");
|
||||||
|
spineEffect.Parameters["Light0_Direction"].SetValue(new Vector3(-0.5265408f, 0.5735765f, -0.6275069f));
|
||||||
|
spineEffect.Parameters["Light0_Diffuse"].SetValue(new Vector3(1, 0.9607844f, 0.8078432f));
|
||||||
|
spineEffect.Parameters["Light0_Specular"].SetValue(new Vector3(1, 0.9607844f, 0.8078432f));
|
||||||
|
spineEffect.Parameters["Light0_SpecularExponent"].SetValue(2.0f);
|
||||||
|
}
|
||||||
spineEffect.Parameters["World"].SetValue(Matrix.Identity);
|
spineEffect.Parameters["World"].SetValue(Matrix.Identity);
|
||||||
spineEffect.Parameters["View"].SetValue(Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 1.0f), Vector3.Zero, Vector3.Up));
|
spineEffect.Parameters["View"].SetValue(Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 1.0f), Vector3.Zero, Vector3.Up));
|
||||||
|
|
||||||
@ -85,15 +97,23 @@ namespace Spine {
|
|||||||
|
|
||||||
// String name = "spineboy-ess";
|
// String name = "spineboy-ess";
|
||||||
// String name = "goblins-pro";
|
// String name = "goblins-pro";
|
||||||
// String name = "raptor-pro";
|
String name = "raptor-pro";
|
||||||
// String name = "tank-pro";
|
// String name = "tank-pro";
|
||||||
String name = "coin-pro";
|
//String name = "coin-pro";
|
||||||
|
if (useNormalmapShader)
|
||||||
|
name = "raptor-pro"; // we only have normalmaps for raptor
|
||||||
String atlasName = name.Replace("-pro", "").Replace("-ess", "");
|
String atlasName = name.Replace("-pro", "").Replace("-ess", "");
|
||||||
if (name == "goblins-pro") atlasName = "goblins-mesh";
|
if (name == "goblins-pro") atlasName = "goblins-mesh";
|
||||||
bool binaryData = false;
|
bool binaryData = false;
|
||||||
|
|
||||||
Atlas atlas = new Atlas(assetsFolder + atlasName + ".atlas", new XnaTextureLoader(GraphicsDevice));
|
Atlas atlas;
|
||||||
|
if (!useNormalmapShader) {
|
||||||
|
atlas = new Atlas(assetsFolder + atlasName + ".atlas", new XnaTextureLoader(GraphicsDevice));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
atlas = new Atlas(assetsFolder + atlasName + ".atlas", new XnaTextureLoader(GraphicsDevice,
|
||||||
|
loadMultipleTextureLayers: true, textureSuffixes: new string[] { "", "_normals" }));
|
||||||
|
}
|
||||||
float scale = 1;
|
float scale = 1;
|
||||||
if (name == "spineboy-ess") scale = 0.6f;
|
if (name == "spineboy-ess") scale = 0.6f;
|
||||||
if (name == "raptor-pro") scale = 0.5f;
|
if (name == "raptor-pro") scale = 0.5f;
|
||||||
|
|||||||
@ -147,6 +147,10 @@ namespace Spine {
|
|||||||
triangleCount = 0;
|
triangleCount = 0;
|
||||||
lastTexture = item.texture;
|
lastTexture = item.texture;
|
||||||
device.Textures[0] = lastTexture;
|
device.Textures[0] = lastTexture;
|
||||||
|
if (item.textureLayers != null) {
|
||||||
|
for (int layer = 1; layer < item.textureLayers.Length; ++layer)
|
||||||
|
device.Textures[layer] = item.textureLayers[layer];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] itemTriangles = item.triangles;
|
int[] itemTriangles = item.triangles;
|
||||||
@ -182,7 +186,8 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class MeshItem {
|
public class MeshItem {
|
||||||
public Texture2D texture;
|
public Texture2D texture = null;
|
||||||
|
public Texture2D[] textureLayers = null;
|
||||||
public int vertexCount, triangleCount;
|
public int vertexCount, triangleCount;
|
||||||
public VertexPositionColorTextureColor[] vertices = { };
|
public VertexPositionColorTextureColor[] vertices = { };
|
||||||
public int[] triangles = { };
|
public int[] triangles = { };
|
||||||
|
|||||||
@ -36,7 +36,7 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Spine {
|
namespace Spine {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Batch drawing of lines and shapes that can be derrived from lines.
|
/// Batch drawing of lines and shapes that can be derived from lines.
|
||||||
///
|
///
|
||||||
/// Call drawing methods in between Begin()/End()
|
/// Call drawing methods in between Begin()/End()
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -109,7 +109,7 @@ namespace Spine {
|
|||||||
float attachmentZOffset = zSpacing * i;
|
float attachmentZOffset = zSpacing * i;
|
||||||
|
|
||||||
float attachmentColorR, attachmentColorG, attachmentColorB, attachmentColorA;
|
float attachmentColorR, attachmentColorG, attachmentColorB, attachmentColorA;
|
||||||
Texture2D texture = null;
|
object textureObject = null;
|
||||||
int verticesCount = 0;
|
int verticesCount = 0;
|
||||||
float[] vertices = this.vertices;
|
float[] vertices = this.vertices;
|
||||||
int indicesCount = 0;
|
int indicesCount = 0;
|
||||||
@ -120,7 +120,7 @@ namespace Spine {
|
|||||||
RegionAttachment regionAttachment = (RegionAttachment)attachment;
|
RegionAttachment regionAttachment = (RegionAttachment)attachment;
|
||||||
attachmentColorR = regionAttachment.R; attachmentColorG = regionAttachment.G; attachmentColorB = regionAttachment.B; attachmentColorA = regionAttachment.A;
|
attachmentColorR = regionAttachment.R; attachmentColorG = regionAttachment.G; attachmentColorB = regionAttachment.B; attachmentColorA = regionAttachment.A;
|
||||||
AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject;
|
AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject;
|
||||||
texture = (Texture2D)region.page.rendererObject;
|
textureObject = region.page.rendererObject;
|
||||||
verticesCount = 4;
|
verticesCount = 4;
|
||||||
regionAttachment.ComputeWorldVertices(slot.Bone, vertices, 0, 2);
|
regionAttachment.ComputeWorldVertices(slot.Bone, vertices, 0, 2);
|
||||||
indicesCount = 6;
|
indicesCount = 6;
|
||||||
@ -131,7 +131,7 @@ namespace Spine {
|
|||||||
MeshAttachment mesh = (MeshAttachment)attachment;
|
MeshAttachment mesh = (MeshAttachment)attachment;
|
||||||
attachmentColorR = mesh.R; attachmentColorG = mesh.G; attachmentColorB = mesh.B; attachmentColorA = mesh.A;
|
attachmentColorR = mesh.R; attachmentColorG = mesh.G; attachmentColorB = mesh.B; attachmentColorA = mesh.A;
|
||||||
AtlasRegion region = (AtlasRegion)mesh.RendererObject;
|
AtlasRegion region = (AtlasRegion)mesh.RendererObject;
|
||||||
texture = (Texture2D)region.page.rendererObject;
|
textureObject = region.page.rendererObject;
|
||||||
int vertexCount = mesh.WorldVerticesLength;
|
int vertexCount = mesh.WorldVerticesLength;
|
||||||
if (vertices.Length < vertexCount) vertices = new float[vertexCount];
|
if (vertices.Length < vertexCount) vertices = new float[vertexCount];
|
||||||
verticesCount = vertexCount >> 1;
|
verticesCount = vertexCount >> 1;
|
||||||
@ -196,7 +196,12 @@ namespace Spine {
|
|||||||
|
|
||||||
// submit to batch
|
// submit to batch
|
||||||
MeshItem item = batcher.NextItem(verticesCount, indicesCount);
|
MeshItem item = batcher.NextItem(verticesCount, indicesCount);
|
||||||
item.texture = texture;
|
if (textureObject is Texture2D)
|
||||||
|
item.texture = (Texture2D) textureObject;
|
||||||
|
else {
|
||||||
|
item.textureLayers = (Texture2D[]) textureObject;
|
||||||
|
item.texture = item.textureLayers[0];
|
||||||
|
}
|
||||||
for (int ii = 0, nn = indicesCount; ii < nn; ii++) {
|
for (int ii = 0, nn = indicesCount; ii < nn; ii++) {
|
||||||
item.triangles[ii] = indices[ii];
|
item.triangles[ii] = indices[ii];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,20 +35,60 @@ using Microsoft.Xna.Framework.Graphics;
|
|||||||
namespace Spine {
|
namespace Spine {
|
||||||
public class XnaTextureLoader : TextureLoader {
|
public class XnaTextureLoader : TextureLoader {
|
||||||
GraphicsDevice device;
|
GraphicsDevice device;
|
||||||
|
string[] textureLayerSuffixes = null;
|
||||||
|
|
||||||
public XnaTextureLoader (GraphicsDevice device) {
|
/// <summary>
|
||||||
|
/// Constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">The graphics device to be used.</param>
|
||||||
|
/// <param name="loadMultipleTextureLayers">If <c>true</c> multiple textures layers
|
||||||
|
/// (e.g. a diffuse/albedo texture and a normal map) are loaded instead of a single texture.
|
||||||
|
/// Names are constructed based on suffixes added according to the <c>textureSuffixes</c> parameter.</param>
|
||||||
|
/// <param name="textureSuffixes">If <c>loadMultipleTextureLayers</c> is <c>true</c>, the strings of this array
|
||||||
|
/// define the path name suffix of each layer to be loaded. Array size must be equal to the number of layers to be loaded.
|
||||||
|
/// The first array entry is the suffix to be <c>replaced</c> (e.g. "_albedo", or "" for a first layer without a suffix),
|
||||||
|
/// subsequent array entries contain the suffix to replace the first entry with (e.g. "_normals").
|
||||||
|
///
|
||||||
|
/// An example would be:
|
||||||
|
/// <code>new string[] { "", "_normals" }</code> for loading a base diffuse texture named "skeletonname.png" and
|
||||||
|
/// a normalmap named "skeletonname_normals.png".</param>
|
||||||
|
public XnaTextureLoader (GraphicsDevice device, bool loadMultipleTextureLayers = false, string[] textureSuffixes = null) {
|
||||||
this.device = device;
|
this.device = device;
|
||||||
|
if (loadMultipleTextureLayers)
|
||||||
|
this.textureLayerSuffixes = textureSuffixes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Load (AtlasPage page, String path) {
|
public void Load (AtlasPage page, String path) {
|
||||||
Texture2D texture = Util.LoadTexture(device, path);
|
Texture2D texture = Util.LoadTexture(device, path);
|
||||||
page.rendererObject = texture;
|
|
||||||
page.width = texture.Width;
|
page.width = texture.Width;
|
||||||
page.height = texture.Height;
|
page.height = texture.Height;
|
||||||
|
|
||||||
|
if (textureLayerSuffixes == null) {
|
||||||
|
page.rendererObject = texture;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Texture2D[] textureLayersArray = new Texture2D[textureLayerSuffixes.Length];
|
||||||
|
textureLayersArray[0] = texture;
|
||||||
|
for (int layer = 1; layer < textureLayersArray.Length; ++layer) {
|
||||||
|
string layerPath = GetLayerName(path, textureLayerSuffixes[0], textureLayerSuffixes[layer]);
|
||||||
|
textureLayersArray[layer] = Util.LoadTexture(device, layerPath);
|
||||||
|
}
|
||||||
|
page.rendererObject = textureLayersArray;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Unload (Object texture) {
|
public void Unload (Object texture) {
|
||||||
((Texture2D)texture).Dispose();
|
((Texture2D)texture).Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetLayerName (string firstLayerPath, string firstLayerSuffix, string replacementSuffix) {
|
||||||
|
|
||||||
|
int suffixLocation = firstLayerPath.LastIndexOf(firstLayerSuffix + ".");
|
||||||
|
if (suffixLocation == -1) {
|
||||||
|
throw new Exception(string.Concat("Error composing texture layer name: first texture layer name '", firstLayerPath,
|
||||||
|
"' does not contain suffix to be replaced: '", firstLayerSuffix, "'"));
|
||||||
|
}
|
||||||
|
return firstLayerPath.Remove(suffixLocation, firstLayerSuffix.Length).Insert(suffixLocation, replacementSuffix);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user