Skip to content

Commit

Permalink
[haxe][flixel] WIP fix alpha and color tinting not working on meshes.
Browse files Browse the repository at this point in the history
  • Loading branch information
davidetan committed Jul 17, 2024
1 parent 5331ee6 commit 311a719
Show file tree
Hide file tree
Showing 10 changed files with 215 additions and 37 deletions.
6 changes: 6 additions & 0 deletions spine-haxe/example/assets/export/skeleton.atlas
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
skeleton.png
size:404,404
filter:Linear,Linear
pma:true
square
bounds:2,2,400,400
1 change: 1 addition & 0 deletions spine-haxe/example/assets/export/skeleton.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"skeleton":{"hash":"gAzm+5Vz+z4","spine":"4.2.33","x":-320.5,"y":-381.5,"width":1036,"height":1194,"images":"./images","audio":"./audio"},"bones":[{"name":"root"}],"slots":[{"name":"square","bone":"root","attachment":"square"},{"name":"square2","bone":"root","attachment":"square"},{"name":"square3","bone":"root","attachment":"square"},{"name":"square4","bone":"root","color":"ff7676ff","attachment":"square"},{"name":"square5","bone":"root","attachment":"square"},{"name":"square6","bone":"root","attachment":"square"}],"skins":[{"name":"default","attachments":{"square":{"square":{"x":-2.5,"y":-5.5,"width":400,"height":400}},"square2":{"square":{"color":"ff0000ff","x":227.5,"y":160.5,"width":400,"height":400}},"square3":{"square":{"x":397.5,"y":306.5,"width":400,"height":400}},"square4":{"square":{"x":199.5,"y":612.5,"width":400,"height":400}},"square5":{"square":{"x":-120.5,"y":442.5,"width":400,"height":400}},"square6":{"square":{"color":"f700c0ff","x":515.5,"y":-181.5,"width":400,"height":400}}}}],"animations":{"animation":{}}}
Binary file added spine-haxe/example/assets/export/skeleton.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 16 additions & 19 deletions spine-haxe/example/src/flixelExamples/BasicExample.hx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

package flixelExamples;

import flixel.ui.FlxButton;
import flixel.FlxG;
import spine.flixel.SkeletonSprite;
import spine.flixel.FlixelTextureLoader;
Expand All @@ -43,15 +44,20 @@ class BasicExample extends FlxState {

var skeletonSprite:SkeletonSprite;
override public function create():Void {
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(new SequenceExample()));
button.setPosition(FlxG.width * .75, FlxG.height / 10);
add(button);

var atlas = new TextureAtlas(Assets.getText("assets/raptor.atlas"), new FlixelTextureLoader("assets/raptor-pro.atlas"));
var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/raptor-pro.skel") : Assets.getText("assets/raptor-pro.json"), atlas);
var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/raptor-pro.skel") : Assets.getText("assets/raptor-pro.json"), atlas, .25);
var animationStateData = new AnimationStateData(skeletondata);
animationStateData.defaultMix = 0.25;

skeletonSprite = new SkeletonSprite(skeletondata, animationStateData, .25);
// var bounds = skeletonSprite.skeleton.getBounds();
// skeletonSprite.scale = Starling.current.stage.stageWidth / bounds.width * 0.5;
skeletonSprite.setPosition(.5 * FlxG.width, .5 * FlxG.height);
skeletonSprite = new SkeletonSprite(skeletondata, animationStateData);
skeletonSprite.setPosition(
.5 * FlxG.width - skeletonSprite.width / 2,
.5 * FlxG.height - skeletonSprite.height / 2
);

skeletonSprite.state.setAnimationByName(0, "walk", true);

Expand All @@ -66,31 +72,22 @@ class BasicExample extends FlxState {
trace("loaded");
}

// public function onTouch(e:TouchEvent) {
// var touch = e.getTouch(this);
// if (touch != null && touch.phase == TouchPhase.ENDED) {
// SceneManager.getInstance().switchScene(new SequenceExample());
// }
// }

override public function update(elapsed:Float):Void
{
if (FlxG.keys.anyPressed([RIGHT])) {
skeletonSprite.x += 250 * elapsed;
skeletonSprite.x += 15;
}

if (FlxG.keys.anyPressed([LEFT])) {
skeletonSprite.x -= 250 * elapsed;
skeletonSprite.x -= 15;
}

if (FlxG.keys.anyPressed([UP])) {
skeletonSprite.y += 250 * elapsed;
skeletonSprite.y += 15;
}

if (FlxG.keys.anyPressed([DOWN])) {
skeletonSprite.y -= 250 * elapsed;
skeletonSprite.y -= 15;
}

super.update(elapsed);
}

}
15 changes: 7 additions & 8 deletions spine-haxe/example/src/flixelExamples/FlixelState.hx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class FlixelState extends FlxState

