Skip to content

Commit

Permalink
Add New Feature
Browse files Browse the repository at this point in the history
  • Loading branch information
isHarryh committed Feb 25, 2023
1 parent b0c00b5 commit 4aa567b
Show file tree
Hide file tree
Showing 3 changed files with 286 additions and 71 deletions.
122 changes: 78 additions & 44 deletions core/src/com/isharryh/arkpets/ArkChar.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;

import com.esotericsoftware.spine.Skeleton;
Expand All @@ -24,40 +24,38 @@
import com.esotericsoftware.spine.Animation;
import com.esotericsoftware.spine.AnimationState;
import com.esotericsoftware.spine.AnimationStateData;
import com.esotericsoftware.spine.Animation.MixBlend;
import com.esotericsoftware.spine.Animation.MixDirection;
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;

import com.isharryh.arkpets.easings.EasingLinear;
import com.isharryh.arkpets.easings.EasingLinearVector3;
import com.isharryh.arkpets.utils.AnimData;
import com.isharryh.arkpets.utils.FlexibleWindowCtrl;
import com.isharryh.arkpets.utils.FrameCtrl;
import java.nio.ByteBuffer;


public class ArkChar {
private OrthographicCamera camera;
private TwoColorPolygonBatch batch;
private final OrthographicCamera camera;
private final TwoColorPolygonBatch batch;
private Texture bgTexture;
public Vector3 positionCur;
public Vector3 positionTar;
public EasingLinearVector3 positionEas;
public int offset_y;
public Matrix4 transform;

private Skeleton skeleton;
private SkeletonRenderer renderer;
private final Skeleton skeleton;
private final SkeletonRenderer renderer;
private final int MAX_SKELETON_SIZE = 500;
private SkeletonData skeletonData;
private Animation animation;
private AnimationState animationState;
private Pixmap lastTexture;

private int anim_width;
private int anim_height;
public FlexibleWindowCtrl flexibleLayout;
public String[] anim_list;
public AnimData[] anim_queue;
public FrameCtrl anim_frame;
public int anim_fps;
public float f_time; // Duration(Sec) per frame


/** Initialize an ArkPets character.
* @param $fp_atlas The file path of the atlas file.
Expand All @@ -75,7 +73,6 @@ public ArkChar(String $fp_atlas, String $fp_skel, float $anim_scale) {
positionCur = new Vector3(0, 0, 0);
positionTar = new Vector3(0, 0, 0);
offset_y = 0;
transform = new Matrix4();
anim_queue = new AnimData[2];

// Transfer params
Expand Down Expand Up @@ -135,22 +132,51 @@ public void setCanvas(int $anim_width, int $anim_height, int $anim_fps) {
*/
public void setCanvas(int $anim_width, int $anim_height, int $anim_fps, Color $bgColor) {
// Transfer params
anim_width = $anim_width;
anim_height = $anim_height;
flexibleLayout = new FlexibleWindowCtrl(
new Vector2($anim_width, $anim_height),
($anim_width + $anim_height) / 4
);
anim_fps = $anim_fps;
// Set position (center)
setPositionTar(anim_width / 2f, 0, 1);
camera.setToOrtho(false, anim_width, anim_height);
camera.update();
batch.getProjectionMatrix().set(camera.combined);
transform = batch.getTransformMatrix();
setPositionTar(MAX_SKELETON_SIZE * 0.5f, 0, 1);
updateCanvas();
// Set background image
Pixmap pixmap = new Pixmap($anim_width, $anim_height, Format.RGBA8888);
pixmap.setColor($bgColor);
pixmap.fill();
bgTexture = new Texture(pixmap);
}

/** Fix the canvas size to make it adapted to the animation.
*/
public void fixCanvasSize() {
if (!flexibleLayout.fixToBestCroppedSize(getCurrentTexture(false), 15, 30, 5, false, true))
return;
System.out.println(
"^"+flexibleLayout.curInsert.top+
"\tv"+flexibleLayout.curInsert.bottom+
"\t<"+flexibleLayout.curInsert.left+
"\t>"+flexibleLayout.curInsert.right
);
//if (anim_frame != null)
//PixmapIO.writePNG(new FileHandle("temp").child("temp" + (anim_frame.F_CUR % 50 + 1) + ".png"), getCurrentTexture(true));
//PixmapIO.writePNG(new FileHandle("temp.png"), getCurrentTexture(true));
//updateCanvas();
}

/** Update the canvas and the camera.
* If you didn't update the canvas in properly, unexpected rendering may cause.
*/
public void updateCanvas() {
camera.setToOrtho(false, flexibleLayout.getWidth(), flexibleLayout.getHeight());
camera.translate(
((MAX_SKELETON_SIZE - flexibleLayout.getHeight()) >> 1) - flexibleLayout.curInsert.left,
-flexibleLayout.curInsert.top
); // Translated X = (Canvas - Camera) / 2 - Insert
camera.update();
batch.getProjectionMatrix().set(camera.combined);
}

/** Set the target position.
* @param $pos_x
* @param $pos_y
Expand All @@ -169,7 +195,11 @@ public void setPositionTar(float $pos_x, float $pos_y, float $flip) {
*/
public void setPositionCur(float $deltaTime) {
// Set current position
positionCur.set(positionEas.eX.step($deltaTime), positionEas.eY.step($deltaTime), positionEas.eZ.step($deltaTime));
positionCur.set(
positionEas.eX.step($deltaTime),
positionEas.eY.step($deltaTime),
positionEas.eZ.step($deltaTime)
);
skeleton.setPosition(positionCur.x, positionCur.y);
skeleton.setScaleX(positionCur.z);
skeleton.updateWorldTransform();
Expand All @@ -187,46 +217,50 @@ public boolean setAnimation(AnimData $animData) {
return false;
}

/** Render a specified frame to a byte buffer.
* @param $frame
* @return ByteBuffer object.
/** Get the current framebuffer contents as a Pixmap.
* Note that the image may not be flipped along the y-axis.
* @param debug Whether to show debug additions in the pixmap.
* @return Pixmap object.
*/
public ByteBuffer toBuffer(int $frame) {
// Apply Animation
animation.apply(skeleton, ($frame - 1) * f_time, ($frame - 1) * f_time, false, null, 1, MixBlend.first, MixDirection.in);
skeleton.updateWorldTransform();
// Render the skeleton to the FBO
ScreenUtils.clear(0, 0, 0, 0);
batch.begin();
renderer.draw(batch, skeleton);
batch.end();
// Copy the FBO to a pixmap
Pixmap pixmap = new Pixmap(200, 200, Format.RGBA8888);
Gdx.gl.glPixelStorei(GL20.GL_PACK_ALIGNMENT, 1);
Gdx.gl.glReadPixels(0, 0, anim_width, anim_height,
GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixmap.getPixels());
// Convert to byte buffer
return pixmap.getPixels();
public Pixmap getCurrentTexture(boolean debug) {
Pixmap pixmap = lastTexture == null ? Pixmap.createFromFrameBuffer(0, 0, flexibleLayout.getWidth(), flexibleLayout.getHeight()) : lastTexture;
if (debug) {
pixmap.setColor(new Color(1, 0, 0, 0.75f));
if (flexibleLayout.curInsert.bottom > 0)
pixmap.drawRectangle(0, 0, pixmap.getWidth(), flexibleLayout.curInsert.bottom);
if (flexibleLayout.curInsert.top > 0)
pixmap.drawRectangle(0, pixmap.getHeight() - flexibleLayout.curInsert.top, pixmap.getWidth(), flexibleLayout.curInsert.top);
if (flexibleLayout.curInsert.left > 0)
pixmap.drawRectangle(0, 0, flexibleLayout.curInsert.left, pixmap.getHeight());
if (flexibleLayout.curInsert.right > 0)
pixmap.drawRectangle(pixmap.getWidth() - flexibleLayout.curInsert.right, 0, flexibleLayout.curInsert.right, pixmap.getHeight());
}
return pixmap;
}

/** Render the animation to batch.
* @param $frame
*/
public void toScreen(int $frame) {
public void toScreen() {
// Apply Animation
setPositionTar(positionTar.x, positionTar.y, positionTar.z);
setPositionCur(Gdx.graphics.getDeltaTime());
animationState.apply(skeleton);
animationState.update(Gdx.graphics.getDeltaTime());
// OLD METHOD: animation.apply(skeleton, ($frame - 1) * anim_frame.F_TIME, ($frame - 1) * anim_frame.F_TIME, false, null, 1, MixBlend.first, MixDirection.in);
skeleton.updateWorldTransform();
// Render the skeleton to the FBO
// Render the skeleton to the batch
updateCanvas();
ScreenUtils.clear(0, 0, 0, 0, true);
batch.begin();
if (bgTexture != null)
batch.draw(bgTexture, 0, 0);
renderer.draw(batch, skeleton);
batch.end();
// Write the current graphic texture to cache
lastTexture = new Pixmap(flexibleLayout.getWidth(), flexibleLayout.getHeight(), Format.RGBA8888);
Gdx.gl.glPixelStorei(GL20.GL_PACK_ALIGNMENT, 1);
Gdx.gl.glReadPixels(0, 0, flexibleLayout.getWidth(), flexibleLayout.getHeight(),
GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, lastTexture.getPixels());
}

/** Render the next frame.
Expand Down Expand Up @@ -257,7 +291,7 @@ public void next() {
}
}
// Render the next frame
toScreen(anim_frame.F_CUR);
toScreen();
}

private void changeAnimation() {
Expand Down
59 changes: 32 additions & 27 deletions core/src/com/isharryh/arkpets/ArkPets.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@
import com.badlogic.gdx.InputProcessor;

import java.util.ArrayList;
import java.util.Objects;

import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.platform.win32.WinDef.HWND;

import com.isharryh.arkpets.utils.*;
import com.isharryh.arkpets.behaviors.*;
import com.isharryh.arkpets.utils.AnimData;
import com.isharryh.arkpets.utils.HWndCtrl;
import com.isharryh.arkpets.utils.LoopCtrl;
import com.isharryh.arkpets.utils.Plane;
import com.isharryh.arkpets.easings.EasingLinear;
import com.isharryh.arkpets.easings.EasingLinearVector2;

Expand Down Expand Up @@ -59,34 +58,34 @@ public void create() {
Gdx.app.setLogLevel(3);
Gdx.app.log("event", "AP:Create");
Gdx.input.setInputProcessor(this);
config = ArkConfig.getConfig();
config = Objects.requireNonNull(ArkConfig.getConfig());
APP_FPS = config.display_fps;
Gdx.graphics.setForegroundFPS(APP_FPS);
getHWndLoopCtrl = new LoopCtrl(1.0f / APP_FPS * 12);
ScreenUtils.clear(0, 0, 0, 0, true);
// 2.Window setup
// 2.Character setup
int WD_ORI_W = 140; // Window Origin Width
int WD_ORI_H = 160; // Window Origin Height
cha = new ArkChar(config.character_recent+".atlas", config.character_recent+".skel", 0.33f);
cha.setCanvas(WD_ORI_W, WD_ORI_H, APP_FPS);
// 3.Window params setup
WD_poscur = new Vector2(0, 0);
WD_postar = new Vector2(0, 0);
WD_poseas = new EasingLinearVector2(new EasingLinear(0, 1, 0.2f));
WD_SCALE = config.display_scale;
int WD_ORI_W = 140; // Window Origin Width
int WD_ORI_H = 160; // Window Origin Height
WD_W = (int) (WD_SCALE * WD_ORI_W);
WD_H = (int) (WD_SCALE * WD_ORI_H);
WD_W = (int)(WD_SCALE * cha.flexibleLayout.getWidth());
WD_H = (int)(WD_SCALE * cha.flexibleLayout.getHeight());
SCR_W = config.display_monitor_info[0];
SCR_H = config.display_monitor_info[1];
APP_FPS = config.display_fps;
getHWndLoopCtrl = new LoopCtrl(1f / APP_FPS * 4);
intiWindow(100, SCR_H / 2);
setWindowPosTar(100, SCR_H / 2f);
Gdx.graphics.setForegroundFPS(APP_FPS);
// 3.Plane setup
setWindowPosTar(100, SCR_H / 2.0f);
// 4.Plane setup
plane = new Plane(SCR_W, config.display_margin_bottom-SCR_H, SCR_H * 0.75f);
plane.setFrict(SCR_W * 0.05f, SCR_W * 0.25f);
plane.setBounce(0);
plane.setObjSize(WD_W, -WD_H);
plane.setSpeedLimit(SCR_W * 0.5f, SCR_H * 1f);
plane.setSpeedLimit(SCR_W * 0.5f, SCR_H * 1.0f);
plane.changePosition(0, WD_postar.x, -WD_postar.y);
// 4.Character setup
cha = new ArkChar(config.character_recent+".atlas", config.character_recent+".skel", 0.33f);
cha.setCanvas(WD_ORI_W, WD_ORI_H, APP_FPS);
// 5.Behavior setup
if (BehaviorOperBuild2.match(cha.anim_list))
behavior = new BehaviorOperBuild2(config);
Expand All @@ -109,6 +108,7 @@ else if (BehaviorOperBuild3.match(cha.anim_list))
@Override
public void render() {
// 1.Render the next frame.
cha.fixCanvasSize();
cha.next();
if (cha.anim_frame.F_CUR == cha.anim_frame.F_MAX) {
Gdx.app.log("info", "FPS" + Gdx.graphics.getFramesPerSecond() + ", Heap" + (int) (Gdx.app.getJavaHeap() / 1024) + "KB");
Expand Down Expand Up @@ -245,18 +245,20 @@ private boolean intiWindow(int x, int y) {
// | WinUser.WS_EX_LAYERED | WinUser.WS_EX_TRANSPARENT;
//System.out.println(User32.INSTANCE.GetWindowLong(hwnd, WinUser.GWL_EXSTYLE));
//User32.INSTANCE.SetWindowLong(HWND_MINE, WinUser.GWL_EXSTYLE, enable ? WL_TRAN_ON : WL_TRAN_OFF);
User32.INSTANCE.SetWindowLong(HWND_MINE, WinUser.GWL_EXSTYLE, 0x00000088);
User32.INSTANCE.SetWindowPos(HWND_MINE, HWND_TOPMOST, x, y,
WD_W, WD_H, WinUser.SWP_FRAMECHANGED);
User32.INSTANCE.SetWindowPos(HWND_MINE, HWND_TOPMOST, x, y,
WD_W, WD_H, WinUser.SWP_NOSIZE);
User32.INSTANCE.SetWindowPos(HWND_MINE, HWND_TOPMOST,
x, y, WD_W, WD_H,
WinUser.SWP_SHOWWINDOW | WinUser.SWP_NOACTIVATE
);
Gdx.app.debug("debug", "JNA SetWindowLong returns " + Integer.toHexString(User32.INSTANCE.SetWindowLong(HWND_MINE, WinUser.GWL_EXSTYLE, 0x00000088)));
return true;
}

private boolean setWindowPos(int x, int y, boolean override) {
if (HWND_MINE == null)
return false;
if (getHWndLoopCtrl.isExecutable(Gdx.graphics.getDeltaTime())) {
WD_W = (int)(WD_SCALE * cha.flexibleLayout.getWidth());
WD_H = (int)(WD_SCALE * cha.flexibleLayout.getHeight());
HWND new_hwnd_topmost = refreshWindowIdx();
if (new_hwnd_topmost != HWND_TOPMOST) {
HWND_TOPMOST = new_hwnd_topmost;
Expand All @@ -275,8 +277,11 @@ private boolean setWindowPos(int x, int y, boolean override) {
WD_poseas.eX.curDuration = WD_poseas.eX.DURATION;
WD_poseas.eY.curDuration = WD_poseas.eY.DURATION;
}
User32.INSTANCE.SetWindowPos(HWND_MINE, HWND_TOPMOST, (int)WD_poscur.x, (int)WD_poscur.y,
0, 0, WinUser.SWP_NOSIZE);
User32.INSTANCE.SetWindowPos(HWND_MINE, HWND_TOPMOST,
(int)WD_poscur.x - cha.flexibleLayout.curInsert.left,
(int)WD_poscur.y,
WD_W, WD_H, WinUser.SWP_NOACTIVATE
);
return true;
}

Expand Down Expand Up @@ -360,7 +365,7 @@ private int getArkPetsWindowNum(String title) {

/* WINDOW OPERATION RELATED */
private void walkWindow(float len) {
float expectedLen = len * WD_SCALE * (30f / APP_FPS);
float expectedLen = len * WD_SCALE * (30.0f / APP_FPS);
int realLen = randomRound(expectedLen);
plane.changePosition(Gdx.graphics.getDeltaTime(), WD_postar.x + realLen, -WD_postar.y);
}
Expand Down
Loading

0 comments on commit 4aa567b

Please sign in to comment.