Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ee028248d | ||
|
|
84cc693593 |
@@ -16,6 +16,7 @@ FaceApp* g_Application = nullptr;
|
|||||||
AAssetManager* g_assetManager = nullptr;
|
AAssetManager* g_assetManager = nullptr;
|
||||||
|
|
||||||
jobject g_callback = nullptr;
|
jobject g_callback = nullptr;
|
||||||
|
jobject g_callbackAnimationFinished = nullptr;
|
||||||
|
|
||||||
void handle_cmd(android_app *pApp, int32_t cmd) {
|
void handle_cmd(android_app *pApp, int32_t cmd) {
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
@@ -149,22 +150,7 @@ Java_com_hmwl_face_1sdk_FaceActivity_SetCppInitArg(JNIEnv *env, jobject thiz, js
|
|||||||
}
|
}
|
||||||
memcpy(g_InitArgString, nativeString, len);
|
memcpy(g_InitArgString, nativeString, len);
|
||||||
}
|
}
|
||||||
extern "C"
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_com_hmwl_face_1sdk_FaceActivity_ChangeStateCpp(JNIEnv *env, jobject thiz, jstring json) {
|
|
||||||
// TODO: implement ChangeStateCpp()
|
|
||||||
const char *nativeString = env->GetStringUTFChars(json, nullptr);
|
|
||||||
jsize len = env->GetStringUTFLength(json);
|
|
||||||
if(len > ArgLen)
|
|
||||||
{
|
|
||||||
aout << "ArgLen to long:" << len << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(g_Application->isInited())
|
|
||||||
{
|
|
||||||
g_Application->changeMotion(nativeString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_com_hmwl_face_1sdk_FaceActivity_StopRunning(JNIEnv *env, jobject thiz) {
|
Java_com_hmwl_face_1sdk_FaceActivity_StopRunning(JNIEnv *env, jobject thiz) {
|
||||||
@@ -241,6 +227,63 @@ void CppCallback(const string& motion_type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CppAnimationFinishedCallback()
|
||||||
|
{
|
||||||
|
JNIEnv* env = nullptr;
|
||||||
|
bool needDetach = false;
|
||||||
|
|
||||||
|
// 获取当前线程的 JNIEnv
|
||||||
|
JavaVM* vm = g_jvm; // 你需要提前保存 JavaVM* 到全局变量 g_jvm
|
||||||
|
int status = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
|
||||||
|
if (status == JNI_EDETACHED) {
|
||||||
|
// 当前线程未 attach,需 attach
|
||||||
|
if (vm->AttachCurrentThread(&env, nullptr) != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
needDetach = true;
|
||||||
|
} else if (status != JNI_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_callbackAnimationFinished == nullptr) {
|
||||||
|
if (needDetach) vm->DetachCurrentThread();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 获取 CallbackInterface 的 class
|
||||||
|
jclass callbackClass = env->GetObjectClass(g_callbackAnimationFinished);
|
||||||
|
if (callbackClass == nullptr) {
|
||||||
|
if (needDetach) vm->DetachCurrentThread();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 获取 OnLoadActionFinished 方法 ID(注意方法名大小写必须一致!)
|
||||||
|
jmethodID methodId = env->GetMethodID(callbackClass, "OnAnimationFinished", "()V");
|
||||||
|
if (methodId == nullptr) {
|
||||||
|
env->ExceptionDescribe(); // 打印异常
|
||||||
|
env->ExceptionClear();
|
||||||
|
if (needDetach) vm->DetachCurrentThread();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 调用 Java 回调
|
||||||
|
env->CallVoidMethod(g_callbackAnimationFinished, methodId);
|
||||||
|
|
||||||
|
// 5. 检查是否抛出异常
|
||||||
|
if (env->ExceptionCheck()) {
|
||||||
|
env->ExceptionDescribe();
|
||||||
|
env->ExceptionClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
env->DeleteLocalRef(callbackClass);
|
||||||
|
|
||||||
|
// 7. 如果是临时 attach 的线程,要 detach
|
||||||
|
if (needDetach) {
|
||||||
|
vm->DetachCurrentThread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jstring JNICALL
|
||||||
@@ -269,3 +312,30 @@ Java_com_hmwl_face_1sdk_FaceActivity_PreReadAction(JNIEnv *env, jobject thiz, js
|
|||||||
std::string ret = g_Application->preReadyMotion(nativeString, CppCallback);
|
std::string ret = g_Application->preReadyMotion(nativeString, CppCallback);
|
||||||
return env->NewStringUTF(ret.c_str());
|
return env->NewStringUTF(ret.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_com_hmwl_face_1sdk_FaceActivity_ChangeMotionCpp(JNIEnv *env, jobject thiz, jstring json,
|
||||||
|
jobject callback, jboolean loop) {
|
||||||
|
// TODO: implement ChangeMotionCpp()
|
||||||
|
const char *nativeString = env->GetStringUTFChars(json, nullptr);
|
||||||
|
jsize len = env->GetStringUTFLength(json);
|
||||||
|
if(len > ArgLen)
|
||||||
|
{
|
||||||
|
aout << "ArgLen to long:" << len << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存新的回调
|
||||||
|
if (callback != nullptr) {
|
||||||
|
g_callbackAnimationFinished = env->NewGlobalRef(callback);
|
||||||
|
} else {
|
||||||
|
g_callbackAnimationFinished = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(g_Application->isInited())
|
||||||
|
{
|
||||||
|
g_Application->changeMotion(nativeString, CppAnimationFinishedCallback, loop);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,6 +50,21 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
|
||||||
|
if (requestCode == REQUEST_CAMERA_PERMISSION) {
|
||||||
|
// 检查权限是否被授予
|
||||||
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
// 用户授予了权限,启动相机
|
||||||
|
startCamera();
|
||||||
|
} else {
|
||||||
|
requestCameraPermission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void startCamera() {
|
private void startCamera() {
|
||||||
ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
|
ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
|
||||||
ProcessCameraProvider.getInstance(this);
|
ProcessCameraProvider.getInstance(this);
|
||||||
@@ -276,15 +291,19 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
void OnLoadActionFinished(String result);
|
void OnLoadActionFinished(String result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface AnimationFinishedCallbackInterface {
|
||||||
|
void OnAnimationFinished();
|
||||||
|
}
|
||||||
|
|
||||||
protected native String PreReadAction(String motion, CallbackInterface callback);
|
protected native String PreReadAction(String motion, CallbackInterface callback);
|
||||||
protected String PreLoadAction(String json, CallbackInterface callback){
|
protected String PreLoadAction(String json, CallbackInterface callback){
|
||||||
return PreReadAction(json, callback);
|
return PreReadAction(json, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected native void ChangeStateCpp(String json);
|
protected native void ChangeMotionCpp(String json, AnimationFinishedCallbackInterface callback, boolean loop);
|
||||||
protected void ChangeMotion(String json){
|
protected void ChangeMotion(String json, AnimationFinishedCallbackInterface callback, boolean loop){
|
||||||
Log.i("FaceActivity", "ChangeState:" + json);
|
Log.i("FaceActivity", "ChangeState:" + json);
|
||||||
ChangeStateCpp(json);
|
ChangeMotionCpp(json, callback, loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加这个缺失的方法
|
// 添加这个缺失的方法
|
||||||
|
|||||||
@@ -80,4 +80,7 @@ dependencies {
|
|||||||
implementation 'com.google.flogger:flogger-system-backend:0.7.4'
|
implementation 'com.google.flogger:flogger-system-backend:0.7.4'
|
||||||
|
|
||||||
implementation 'com.google.guava:guava:31.1-android'
|
implementation 'com.google.guava:guava:31.1-android'
|
||||||
|
|
||||||
|
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7") // 提供 lifecycleScope
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
|
||||||
}
|
}
|
||||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -71,13 +71,38 @@
|
|||||||
"7.png"
|
"7.png"
|
||||||
],
|
],
|
||||||
"11": [
|
"11": [
|
||||||
"11.png"
|
"002.png",
|
||||||
|
"003.png",
|
||||||
|
"004.png",
|
||||||
|
"005.png",
|
||||||
|
"006.png",
|
||||||
|
"007.png",
|
||||||
|
"008.png",
|
||||||
|
"009.png",
|
||||||
|
"010.png",
|
||||||
|
"011.png",
|
||||||
|
"11.png",
|
||||||
|
"012.png"
|
||||||
],
|
],
|
||||||
"12": [
|
"12": [
|
||||||
"12.png"
|
"12.png"
|
||||||
],
|
],
|
||||||
"13": [
|
"13": [
|
||||||
"13.png"
|
"001.png",
|
||||||
|
"002.png",
|
||||||
|
"003.png",
|
||||||
|
"004.png",
|
||||||
|
"005.png",
|
||||||
|
"006.png",
|
||||||
|
"007.png",
|
||||||
|
"008.png",
|
||||||
|
"009.png",
|
||||||
|
"010.png",
|
||||||
|
"011.png",
|
||||||
|
"012.png",
|
||||||
|
"013.png",
|
||||||
|
"13.png",
|
||||||
|
"014.png"
|
||||||
],
|
],
|
||||||
"14": [
|
"14": [
|
||||||
"14.png"
|
"14.png"
|
||||||
|
|||||||
@@ -4,11 +4,16 @@ package com.inewme.uvmirror
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.KeyEvent.KEYCODE_BACK
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.widget.Toast
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.hmwl.face_sdk.FaceActivity
|
import com.hmwl.face_sdk.FaceActivity
|
||||||
import com.hmwl.face_sdk.InitArg
|
import com.hmwl.face_sdk.InitArg
|
||||||
import com.hmwl.face_sdk.Motion
|
import com.hmwl.face_sdk.Motion
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
@@ -16,8 +21,43 @@ import java.io.InputStreamReader
|
|||||||
|
|
||||||
class MakeupActivity : FaceActivity()
|
class MakeupActivity : FaceActivity()
|
||||||
{
|
{
|
||||||
private var curIndex = 0
|
var isLoadFinished: Boolean = false;
|
||||||
private var pngFilesByFolder: List<FolderInfo>? = null
|
var isMotionFinished: Boolean = true;
|
||||||
|
var _motionIndex : Int = 0
|
||||||
|
|
||||||
|
|
||||||
|
var animationFinishedFun = object : AnimationFinishedCallbackInterface {
|
||||||
|
override fun OnAnimationFinished() {
|
||||||
|
isMotionFinished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var loadFinishedFun = object : CallbackInterface {
|
||||||
|
override fun OnLoadActionFinished(motion_type: String) {
|
||||||
|
isLoadFinished = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private val motionQueue: MutableList<String> = mutableListOf()
|
||||||
|
fun PlayMotionQueue(motions: List<String>)
|
||||||
|
{
|
||||||
|
for (m in motions) {
|
||||||
|
var motion = getMotionByName(m);
|
||||||
|
var motionJsonString = motion.toJson();
|
||||||
|
motionQueue.add(motionJsonString)
|
||||||
|
}
|
||||||
|
//开始播放动画的时候需要先加载第一个动画
|
||||||
|
isLoadFinished = false;
|
||||||
|
_motionIndex = 0;
|
||||||
|
PreLoadAction(motionQueue[_motionIndex], loadFinishedFun)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var updateJob: Job? = null
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
||||||
@@ -32,78 +72,69 @@ class MakeupActivity : FaceActivity()
|
|||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
var motion = getMotionByIndex(0);
|
|
||||||
var motionJsonString = motion.toJson()
|
// 启动一个生命周期感知的协程
|
||||||
val result = PreLoadAction(motionJsonString,object : CallbackInterface {
|
updateJob = lifecycleScope.launch {
|
||||||
override fun OnLoadActionFinished(motion_type: String) {
|
while (true) {
|
||||||
//加载完成后,切断到对应的动画
|
update()
|
||||||
Log.i("info","加载完成后,切换到对应的动画")
|
delay(10) // 每 10 毫秒执行一次
|
||||||
ChangeMotion(motion_type)
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
Toast.makeText(this, "开始加载动画: $result", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMotionByIndex(index: Int): Motion {
|
}
|
||||||
pngFilesByFolder?.let { folders ->
|
|
||||||
|
private fun update()
|
||||||
|
{
|
||||||
|
//下一个动画加载完成,并且当前动画已经播放完了 (刚开始的时候当前动画初始化为播放完成)
|
||||||
|
if(isLoadFinished && isMotionFinished)
|
||||||
|
{
|
||||||
|
//切换到加载完成的动画
|
||||||
|
isMotionFinished = false
|
||||||
|
ChangeMotion(motionQueue[_motionIndex], animationFinishedFun, false)
|
||||||
|
|
||||||
|
isLoadFinished = false
|
||||||
|
|
||||||
|
//如果还有动画,则开始预先加载
|
||||||
|
if(_motionIndex + 1 < motionQueue.size)
|
||||||
|
{
|
||||||
|
_motionIndex += 1
|
||||||
|
PreLoadAction(motionQueue[_motionIndex], loadFinishedFun)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
|
if (keyCode == KEYCODE_BACK) {
|
||||||
|
Log.d("MakeupActivity", "Back key pressed")
|
||||||
|
handleBackPress()
|
||||||
|
return true // 消费事件,防止默认行为(如直接 finish)
|
||||||
|
}
|
||||||
|
return super.onKeyDown(keyCode, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleBackPress() {
|
||||||
|
Stop()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun getMotionByName(m: String): Motion {
|
||||||
val motion = Motion().apply {
|
val motion = Motion().apply {
|
||||||
type = folders[index].folderName
|
type = m
|
||||||
png_names = folders[index].fileList
|
png_names = pngFilesByFolder?.get(m)?.fileList
|
||||||
}
|
}
|
||||||
return motion
|
return motion
|
||||||
}
|
}
|
||||||
return Motion()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getCurMotionState(index: Int): String {
|
|
||||||
pngFilesByFolder?.let { folders ->
|
|
||||||
val motion = Motion().apply {
|
|
||||||
type = folders[index].folderName
|
|
||||||
png_names = folders[index].fileList
|
|
||||||
}
|
|
||||||
return motion.toJson()
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var nextMotionLoadFinished = false
|
|
||||||
var nextMotionType = ""
|
|
||||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||||
when (event.action) {
|
when (event.action) {
|
||||||
MotionEvent.ACTION_DOWN -> {
|
|
||||||
pngFilesByFolder?.let { folders ->
|
|
||||||
if (curIndex > folders.size - 1) {
|
|
||||||
//动画播放完成,切换到主界面
|
|
||||||
curIndex = 0
|
|
||||||
Stop();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MotionEvent.ACTION_UP -> {
|
MotionEvent.ACTION_UP -> {
|
||||||
if (!nextMotionLoadFinished)
|
val motions: List<String> = listOf("4", "11", "13")
|
||||||
{
|
PlayMotionQueue(motions)
|
||||||
var nextMotion = getMotionByIndex(curIndex + 1);
|
|
||||||
var json_str = nextMotion.toJson()
|
|
||||||
PreLoadAction(json_str,object : CallbackInterface {
|
|
||||||
override fun OnLoadActionFinished(motion_type: String) {
|
|
||||||
Log.i("info","加载完成后,还会继续播放当前的动画,可以手动切换动画")
|
|
||||||
nextMotionLoadFinished = true;
|
|
||||||
nextMotionType = motion_type;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Toast.makeText(this, "开始加载下一个动画 ${nextMotion.type}", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//手动切换动画
|
|
||||||
ChangeMotion(nextMotionType);
|
|
||||||
nextMotionLoadFinished = false;
|
|
||||||
curIndex++;
|
|
||||||
Toast.makeText(this, "切换到下一个动画 $nextMotionType", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -114,8 +145,8 @@ class MakeupActivity : FaceActivity()
|
|||||||
val fileList: List<String>
|
val fileList: List<String>
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun readPngFilenamesFromAssets(context: Context, filename: String): List<FolderInfo> {
|
private fun readPngFilenamesFromAssets(context: Context, filename: String): Map<String,FolderInfo> {
|
||||||
val folderList = mutableListOf<FolderInfo>()
|
val folderMap = mutableMapOf<String, FolderInfo>()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
context.assets.open(filename).use { inputStream ->
|
context.assets.open(filename).use { inputStream ->
|
||||||
@@ -138,7 +169,7 @@ class MakeupActivity : FaceActivity()
|
|||||||
filesInFolder.add(fileArray.getString(i))
|
filesInFolder.add(fileArray.getString(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
folderList.add(FolderInfo(folderName, filesInFolder))
|
folderMap[folderName] = (FolderInfo(folderName, filesInFolder))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,9 +177,10 @@ class MakeupActivity : FaceActivity()
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
return folderList
|
return folderMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var pngFilesByFolder: Map<String, FolderInfo>? = null
|
||||||
private fun FaceInit(context: Context) {
|
private fun FaceInit(context: Context) {
|
||||||
pngFilesByFolder = readPngFilenamesFromAssets(context, "pic/motion_data.json")
|
pngFilesByFolder = readPngFilenamesFromAssets(context, "pic/motion_data.json")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1321,9 +1321,21 @@ void FaceApp::drawFrame(long long frameTime)
|
|||||||
{
|
{
|
||||||
_curTexIndex++;
|
_curTexIndex++;
|
||||||
if (_curTexIndex >= _curMotion_png_size)
|
if (_curTexIndex >= _curMotion_png_size)
|
||||||
|
{
|
||||||
|
if(_animationFinishedCallback != nullptr)
|
||||||
|
{
|
||||||
|
_animationFinishedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_animationLoop)
|
||||||
{
|
{
|
||||||
_curTexIndex = 0;
|
_curTexIndex = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_curTexIndex = _curMotion_png_size - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
game_time = game_time - actionTime;
|
game_time = game_time - actionTime;
|
||||||
}
|
}
|
||||||
Application::drawFrame(frameTime);
|
Application::drawFrame(frameTime);
|
||||||
@@ -1357,7 +1369,7 @@ string FaceApp::preReadyMotion(const std::string& json, Callback callback)
|
|||||||
return "failure";
|
return "failure";
|
||||||
}
|
}
|
||||||
|
|
||||||
void FaceApp::changeMotion(const string motion_type)
|
void FaceApp::changeMotion(const string motion_type, AnimationFinishedCallback callback, bool loop)
|
||||||
{
|
{
|
||||||
if (_curMotion_type == motion_type)
|
if (_curMotion_type == motion_type)
|
||||||
{
|
{
|
||||||
@@ -1387,6 +1399,9 @@ void FaceApp::changeMotion(const string motion_type)
|
|||||||
_curMotion_type = motion_type;
|
_curMotion_type = motion_type;
|
||||||
_curMotion_png_size = _nextMotion.png_names.size();
|
_curMotion_png_size = _nextMotion.png_names.size();
|
||||||
_motionState = ready;
|
_motionState = ready;
|
||||||
|
_animationFinishedCallback = callback;
|
||||||
|
_animationLoop = loop;
|
||||||
|
_curTexIndex = 0;
|
||||||
|
|
||||||
|
|
||||||
// for (int i = 0; i < _curMotion.png_names.size(); ++i)
|
// for (int i = 0; i < _curMotion.png_names.size(); ++i)
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ struct PushConstants {
|
|||||||
};
|
};
|
||||||
|
|
||||||
using Callback = std::function<void(const std::string&)>;
|
using Callback = std::function<void(const std::string&)>;
|
||||||
|
using AnimationFinishedCallback = std::function<void()>;
|
||||||
|
|
||||||
class FaceApp :public Application
|
class FaceApp :public Application
|
||||||
{
|
{
|
||||||
@@ -139,8 +140,10 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Callback _callback;
|
Callback _callback;
|
||||||
|
AnimationFinishedCallback _animationFinishedCallback;
|
||||||
|
bool _animationLoop = true;
|
||||||
string preReadyMotion(const std::string& json, Callback callback);
|
string preReadyMotion(const std::string& json, Callback callback);
|
||||||
void changeMotion(const string motion_type);
|
void changeMotion(const string motion_type, AnimationFinishedCallback callback, bool loop);
|
||||||
//void changeMotion(Motion& motion);
|
//void changeMotion(Motion& motion);
|
||||||
InitArg _initArg;
|
InitArg _initArg;
|
||||||
//Motion _curMotion;
|
//Motion _curMotion;
|
||||||
|
|||||||
@@ -41,11 +41,18 @@ std::wstring ReadFileWithChinesePath(const std::wstring& filePath) {
|
|||||||
|
|
||||||
FaceApp* g_app;
|
FaceApp* g_app;
|
||||||
|
|
||||||
|
|
||||||
|
void CppAnimationFinishedCallback()
|
||||||
|
{
|
||||||
|
std::cout << "call CppAnimationFinishedCallback\n";
|
||||||
|
}
|
||||||
|
|
||||||
void CppCallback(const string& motion_type)
|
void CppCallback(const string& motion_type)
|
||||||
{
|
{
|
||||||
g_app->changeMotion(motion_type.c_str());
|
g_app->changeMotion(motion_type.c_str(), CppAnimationFinishedCallback, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
//std::string path = "chinese.txt";
|
//std::string path = "chinese.txt";
|
||||||
|
|||||||