override public function create():Void
{
FlxG.switchState(new MixAndMatchExample());
// FlxG.switchState(new SequenceExample());
// FlxG.switchState(new BasicExample());

FlxG.cameras.bgColor = 0xffa1b2b0;

// setting speed of spineboy (450 is the speed to not let him slide)
Expand All @@ -50,20 +54,15 @@ class FlixelState extends FlxState
myText.alignment = CENTER;
group.add(myText);

var button = new FlxButton(0, 0, "Click me", () -> {
FlxG.switchState(new BasicExample());
});
button.screenCenter();
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(new BasicExample()));
button.setPosition(FlxG.width * .75, FlxG.height / 10);
add(button);

// creating a sprite for the floor
var floor = new FlxSprite();
floor.loadGraphic(FlxGraphic.fromRectangle(FlxG.width, FlxG.height - 100, 0xff822f02));
floor.y = FlxG.height - 100;
add(floor);
var button = new FlxButton("Click me", () -> {
trace("clicked");
});

// loading spineboy
var atlas = new TextureAtlas(Assets.getText("assets/spineboy.atlas"), new FlixelTextureLoader("assets/spineboy.atlas"));
Expand Down Expand Up @@ -119,7 +118,7 @@ class FlixelState extends FlxState
// adding spineboy to the stage
add(spineSprite);

FlxG.debugger.visible = !FlxG.debugger.visible;
// FlxG.debugger.visible = !FlxG.debugger.visible;
// debug ui
// FlxG.debugger.visible = true;
// FlxG.debugger.drawDebug = true;
Expand Down
90 changes: 90 additions & 0 deletions spine-haxe/example/src/flixelExamples/MixAndMatchExample.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package flixelExamples;


import spine.Skin;
import flixel.ui.FlxButton;
import flixel.FlxG;
import spine.flixel.SkeletonSprite;
import spine.flixel.FlixelTextureLoader;
import flixel.FlxState;
import openfl.utils.Assets;
import spine.SkeletonData;
import spine.animation.AnimationStateData;
import spine.atlas.TextureAtlas;

class MixAndMatchExample extends FlxState {
var loadBinary = false;
// var loadBinary = true;

var skeletonSprite:SkeletonSprite;
override public function create():Void {
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(new BasicExample()));
button.setPosition(FlxG.width * .75, FlxG.height / 10);
add(button);

// var atlas = new TextureAtlas(Assets.getText("assets/export/skeleton.atlas"), new FlixelTextureLoader("assets/export/skeleton.atlas"));
// var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/export/skeleton.skel") : Assets.getText("assets/export/skeleton.json"), atlas, .5);

var atlas = new TextureAtlas(Assets.getText("assets/mix-and-match.atlas"), new FlixelTextureLoader("assets/mix-and-match.atlas"));
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/mix-and-match-pro.skel") : Assets.getText("assets/mix-and-match-pro.json"), atlas, .5);
var animationStateData = new AnimationStateData(data);
animationStateData.defaultMix = 0.25;

skeletonSprite = new SkeletonSprite(data, animationStateData);
// var customSkin = new Skin("custom");
// var skinBase = data.findSkin("skin-base");
// customSkin.addSkin(skinBase);
// customSkin.addSkin(data.findSkin("nose/short"));
// customSkin.addSkin(data.findSkin("eyelids/girly"));
// customSkin.addSkin(data.findSkin("eyes/violet"));
// customSkin.addSkin(data.findSkin("hair/brown"));
// customSkin.addSkin(data.findSkin("clothes/hoodie-orange"));
// customSkin.addSkin(data.findSkin("legs/pants-jeans"));
// customSkin.addSkin(data.findSkin("accessories/bag"));
// customSkin.addSkin(data.findSkin("accessories/hat-red-yellow"));
// skeletonSprite.skeleton.skin = customSkin;

camera.zoom = .5;
skeletonSprite.skeleton.skinName = "full-skins/girl";
skeletonSprite.setBoundingBox();

skeletonSprite.afterUpdateWorldTransforms = s -> {
for(slot in s.skeleton.slots) {
if (slot.data.name != "hair-patch") {
// slot.attachment = null;
}
}
}

// skeletonSprite.y -=300;

skeletonSprite.screenCenter();
// skeletonSprite.state.setAnimationByName(0, "dance", true);
add(skeletonSprite);

// FlxG.debugger.visible = !FlxG.debugger.visible;
// FlxG.debugger.track(skeletonSprite);
// FlxG.debugger.track(camera);
FlxG.debugger.drawDebug = true;
super.create();
}

override public function update(elapsed:Float):Void
{
if (FlxG.keys.anyPressed([RIGHT])) {
skeletonSprite.x += 15;
}
if (FlxG.keys.anyPressed([LEFT])) {
skeletonSprite.x -= 15;
}
if (FlxG.keys.anyPressed([UP])) {
skeletonSprite.y -= 15;
}
if (FlxG.keys.anyPressed([DOWN])) {
skeletonSprite.y += 15;
}

super.update(elapsed);
}

}
39 changes: 39 additions & 0 deletions spine-haxe/example/src/flixelExamples/SequenceExample.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package flixelExamples;


import flixel.ui.FlxButton;
import flixel.FlxG;
import spine.flixel.SkeletonSprite;
import spine.flixel.FlixelTextureLoader;
import flixel.FlxState;
import openfl.utils.Assets;
import spine.SkeletonData;
import spine.animation.AnimationStateData;
import spine.atlas.TextureAtlas;

class SequenceExample extends FlxState {
var loadBinary = true;

var skeletonSprite:SkeletonSprite;
override public function create():Void {
var button = new FlxButton(0, 0, "Next scene", () -> FlxG.switchState(new MixAndMatchExample()));
button.setPosition(FlxG.width * .75, FlxG.height / 10);
add(button);

var atlas = new TextureAtlas(Assets.getText("assets/dragon.atlas"), new FlixelTextureLoader("assets/dragon.atlas"));
var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/dragon-ess.skel") : Assets.getText("assets/dragon-.json"), atlas, .5);
var animationStateData = new AnimationStateData(skeletondata);
animationStateData.defaultMix = 0.25;

skeletonSprite = new SkeletonSprite(skeletondata, animationStateData);
skeletonSprite.screenCenter();
skeletonSprite.y -= 100;

skeletonSprite.state.setAnimationByName(0, "flying", true);
FlxG.debugger.visible = !FlxG.debugger.visible;
FlxG.debugger.track(skeletonSprite);
add(skeletonSprite);
super.create();
}

}
7 changes: 6 additions & 1 deletion spine-haxe/spine-haxe/spine/flixel/FlixelTextureLoader.hx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

package spine.flixel;

import flixel.graphics.FlxGraphic;
import flixel.FlxG;
import spine.atlas.TextureAtlasPage;
import spine.atlas.TextureAtlasRegion;
Expand All @@ -53,7 +54,11 @@ class FlixelTextureLoader implements TextureLoader
if (bitmapData == null) {
throw new SpineException("Could not load atlas page texture " + basePath + "/" + path);
}
page.texture = SpineTexture.from(bitmapData);
var texture:FlxGraphic = SpineTexture.from(bitmapData);
// TODO: reset this value to true when destroy skeleton
// this is needed for sequence, otherwise the previous texture would be detroyed
texture.destroyOnNoUse = false;
page.texture = texture;
}

public function loadRegion(region:TextureAtlasRegion):Void {
Expand Down
7 changes: 5 additions & 2 deletions spine-haxe/spine-haxe/spine/flixel/SkeletonMesh.hx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ import flixel.system.FlxAssets.FlxGraphicAsset;
import flixel.FlxStrip;

class SkeletonMesh extends FlxStrip {
public function new(texture:FlxGraphicAsset) {
super(0, 0, texture);
public function new(/*texture:FlxGraphicAsset*/) {
super();
// graphic = texture;
}


}
52 changes: 45 additions & 7 deletions spine-haxe/spine-haxe/spine/flixel/SkeletonSprite.hx
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,17 @@ class SkeletonSprite extends FlxObject
skeleton.updateWorldTransform(Physics.update);
state = new AnimationState(animationStateData != null ? animationStateData : new AnimationStateData(skeletonData));

setBoundingBox();
}

public function setBoundingBox() {
var bounds = skeleton.getBounds();
width = bounds.width;
height = bounds.height;
offsetX = bounds.width / 2;
offsetY = bounds.height;
if (bounds.width > 0 && bounds.height > 0) {
width = bounds.width;
height = bounds.height;
offsetX = bounds.width / 2;
offsetY = bounds.height;
}
}

override public function destroy():Void
Expand Down Expand Up @@ -131,6 +137,7 @@ class SkeletonSprite extends FlxObject
region.computeWorldVertices(slot, worldVertices, 0, clippedVertexSize);

mesh = getFlixelMeshFromRendererAttachment(region);
mesh.graphic = region.region.texture;
triangles = QUAD_INDICES;
uvs = region.uvs;
attachmentColor = region.color;
Expand All @@ -144,6 +151,7 @@ class SkeletonSprite extends FlxObject
meshAttachment.computeWorldVertices(slot, 0, meshAttachment.worldVerticesLength, worldVertices, 0, clippedVertexSize);

mesh = getFlixelMeshFromRendererAttachment(meshAttachment);
mesh.graphic = meshAttachment.region.texture;
triangles = meshAttachment.triangles;
uvs = meshAttachment.uvs;
attachmentColor = meshAttachment.color;
Expand All @@ -158,11 +166,41 @@ class SkeletonSprite extends FlxObject

if (mesh != null) {

mesh.color.setRGBFloat(
// cannot use directly mesh.color.setRGBFloat otherwise the setter won't be called and transfor color not set
// trace('${slot.data.name}');
// trace(skeleton.color.r * slot.color.r * attachmentColor.r * color.redFloat);
// trace(skeleton.color.g * slot.color.g * attachmentColor.g * color.greenFloat);
// trace(skeleton.color.b * slot.color.b * attachmentColor.b * color.blueFloat);
// trace('${mesh.color}\n');
var _tmpColor:Int;
// _tmpColor = FlxColor.fromRGBFloat(1,1,1,1);


_tmpColor = FlxColor.fromRGBFloat(
skeleton.color.r * slot.color.r * attachmentColor.r * color.redFloat,
skeleton.color.g * slot.color.g * attachmentColor.g * color.greenFloat,
skeleton.color.b * slot.color.b * attachmentColor.b * color.blueFloat
skeleton.color.b * slot.color.b * attachmentColor.b * color.blueFloat,
1
);


// // if (slot.data.name == "hair-patch") {
// if (slot.data.name == "square2") {
// _tmpColor = FlxColor.fromRGBFloat(
// skeleton.color.r * slot.color.r * attachmentColor.r * color.redFloat,
// skeleton.color.g * slot.color.g * attachmentColor.g * color.greenFloat,
// skeleton.color.b * slot.color.b * attachmentColor.b * color.blueFloat,
// 1
// );
// // continue;
// // trace('${mesh.color.red} | ${mesh.color.green} | ${mesh.color.blue} | ${mesh.color.alpha}');
// } else {
// // trace(slot.data.name);
// _tmpColor = FlxColor.fromRGBFloat(1,1,1,1);
// }
// trace('${slot.data.name}\t${mesh.color}');

mesh.color = _tmpColor;
mesh.alpha = skeleton.color.a * slot.color.a * attachmentColor.a * alpha;

if (clipper.isClipping()) {
Expand Down Expand Up @@ -200,7 +238,7 @@ class SkeletonSprite extends FlxObject

private function getFlixelMeshFromRendererAttachment(region: RenderedAttachment) {
if (region.rendererObject == null) {
var skeletonMesh = new SkeletonMesh(region.region.texture);
var skeletonMesh = new SkeletonMesh();
region.rendererObject = skeletonMesh;
skeletonMesh.exists = false;
_meshes.push(skeletonMesh);
Expand Down

0 comments on commit 311a719

Please sign in to comment.