Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da2c97e412 | ||
|
|
db80a5dbbd | ||
|
|
634d22f3be | ||
|
|
835f768a4a | ||
|
|
1859706412 | ||
|
|
9c71e40c97 | ||
|
|
84d567674f | ||
|
|
43b00c8446 | ||
|
|
e23ccd75cd | ||
|
|
8623b71ab7 | ||
|
|
16efcbcff3 |
@@ -1,7 +1,8 @@
|
|||||||
plugins {
|
plugins {
|
||||||
//alias(libs.plugins.android.application)
|
//alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.android.library)
|
alias(libs.plugins.android.library)
|
||||||
id 'org.jetbrains.kotlin.android'
|
alias(libs.plugins.kotlin.android)
|
||||||
|
//id 'org.jetbrains.kotlin.android'
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.vvl_version='1.4.321.0'
|
ext.vvl_version='1.4.321.0'
|
||||||
@@ -30,6 +31,17 @@ android {
|
|||||||
debug {
|
debug {
|
||||||
debuggable true
|
debuggable true
|
||||||
jniDebuggable true
|
jniDebuggable true
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
arguments "-DCMAKE_BUILD_TYPE=Debug"
|
||||||
|
cppFlags "-DDEBUG -O0 -g"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ndk {
|
||||||
|
debugSymbolLevel 'FULL' // Debug 版本包含完整符号
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
release {
|
release {
|
||||||
@@ -43,13 +55,13 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 添加 Kotlin 编译选项
|
// 添加 Kotlin 编译选项
|
||||||
kotlinOptions {
|
// kotlinOptions {
|
||||||
jvmTarget = '17' // 与 Java 版本保持一致
|
// jvmTarget = '17' // 与 Java 版本保持一致
|
||||||
}
|
// }
|
||||||
|
|
||||||
kotlin {
|
// kotlin {
|
||||||
jvmToolchain(21)
|
// jvmToolchain(17)
|
||||||
}
|
// }
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
prefab true
|
prefab true
|
||||||
@@ -62,10 +74,10 @@ android {
|
|||||||
'libs/tasks-vision/jni',
|
'libs/tasks-vision/jni',
|
||||||
'libs/tasks-core/jni'
|
'libs/tasks-core/jni'
|
||||||
]
|
]
|
||||||
java.srcDirs += [
|
//java.srcDirs += [
|
||||||
'libs/tasks-vision/vision_classes',
|
// 'libs/tasks-vision/vision_classes',
|
||||||
'libs/tasks-core/core_classes'
|
// 'libs/tasks-core/core_classes'
|
||||||
]
|
//]
|
||||||
res.srcDirs += [
|
res.srcDirs += [
|
||||||
'libs/tasks-vision/res',
|
'libs/tasks-vision/res',
|
||||||
'libs/tasks-core/res'
|
'libs/tasks-core/res'
|
||||||
@@ -79,6 +91,13 @@ android {
|
|||||||
version '3.22.1'
|
version '3.22.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packagingOptions {
|
||||||
|
pickFirst '**/*.jar'
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = '17'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -86,16 +105,17 @@ dependencies {
|
|||||||
implementation libs.appcompat
|
implementation libs.appcompat
|
||||||
implementation libs.material
|
implementation libs.material
|
||||||
implementation libs.games.activity
|
implementation libs.games.activity
|
||||||
|
implementation libs.androidx.core.core.ktx
|
||||||
testImplementation libs.junit
|
testImplementation libs.junit
|
||||||
androidTestImplementation libs.ext.junit
|
androidTestImplementation libs.ext.junit
|
||||||
androidTestImplementation libs.espresso.core
|
androidTestImplementation libs.espresso.core
|
||||||
|
|
||||||
|
|
||||||
//implementation 'com.google.protobuf:protobuf-javalite:3.21.12'
|
implementation 'com.google.protobuf:protobuf-javalite:3.21.12'
|
||||||
//implementation files('libs/tasks-vision.jar', 'libs/tasks-core.jar')
|
implementation files('libs/tasks-vision.jar', 'libs/tasks-core.jar')
|
||||||
|
|
||||||
implementation fileTree(dir: 'libs/tasks-vision', include: ['*.jar'])
|
//implementation fileTree(dir: 'libs/tasks-vision', include: ['*.jar'])
|
||||||
implementation fileTree(dir: 'libs/tasks-core', include: ['*.jar'])
|
//implementation fileTree(dir: 'libs/tasks-core', include: ['*.jar'])
|
||||||
|
|
||||||
|
|
||||||
def camerax_version = '1.4.2'
|
def camerax_version = '1.4.2'
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ android_app* g_android_app = nullptr;
|
|||||||
FaceApp* g_Application = nullptr;
|
FaceApp* g_Application = nullptr;
|
||||||
AAssetManager* g_assetManager = nullptr;
|
AAssetManager* g_assetManager = nullptr;
|
||||||
|
|
||||||
|
jobject g_callback = nullptr;
|
||||||
|
|
||||||
void handle_cmd(android_app *pApp, int32_t cmd) {
|
void handle_cmd(android_app *pApp, int32_t cmd) {
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case APP_CMD_INIT_WINDOW:
|
case APP_CMD_INIT_WINDOW:
|
||||||
@@ -80,7 +82,7 @@ void android_main(struct android_app *pApp) {
|
|||||||
auto frameTime = end_time - last_update_time;
|
auto frameTime = end_time - last_update_time;
|
||||||
last_update_time = end_time;
|
last_update_time = end_time;
|
||||||
auto function_time = (end_time - start_time);
|
auto function_time = (end_time - start_time);
|
||||||
aout << "function_time:" << function_time << " fps:" << (1000/frameTime) << std::endl;
|
//aout << "function_time:" << function_time << " fps:" << (1000/frameTime) << std::endl;
|
||||||
if(function_time < 35)
|
if(function_time < 35)
|
||||||
{
|
{
|
||||||
this_thread::sleep_for(chrono::milliseconds((35-function_time)));
|
this_thread::sleep_for(chrono::milliseconds((35-function_time)));
|
||||||
@@ -162,4 +164,108 @@ Java_com_hmwl_face_1sdk_FaceActivity_ChangeStateCpp(JNIEnv *env, jobject thiz, j
|
|||||||
{
|
{
|
||||||
g_Application->changeMotion(nativeString);
|
g_Application->changeMotion(nativeString);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_com_hmwl_face_1sdk_FaceActivity_StopRunning(JNIEnv *env, jobject thiz) {
|
||||||
|
g_Application->_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JavaVM* g_jvm = nullptr;
|
||||||
|
|
||||||
|
// 添加 JNI_OnLoad 函数
|
||||||
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||||
|
g_jvm = vm; // 保存 JavaVM 指针,供其他线程使用
|
||||||
|
return JNI_VERSION_1_6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CppCallback(const string& motion_type)
|
||||||
|
{
|
||||||
|
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_callback == nullptr) {
|
||||||
|
if (needDetach) vm->DetachCurrentThread();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 获取 CallbackInterface 的 class
|
||||||
|
jclass callbackClass = env->GetObjectClass(g_callback);
|
||||||
|
if (callbackClass == nullptr) {
|
||||||
|
if (needDetach) vm->DetachCurrentThread();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 获取 OnLoadActionFinished 方法 ID(注意方法名大小写必须一致!)
|
||||||
|
jmethodID methodId = env->GetMethodID(callbackClass, "OnLoadActionFinished", "(Ljava/lang/String;)V");
|
||||||
|
if (methodId == nullptr) {
|
||||||
|
env->ExceptionDescribe(); // 打印异常
|
||||||
|
env->ExceptionClear();
|
||||||
|
if (needDetach) vm->DetachCurrentThread();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 构造 jstring 参数
|
||||||
|
jstring jResult = env->NewStringUTF(motion_type.c_str());
|
||||||
|
|
||||||
|
// 4. 调用 Java 回调
|
||||||
|
env->CallVoidMethod(g_callback, methodId, jResult);
|
||||||
|
|
||||||
|
// 5. 检查是否抛出异常
|
||||||
|
if (env->ExceptionCheck()) {
|
||||||
|
env->ExceptionDescribe();
|
||||||
|
env->ExceptionClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 释放局部引用(可选,但推荐)
|
||||||
|
env->DeleteLocalRef(jResult);
|
||||||
|
env->DeleteLocalRef(callbackClass);
|
||||||
|
|
||||||
|
// 7. 如果是临时 attach 的线程,要 detach
|
||||||
|
if (needDetach) {
|
||||||
|
vm->DetachCurrentThread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_hmwl_face_1sdk_FaceActivity_PreReadAction(JNIEnv *env, jobject thiz, jstring motion,
|
||||||
|
jobject callback) {
|
||||||
|
// 清理旧的全局引用
|
||||||
|
if (g_callback != nullptr) {
|
||||||
|
env->DeleteGlobalRef(g_callback);
|
||||||
|
g_callback = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存新的回调
|
||||||
|
if (callback != nullptr) {
|
||||||
|
g_callback = env->NewGlobalRef(callback);
|
||||||
|
} else {
|
||||||
|
g_callback = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *nativeString = env->GetStringUTFChars(motion, nullptr);
|
||||||
|
jsize len = env->GetStringUTFLength(motion);
|
||||||
|
if(len > ArgLen)
|
||||||
|
{
|
||||||
|
aout << "ArgLen to long:" << len << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ret = g_Application->preReadyMotion(nativeString, CppCallback);
|
||||||
|
return env->NewStringUTF(ret.c_str());
|
||||||
}
|
}
|
||||||
@@ -122,6 +122,12 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Stop(){
|
||||||
|
StopRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
private native void StopRunning();
|
||||||
|
|
||||||
// Native 方法
|
// Native 方法
|
||||||
private native void processImageNative(ByteBuffer buffer, int width, int height,
|
private native void processImageNative(ByteBuffer buffer, int width, int height,
|
||||||
int format, int rowStride, int pixelStride,
|
int format, int rowStride, int pixelStride,
|
||||||
@@ -266,8 +272,17 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
SetCppInitArg(json);
|
SetCppInitArg(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface CallbackInterface {
|
||||||
|
void OnLoadActionFinished(String result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected native String PreReadAction(String motion, CallbackInterface callback);
|
||||||
|
protected String PreLoadAction(String json, CallbackInterface callback){
|
||||||
|
return PreReadAction(json, callback);
|
||||||
|
}
|
||||||
|
|
||||||
protected native void ChangeStateCpp(String json);
|
protected native void ChangeStateCpp(String json);
|
||||||
protected void ChangeState(String json){
|
protected void ChangeMotion(String json){
|
||||||
Log.i("FaceActivity", "ChangeState:" + json);
|
Log.i("FaceActivity", "ChangeState:" + json);
|
||||||
ChangeStateCpp(json);
|
ChangeStateCpp(json);
|
||||||
}
|
}
|
||||||
@@ -276,6 +291,6 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
|
|||||||
@Override
|
@Override
|
||||||
public void onEmpty() {
|
public void onEmpty() {
|
||||||
// 当没有检测到人脸时的处理逻辑
|
// 当没有检测到人脸时的处理逻辑
|
||||||
Log.d(TAG, "No face detected in the current frame");
|
//Log.d(TAG, "No face detected in the current frame");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,6 +67,9 @@ class FaceLandmarkerHelper(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
minFaceDetectionConfidence = 0.1f;
|
||||||
|
minFaceTrackingConfidence = 0.1f;
|
||||||
|
minFacePresenceConfidence = 0.1f;
|
||||||
try {
|
try {
|
||||||
val baseOptions = baseOptionBuilder.build()
|
val baseOptions = baseOptionBuilder.build()
|
||||||
// Create an option builder with base options and specific
|
// Create an option builder with base options and specific
|
||||||
@@ -238,32 +241,33 @@ class FaceLandmarkerHelper(
|
|||||||
val frameId = result.timestampMs()
|
val frameId = result.timestampMs()
|
||||||
if( result.faceLandmarks().size > 0 ) {
|
if( result.faceLandmarks().size > 0 ) {
|
||||||
// 计算各种延时
|
// 计算各种延时
|
||||||
val timings = frameTimings[frameId]
|
// val timings = frameTimings[frameId]
|
||||||
if (timings != null) {
|
// if (timings != null) {
|
||||||
val totalLatency = resultTime - timings.captureTime
|
// val totalLatency = resultTime - timings.captureTime
|
||||||
val preprocessLatency = timings.preprocessEndTime - timings.preprocessStartTime
|
// val preprocessLatency = timings.preprocessEndTime - timings.preprocessStartTime
|
||||||
val detectionLatency = resultTime - timings.detectionStartTime
|
// val detectionLatency = resultTime - timings.detectionStartTime
|
||||||
val captureToDetectionLatency = timings.detectionStartTime - timings.captureTime
|
// val captureToDetectionLatency = timings.detectionStartTime - timings.captureTime
|
||||||
|
//
|
||||||
Log.i("TimeLatency",
|
// Log.i("TimeLatency",
|
||||||
"总延时: ${totalLatency}ms | " +
|
// "总延时: ${totalLatency}ms | " +
|
||||||
"预处理: ${preprocessLatency}ms | " +
|
// "预处理: ${preprocessLatency}ms | " +
|
||||||
"检测: ${detectionLatency}ms | " +
|
// "检测: ${detectionLatency}ms | " +
|
||||||
"捕获到检测: ${captureToDetectionLatency}ms | " +
|
// "捕获到检测: ${captureToDetectionLatency}ms | " +
|
||||||
"FPS: ${String.format("%.1f", currentFps)}"
|
// "FPS: ${String.format("%.1f", currentFps)}"
|
||||||
)
|
// )
|
||||||
|
//
|
||||||
val finishTimeMs = SystemClock.uptimeMillis()
|
// val finishTimeMs = SystemClock.uptimeMillis()
|
||||||
val inferenceTime = finishTimeMs - result.timestampMs()
|
// val inferenceTime = finishTimeMs - result.timestampMs()
|
||||||
faceLandmarkerHelperListener?.onResults(
|
// faceLandmarkerHelperListener?.onResults(
|
||||||
ResultBundle(
|
// ResultBundle(
|
||||||
result,
|
// result,
|
||||||
inferenceTime, // 主要是检测时间
|
// inferenceTime, // 主要是检测时间
|
||||||
input.height,
|
// input.height,
|
||||||
input.width,
|
// input.width,
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
} else {
|
// } else
|
||||||
|
//{
|
||||||
val finishTimeMs = SystemClock.uptimeMillis()
|
val finishTimeMs = SystemClock.uptimeMillis()
|
||||||
val inferenceTime = finishTimeMs - result.timestampMs()
|
val inferenceTime = finishTimeMs - result.timestampMs()
|
||||||
Log.i("TimeLatency",
|
Log.i("TimeLatency",
|
||||||
@@ -277,7 +281,7 @@ class FaceLandmarkerHelper(
|
|||||||
input.width
|
input.width
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
faceLandmarkerHelperListener?.onEmpty()
|
faceLandmarkerHelperListener?.onEmpty()
|
||||||
|
|||||||
@@ -4,13 +4,12 @@ import org.json.JSONObject;
|
|||||||
public class InitArg {
|
public class InitArg {
|
||||||
public int action_fps;
|
public int action_fps;
|
||||||
public float zoom;
|
public float zoom;
|
||||||
public Motion motion;
|
|
||||||
public String toJson() {
|
public String toJson() {
|
||||||
try {
|
try {
|
||||||
JSONObject jsonObject = new JSONObject();
|
JSONObject jsonObject = new JSONObject();
|
||||||
jsonObject.put("action_fps", action_fps);
|
jsonObject.put("action_fps", action_fps);
|
||||||
jsonObject.put("zoom", zoom);
|
jsonObject.put("zoom", zoom);
|
||||||
jsonObject.put("motion", motion.toJsonObject());
|
|
||||||
return jsonObject.toString();
|
return jsonObject.toString();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -1,6 +1,19 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:8.3.2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application) apply false
|
alias(libs.plugins.android.application) apply false
|
||||||
alias(libs.plugins.android.library) apply false // 添加这行
|
alias(libs.plugins.android.library) apply false
|
||||||
id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
|
alias(libs.plugins.kotlin.android) apply false // 添加这行
|
||||||
|
//alias(libs.plugins.kotlin.android) apply false
|
||||||
|
//id 'org.jetbrains.kotlin.android' version '2.2.0' apply false
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
|
alias(libs.plugins.kotlin.android)
|
||||||
|
//alias(libs.plugins.kotlin.android)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace 'com.hmwl.example'
|
namespace 'com.inewme.uvmirror'
|
||||||
compileSdk 36
|
compileSdk 36
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.hmwl.f20251110"
|
applicationId "com.inewme.uvmirror.f20251129"
|
||||||
minSdk 30
|
minSdk 30
|
||||||
targetSdk 36
|
targetSdk 36
|
||||||
versionCode 1
|
versionCode 1
|
||||||
@@ -18,6 +20,7 @@ android {
|
|||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
|
signingConfig signingConfigs.debug
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
@@ -26,6 +29,20 @@ android {
|
|||||||
sourceCompatibility JavaVersion.VERSION_17
|
sourceCompatibility JavaVersion.VERSION_17
|
||||||
targetCompatibility JavaVersion.VERSION_17
|
targetCompatibility JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
compose true
|
||||||
|
}
|
||||||
|
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion '1.5.1'
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = '17'
|
||||||
|
}
|
||||||
|
// kotlinOptions {
|
||||||
|
// jvmTarget = '17'
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -33,11 +50,21 @@ dependencies {
|
|||||||
implementation libs.appcompat
|
implementation libs.appcompat
|
||||||
implementation libs.material
|
implementation libs.material
|
||||||
implementation libs.games.activity
|
implementation libs.games.activity
|
||||||
|
implementation libs.core.ktx
|
||||||
|
implementation libs.androidx.core.ktx
|
||||||
testImplementation libs.junit
|
testImplementation libs.junit
|
||||||
androidTestImplementation libs.ext.junit
|
androidTestImplementation libs.ext.junit
|
||||||
androidTestImplementation libs.espresso.core
|
androidTestImplementation libs.espresso.core
|
||||||
|
|
||||||
implementation project(':app')
|
implementation project(':app')
|
||||||
|
// Jetpack Compose
|
||||||
|
implementation "androidx.compose.ui:ui:1.5.0"
|
||||||
|
implementation "androidx.compose.material3:material3:1.0.0"
|
||||||
|
implementation "androidx.compose.foundation:foundation:1.5.0"
|
||||||
|
implementation "androidx.compose.runtime:runtime:1.5.0"
|
||||||
|
implementation "androidx.activity:activity-compose:1.7.2" // �ؼ����ṩ setContent
|
||||||
|
|
||||||
|
implementation "androidx.compose.ui:ui-tooling:1.5.4"
|
||||||
|
|
||||||
def camerax_version = '1.4.2'
|
def camerax_version = '1.4.2'
|
||||||
implementation "androidx.camera:camera-core:$camerax_version"
|
implementation "androidx.camera:camera-core:$camerax_version"
|
||||||
|
|||||||
@@ -20,6 +20,10 @@
|
|||||||
android:name="android.app.lib_name"
|
android:name="android.app.lib_name"
|
||||||
android:value="face_sdk" />
|
android:value="face_sdk" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".MakeupActivity"
|
||||||
|
android:exported="false" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.2 KiB |
@@ -1,6 +1,30 @@
|
|||||||
{
|
{
|
||||||
"4": [
|
"4": [
|
||||||
"4.png"
|
"000000.png",
|
||||||
|
"000001.png",
|
||||||
|
"000002.png",
|
||||||
|
"000003.png",
|
||||||
|
"000004.png",
|
||||||
|
"000005.png",
|
||||||
|
"000006.png",
|
||||||
|
"000007.png",
|
||||||
|
"000008.png",
|
||||||
|
"000009.png",
|
||||||
|
"000010.png",
|
||||||
|
"000011.png",
|
||||||
|
"000012.png",
|
||||||
|
"000013.png",
|
||||||
|
"000014.png",
|
||||||
|
"000015.png",
|
||||||
|
"000016.png",
|
||||||
|
"000017.png",
|
||||||
|
"000018.png",
|
||||||
|
"000019.png",
|
||||||
|
"000020.png",
|
||||||
|
"000021.png",
|
||||||
|
"000022.png",
|
||||||
|
"000023.png",
|
||||||
|
"000024.png"
|
||||||
],
|
],
|
||||||
"5": [
|
"5": [
|
||||||
"5.png"
|
"5.png"
|
||||||
@@ -86,37 +110,13 @@
|
|||||||
"78": [
|
"78": [
|
||||||
"78.png"
|
"78.png"
|
||||||
],
|
],
|
||||||
|
"80": [
|
||||||
|
"80.png"
|
||||||
|
],
|
||||||
"81": [
|
"81": [
|
||||||
"81.png"
|
"81.png"
|
||||||
],
|
],
|
||||||
"82": [
|
"82": [
|
||||||
"82.png"
|
"82.png"
|
||||||
],
|
|
||||||
"action24": [
|
|
||||||
"000000.png",
|
|
||||||
"000001.png",
|
|
||||||
"000002.png",
|
|
||||||
"000003.png",
|
|
||||||
"000004.png",
|
|
||||||
"000005.png",
|
|
||||||
"000006.png",
|
|
||||||
"000007.png",
|
|
||||||
"000008.png",
|
|
||||||
"000009.png",
|
|
||||||
"000010.png",
|
|
||||||
"000011.png",
|
|
||||||
"000012.png",
|
|
||||||
"000013.png",
|
|
||||||
"000014.png",
|
|
||||||
"000015.png",
|
|
||||||
"000016.png",
|
|
||||||
"000017.png",
|
|
||||||
"000018.png",
|
|
||||||
"000019.png",
|
|
||||||
"000020.png",
|
|
||||||
"000021.png",
|
|
||||||
"000022.png",
|
|
||||||
"000023.png",
|
|
||||||
"000024.png"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,150 +0,0 @@
|
|||||||
package com.hmwl.example;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.hmwl.face_sdk.InitArg;
|
|
||||||
import com.hmwl.face_sdk.Motion;
|
|
||||||
|
|
||||||
|
|
||||||
import com.hmwl.face_sdk.FaceActivity;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class MainActivity extends FaceActivity
|
|
||||||
{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
Motion motion = new Motion();
|
|
||||||
motion.type = "4";
|
|
||||||
motion.png_names.add("4.png");
|
|
||||||
InitArg initArg = new InitArg();
|
|
||||||
initArg.action_fps = 29;
|
|
||||||
initArg.zoom = 1.5f;
|
|
||||||
initArg.motion = motion;
|
|
||||||
SetInitArg(initArg.toJson());
|
|
||||||
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
FaceInit(this);
|
|
||||||
Toast.makeText(this, "4.png", Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
String GetCurMotionState(int index)
|
|
||||||
{
|
|
||||||
Motion motion = new Motion();
|
|
||||||
motion.type = pngFilesByFolder.get(index).folderName;
|
|
||||||
motion.png_names = pngFilesByFolder.get(index).getFileList();
|
|
||||||
return motion.toJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
|
||||||
// 获取触控动作
|
|
||||||
int action = event.getAction();
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case MotionEvent.ACTION_DOWN:
|
|
||||||
// 手指按下
|
|
||||||
Log.d("TouchEvent", "手指按下 - X: " + event.getX() + ", Y: " + event.getY());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
|
||||||
// 手指移动
|
|
||||||
Log.d("TouchEvent", "手指移动 - X: " + event.getX() + ", Y: " + event.getY());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
// 手指抬起
|
|
||||||
Log.d("TouchEvent", "手指抬起");
|
|
||||||
curIndex++;
|
|
||||||
if(curIndex > pngFilesByFolder.size()-1)
|
|
||||||
{
|
|
||||||
curIndex = 0;
|
|
||||||
}
|
|
||||||
ChangeState(GetCurMotionState(curIndex));
|
|
||||||
Toast.makeText(this, pngFilesByFolder.get(curIndex).folderName, Toast.LENGTH_LONG).show();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true; // 表示已处理该事件
|
|
||||||
}
|
|
||||||
|
|
||||||
private class FolderInfo {
|
|
||||||
private String folderName;
|
|
||||||
private List<String> fileList;
|
|
||||||
|
|
||||||
public FolderInfo(String folderName, List<String> fileList) {
|
|
||||||
this.folderName = folderName;
|
|
||||||
this.fileList = fileList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFolderName() {
|
|
||||||
return folderName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getFileList() {
|
|
||||||
return fileList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<FolderInfo> readPngFilenamesFromAssets(Context context, String filename) {
|
|
||||||
List<FolderInfo> folderList = new ArrayList<>();
|
|
||||||
|
|
||||||
try {
|
|
||||||
InputStream is = context.getAssets().open(filename);
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
stringBuilder.append(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONObject jsonObject = new JSONObject(stringBuilder.toString());
|
|
||||||
|
|
||||||
// 遍历所有文件夹
|
|
||||||
Iterator<String> folderIterator = jsonObject.keys();
|
|
||||||
while (folderIterator.hasNext()) {
|
|
||||||
String folderName = folderIterator.next();
|
|
||||||
JSONArray fileArray = jsonObject.getJSONArray(folderName);
|
|
||||||
|
|
||||||
List<String> filesInFolder = new ArrayList<>();
|
|
||||||
for (int i = 0; i < fileArray.length(); i++) {
|
|
||||||
filesInFolder.add(fileArray.getString(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
folderList.add(new FolderInfo(folderName, filesInFolder));
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.close();
|
|
||||||
is.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return folderList;
|
|
||||||
}
|
|
||||||
int curIndex = 0;
|
|
||||||
List<FolderInfo> pngFilesByFolder = null;
|
|
||||||
private void FaceInit(Context context){
|
|
||||||
pngFilesByFolder = readPngFilenamesFromAssets(context, "pic/motion_data.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package com.inewme.uvmirror
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
|
||||||
|
class MainActivity : ComponentActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContent {
|
||||||
|
MyApp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MyApp(modifier: Modifier = Modifier) {
|
||||||
|
MaterialTheme {
|
||||||
|
Surface(modifier = modifier) {
|
||||||
|
Greeting("Android")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Greeting(name: String, modifier: Modifier = Modifier) {
|
||||||
|
val context = LocalContext.current // 获取上下文用于启动 Activity
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = modifier.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(text = "Hello $name!")
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
// 跳转到 MakeupActivity
|
||||||
|
val intent = Intent(context, MakeupActivity::class.java)
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text("Go to Makeup")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun GreetingPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
Greeting("Android")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
|
||||||
|
package com.inewme.uvmirror
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.hmwl.face_sdk.FaceActivity
|
||||||
|
import com.hmwl.face_sdk.InitArg
|
||||||
|
import com.hmwl.face_sdk.Motion
|
||||||
|
import org.json.JSONObject
|
||||||
|
import java.io.BufferedReader
|
||||||
|
import java.io.InputStreamReader
|
||||||
|
|
||||||
|
|
||||||
|
class MakeupActivity : FaceActivity()
|
||||||
|
{
|
||||||
|
private var curIndex = 0
|
||||||
|
private var pngFilesByFolder: List<FolderInfo>? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
||||||
|
FaceInit(this)
|
||||||
|
|
||||||
|
val initArg = InitArg().apply {
|
||||||
|
action_fps = 10
|
||||||
|
zoom = 1.5f
|
||||||
|
}
|
||||||
|
|
||||||
|
SetInitArg(initArg.toJson())
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
var motion = getMotionByIndex(0);
|
||||||
|
var motionJsonString = motion.toJson()
|
||||||
|
val result = PreLoadAction(motionJsonString,object : CallbackInterface {
|
||||||
|
override fun OnLoadActionFinished(motion_type: String) {
|
||||||
|
//加载完成后,切断到对应的动画
|
||||||
|
Log.i("info","加载完成后,切换到对应的动画")
|
||||||
|
ChangeMotion(motion_type)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Toast.makeText(this, "开始加载动画: $result", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMotionByIndex(index: Int): Motion {
|
||||||
|
pngFilesByFolder?.let { folders ->
|
||||||
|
val motion = Motion().apply {
|
||||||
|
type = folders[index].folderName
|
||||||
|
png_names = folders[index].fileList
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
when (event.action) {
|
||||||
|
MotionEvent.ACTION_DOWN -> {
|
||||||
|
pngFilesByFolder?.let { folders ->
|
||||||
|
if (curIndex > folders.size - 1) {
|
||||||
|
//动画播放完成,切换到主界面
|
||||||
|
curIndex = 0
|
||||||
|
Stop();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_UP -> {
|
||||||
|
if (!nextMotionLoadFinished)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class FolderInfo(
|
||||||
|
val folderName: String,
|
||||||
|
val fileList: List<String>
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun readPngFilenamesFromAssets(context: Context, filename: String): List<FolderInfo> {
|
||||||
|
val folderList = mutableListOf<FolderInfo>()
|
||||||
|
|
||||||
|
try {
|
||||||
|
context.assets.open(filename).use { inputStream ->
|
||||||
|
BufferedReader(InputStreamReader(inputStream)).use { reader ->
|
||||||
|
val stringBuilder = StringBuilder()
|
||||||
|
var line: String?
|
||||||
|
while (reader.readLine().also { line = it } != null) {
|
||||||
|
stringBuilder.append(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
val jsonObject = JSONObject(stringBuilder.toString())
|
||||||
|
val folderIterator = jsonObject.keys()
|
||||||
|
|
||||||
|
while (folderIterator.hasNext()) {
|
||||||
|
val folderName = folderIterator.next()
|
||||||
|
val fileArray = jsonObject.getJSONArray(folderName)
|
||||||
|
val filesInFolder = mutableListOf<String>()
|
||||||
|
|
||||||
|
for (i in 0 until fileArray.length()) {
|
||||||
|
filesInFolder.add(fileArray.getString(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
folderList.add(FolderInfo(folderName, filesInFolder))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
return folderList
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FaceInit(context: Context) {
|
||||||
|
pngFilesByFolder = readPngFilenamesFromAssets(context, "pic/motion_data.json")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">f20251110</string>
|
<string name="app_name">f20251129</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package com.hmwl.example;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
|
||||||
*
|
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
|
||||||
*/
|
|
||||||
public class ExampleUnitTest {
|
|
||||||
@Test
|
|
||||||
public void addition_isCorrect() {
|
|
||||||
assertEquals(4, 2 + 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,11 @@ espressoCore = "3.7.0"
|
|||||||
appcompat = "1.7.1"
|
appcompat = "1.7.1"
|
||||||
material = "1.13.0"
|
material = "1.13.0"
|
||||||
gamesActivity = "2.0.2"
|
gamesActivity = "2.0.2"
|
||||||
|
kotlin = "1.9.0"
|
||||||
|
coreKtx = "1.12.0"
|
||||||
|
kotlinVersion = "1.9.0"
|
||||||
|
coreKtxVersion = "1.12.0"
|
||||||
|
androidxCoreKtx = "1.12.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||||
@@ -14,7 +19,11 @@ espresso-core = { group = "androidx.test.espresso", name = "espresso-core", vers
|
|||||||
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||||
games-activity = { group = "androidx.games", name = "games-activity", version.ref = "gamesActivity" }
|
games-activity = { group = "androidx.games", name = "games-activity", version.ref = "gamesActivity" }
|
||||||
|
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtxVersion" }
|
||||||
|
androidx-core-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidxCoreKtx" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
android-library = { id = "com.android.library", version.ref = "agp" }
|
android-library = { id = "com.android.library", version.ref = "agp" }
|
||||||
|
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" }
|
||||||
|
|||||||
@@ -599,12 +599,23 @@ void Application::cleanup() {
|
|||||||
vkDestroyImageView(device, imageView, nullptr);
|
vkDestroyImageView(device, imageView, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto framebuffer : swapChainFramebuffers)
|
||||||
|
{
|
||||||
|
if (framebuffer != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vkDestroyFramebuffer(device, framebuffer, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
swapChainFramebuffers.clear();
|
||||||
|
|
||||||
vkDestroySwapchainKHR(device, swapChain, nullptr);
|
vkDestroySwapchainKHR(device, swapChain, nullptr);
|
||||||
|
|
||||||
vkDestroyDevice(device, nullptr);
|
vkDestroyDevice(device, nullptr);
|
||||||
vkDestroySurfaceKHR(instance, surface, nullptr);
|
vkDestroySurfaceKHR(instance, surface, nullptr);
|
||||||
vkDestroyInstance(instance, nullptr);
|
vkDestroyInstance(instance, nullptr);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
@@ -630,24 +641,31 @@ uint32_t Application::findMemoryType(VkPhysicalDevice physicalDevice, uint32_t t
|
|||||||
throw std::runtime_error("Failed to find suitable memory type!");
|
throw std::runtime_error("Failed to find suitable memory type!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture Application::loadTexture(std::string path, Texture& tex, bool srgb)
|
void Application::loadTexture(std::string path, Texture& tex, bool srgb)
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> data = readFileUnsignedChar(path, false);
|
std::vector<unsigned char> data = readFileUnsignedChar(path, false);
|
||||||
std::vector<unsigned char> image;
|
std::vector<unsigned char> image;
|
||||||
unsigned w, h;
|
unsigned w, h;
|
||||||
unsigned error = lodepng::decode(image, w, h, data, LCT_RGBA, 8);
|
unsigned error = lodepng::decode(image, w, h, data, LCT_RGBA, 8);
|
||||||
processWithVulkan(image.data(), w, h, w * 4, image.size(), tex, srgb);
|
processWithVulkan(image.data(), w, h, w * 4, image.size(), tex, srgb);
|
||||||
return tex;
|
//return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::loadTexture(std::vector<unsigned char>& image_data, size_t image_size, int w, int h, Texture& tex, bool srgb)
|
||||||
|
{
|
||||||
|
processWithVulkan(image_data.data(), w, h, w * 4, image_size, tex, srgb);
|
||||||
|
//return tex;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
Texture Application::loadTextureExample(std::wstring path, Texture& tex, bool srgb)
|
void Application::loadTextureExample(std::wstring path, Texture& tex, bool srgb)
|
||||||
{
|
{
|
||||||
std::vector<unsigned char> data = readFileUnsignedCharWin32(path, true);
|
std::vector<unsigned char> data = readFileUnsignedCharWin32(path, true);
|
||||||
std::vector<unsigned char> image;
|
std::vector<unsigned char> image;
|
||||||
unsigned w, h;
|
unsigned w, h;
|
||||||
unsigned error = lodepng::decode(image, w, h, data, LCT_RGBA, 8);
|
unsigned error = lodepng::decode(image, w, h, data, LCT_RGBA, 8);
|
||||||
processWithVulkan(image.data(), w, h, w * 4, image.size(), tex, srgb);
|
processWithVulkan(image.data(), w, h, w * 4, image.size(), tex, srgb);
|
||||||
return tex;
|
//return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
@@ -751,6 +769,7 @@ void Application::createTexture(VkDevice device, VkPhysicalDevice physicalDevice
|
|||||||
}
|
}
|
||||||
|
|
||||||
texture.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
texture.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
texture.device = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::processWithVulkan(uint8_t* data, int width, int height, int rowStride, size_t dataSize, Texture& out_texture, bool srgb)
|
void Application::processWithVulkan(uint8_t* data, int width, int height, int rowStride, size_t dataSize, Texture& out_texture, bool srgb)
|
||||||
@@ -809,38 +828,44 @@ void Application::updateTexture(VkDevice device, VkPhysicalDevice physicalDevice
|
|||||||
uint8_t* data, int width, int height,
|
uint8_t* data, int width, int height,
|
||||||
int rowStride, size_t dataSize, Texture& texture)
|
int rowStride, size_t dataSize, Texture& texture)
|
||||||
{
|
{
|
||||||
VkBuffer stagingBuffer;
|
//VkBuffer stagingBuffer;
|
||||||
VkDeviceMemory stagingBufferMemory;
|
//VkDeviceMemory stagingBufferMemory;
|
||||||
|
|
||||||
VkBufferCreateInfo bufferInfo = {};
|
if (texture.stagingBuffer == nullptr)
|
||||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
||||||
bufferInfo.size = dataSize;
|
|
||||||
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
|
|
||||||
if (vkCreateBuffer(device, &bufferInfo, nullptr, &stagingBuffer) != VK_SUCCESS)
|
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to create staging buffer!");
|
VkBufferCreateInfo bufferInfo = {};
|
||||||
|
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
bufferInfo.size = dataSize;
|
||||||
|
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
if (vkCreateBuffer(device, &bufferInfo, nullptr, &texture.stagingBuffer) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to create staging buffer!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkMemoryRequirements memRequirements;
|
if (texture.stagingBufferMemory == nullptr)
|
||||||
vkGetBufferMemoryRequirements(device, stagingBuffer, &memRequirements);
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo allocInfo = {};
|
|
||||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
||||||
allocInfo.allocationSize = memRequirements.size;
|
|
||||||
allocInfo.memoryTypeIndex = findMemoryType(physicalDevice,
|
|
||||||
memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
||||||
|
|
||||||
if (vkAllocateMemory(device, &allocInfo, nullptr, &stagingBufferMemory) != VK_SUCCESS)
|
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to allocate staging buffer memory!");
|
VkMemoryRequirements memRequirements;
|
||||||
}
|
vkGetBufferMemoryRequirements(device, texture.stagingBuffer, &memRequirements);
|
||||||
|
|
||||||
vkBindBufferMemory(device, stagingBuffer, stagingBufferMemory, 0);
|
VkMemoryAllocateInfo allocInfo = {};
|
||||||
|
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
allocInfo.allocationSize = memRequirements.size;
|
||||||
|
allocInfo.memoryTypeIndex = findMemoryType(physicalDevice,
|
||||||
|
memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||||
|
|
||||||
|
if (vkAllocateMemory(device, &allocInfo, nullptr, &texture.stagingBufferMemory) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to allocate staging buffer memory!");
|
||||||
|
}
|
||||||
|
|
||||||
|
vkBindBufferMemory(device, texture.stagingBuffer, texture.stagingBufferMemory, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void* mappedData;
|
void* mappedData;
|
||||||
vkMapMemory(device, stagingBufferMemory, 0, dataSize, 0, &mappedData);
|
vkMapMemory(device, texture.stagingBufferMemory, 0, dataSize, 0, &mappedData);
|
||||||
|
|
||||||
if (rowStride == width * 4)
|
if (rowStride == width * 4)
|
||||||
{
|
{
|
||||||
@@ -860,7 +885,7 @@ void Application::updateTexture(VkDevice device, VkPhysicalDevice physicalDevice
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vkUnmapMemory(device, stagingBufferMemory);
|
vkUnmapMemory(device, texture.stagingBufferMemory);
|
||||||
|
|
||||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool);
|
VkCommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool);
|
||||||
|
|
||||||
@@ -880,7 +905,7 @@ void Application::updateTexture(VkDevice device, VkPhysicalDevice physicalDevice
|
|||||||
region.imageExtent = { static_cast<uint32_t>(width),
|
region.imageExtent = { static_cast<uint32_t>(width),
|
||||||
static_cast<uint32_t>(height), 1 };
|
static_cast<uint32_t>(height), 1 };
|
||||||
|
|
||||||
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, texture.image,
|
vkCmdCopyBufferToImage(commandBuffer, texture.stagingBuffer, texture.image,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||||
|
|
||||||
transitionImageLayout(commandBuffer, texture.image,
|
transitionImageLayout(commandBuffer, texture.image,
|
||||||
@@ -889,8 +914,6 @@ void Application::updateTexture(VkDevice device, VkPhysicalDevice physicalDevice
|
|||||||
|
|
||||||
endSingleTimeCommands(device, commandPool, queue, commandBuffer);
|
endSingleTimeCommands(device, commandPool, queue, commandBuffer);
|
||||||
|
|
||||||
vkDestroyBuffer(device, stagingBuffer, nullptr);
|
|
||||||
vkFreeMemory(device, stagingBufferMemory, nullptr);
|
|
||||||
|
|
||||||
texture.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
texture.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,17 @@ struct Texture
|
|||||||
VkImageView view;
|
VkImageView view;
|
||||||
uint32_t width, height;
|
uint32_t width, height;
|
||||||
uint32_t mip_levels;
|
uint32_t mip_levels;
|
||||||
|
VkBuffer stagingBuffer = VK_NULL_HANDLE;
|
||||||
|
VkDeviceMemory stagingBufferMemory = VK_NULL_HANDLE;
|
||||||
|
VkDevice device;
|
||||||
|
void reset() {
|
||||||
|
sampler = VK_NULL_HANDLE;
|
||||||
|
image = VK_NULL_HANDLE;
|
||||||
|
device_memory = VK_NULL_HANDLE;
|
||||||
|
view = VK_NULL_HANDLE;
|
||||||
|
stagingBuffer = VK_NULL_HANDLE;
|
||||||
|
stagingBufferMemory = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Application : public AppBase
|
class Application : public AppBase
|
||||||
@@ -74,9 +85,10 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Texture loadTexture(std::string path, Texture& tex, bool srgb);
|
void loadTexture(std::string path, Texture& tex, bool srgb);
|
||||||
|
void loadTexture(std::vector<unsigned char>& image_data, size_t image_size, int w, int h, Texture& tex, bool srgb);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
Texture loadTextureExample(std::wstring path, Texture& tex, bool srgb);
|
void loadTextureExample(std::wstring path, Texture& tex, bool srgb);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter,
|
uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "FaceApp.h"
|
#include "FaceApp.h"
|
||||||
#include "hardcode_data.h"
|
#include "hardcode_data.h"
|
||||||
|
#include "lodepng.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -454,6 +455,10 @@ void FaceApp::create_face_pipelines()
|
|||||||
pipeline_create_info.pStages = shader_stages;
|
pipeline_create_info.pStages = shader_stages;
|
||||||
|
|
||||||
VK_CHECK(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_create_info, nullptr, &m_graphicsPipeline));
|
VK_CHECK(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_create_info, nullptr, &m_graphicsPipeline));
|
||||||
|
|
||||||
|
// 销毁着色器模块
|
||||||
|
vkDestroyShaderModule(device, fragShaderModule, nullptr);
|
||||||
|
vkDestroyShaderModule(device, vertShaderModule, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -562,7 +567,11 @@ void FaceApp::setup_descriptor_set()
|
|||||||
alloc_info.pSetLayouts = layouts.data();
|
alloc_info.pSetLayouts = layouts.data();
|
||||||
alloc_info.descriptorSetCount = m_descriptor_sets.size();
|
alloc_info.descriptorSetCount = m_descriptor_sets.size();
|
||||||
VK_CHECK(vkAllocateDescriptorSets(device, &alloc_info, m_descriptor_sets.data()));
|
VK_CHECK(vkAllocateDescriptorSets(device, &alloc_info, m_descriptor_sets.data()));
|
||||||
|
update_descriptor_set(m_texs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceApp::update_descriptor_set(vector<Texture>& texs)
|
||||||
|
{
|
||||||
for (int i = 0; i < kMaxTexture; ++i)
|
for (int i = 0; i < kMaxTexture; ++i)
|
||||||
{
|
{
|
||||||
VkDescriptorBufferInfo buffer_descriptor{};
|
VkDescriptorBufferInfo buffer_descriptor{};
|
||||||
@@ -572,9 +581,9 @@ void FaceApp::setup_descriptor_set()
|
|||||||
|
|
||||||
|
|
||||||
VkDescriptorImageInfo image_descriptor;
|
VkDescriptorImageInfo image_descriptor;
|
||||||
image_descriptor.imageView = m_texs[i].view;
|
image_descriptor.imageView = texs[i].view;
|
||||||
image_descriptor.sampler = m_texs[i].sampler;
|
image_descriptor.sampler = texs[i].sampler;
|
||||||
image_descriptor.imageLayout = m_texs[i].image_layout;
|
image_descriptor.imageLayout = texs[i].image_layout;
|
||||||
|
|
||||||
VkWriteDescriptorSet write_descriptor_set_uniform{};
|
VkWriteDescriptorSet write_descriptor_set_uniform{};
|
||||||
write_descriptor_set_uniform.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
write_descriptor_set_uniform.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
@@ -630,17 +639,7 @@ void FaceApp::setup_descriptor_set()
|
|||||||
vkUpdateDescriptorSets(device, static_cast<uint32_t>(write_descriptor_sets.size()), write_descriptor_sets.data(), 0, NULL);
|
vkUpdateDescriptorSets(device, static_cast<uint32_t>(write_descriptor_sets.size()), write_descriptor_sets.data(), 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FaceApp::render(VkCommandBuffer commandBuffer, long long frameTime)
|
void FaceApp::render(VkCommandBuffer commandBuffer, long long frameTime)
|
||||||
@@ -713,11 +712,25 @@ void FaceApp::initVulkan()
|
|||||||
createVmaAllocator();
|
createVmaAllocator();
|
||||||
LoadOBJ("face_picture_3dmax.obj", obj_vertices, obj_indices);
|
LoadOBJ("face_picture_3dmax.obj", obj_vertices, obj_indices);
|
||||||
m_texs.resize(kMaxTexture);
|
m_texs.resize(kMaxTexture);
|
||||||
m_texs_ex.resize(kMaxTexture);
|
m_texs_next.resize(kMaxTexture);
|
||||||
|
if (kThick)
|
||||||
|
{
|
||||||
|
m_texs_ex.resize(kMaxTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> data = readFileUnsignedChar("demo0.png", false);
|
||||||
|
std::vector<unsigned char> image;
|
||||||
|
unsigned w, h;
|
||||||
|
unsigned error = lodepng::decode(image, w, h, data, LCT_RGBA, 8);
|
||||||
|
|
||||||
for (int i = 0; i < kMaxTexture; ++i)
|
for (int i = 0; i < kMaxTexture; ++i)
|
||||||
{
|
{
|
||||||
loadTexture("demo0.png", m_texs[i], true);
|
loadTexture(image, image.size(), w, h, m_texs[i], true);
|
||||||
loadTexture("demo0_ex.png", m_texs_ex[i], true);
|
loadTexture(image, image.size(), w, h, m_texs_next[i], true);
|
||||||
|
if (kThick)
|
||||||
|
{
|
||||||
|
loadTexture(image, image.size(), w, h, m_texs_ex[i], true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadTexture("out.png", tex_bg, true);
|
loadTexture("out.png", tex_bg, true);
|
||||||
@@ -736,7 +749,8 @@ void FaceApp::initVulkan()
|
|||||||
uploadVertexData();
|
uploadVertexData();
|
||||||
last_update_time = getCurrentTimeMillis();
|
last_update_time = getCurrentTimeMillis();
|
||||||
|
|
||||||
changeMotion(_initArg.motion);
|
//changeMotion(_initArg.motion);
|
||||||
|
_running = true;
|
||||||
faceAppInited = true;
|
faceAppInited = true;
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
std::vector<float> floatArray;
|
std::vector<float> floatArray;
|
||||||
@@ -1032,6 +1046,10 @@ void FaceApp::create_pipelines_bg()
|
|||||||
pipeline_create_info.pStages = shader_stages;
|
pipeline_create_info.pStages = shader_stages;
|
||||||
|
|
||||||
VK_CHECK(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_create_info, nullptr, &m_graphicsPipeline_bg));
|
VK_CHECK(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_create_info, nullptr, &m_graphicsPipeline_bg));
|
||||||
|
|
||||||
|
// 销毁着色器模块
|
||||||
|
vkDestroyShaderModule(device, fragShaderModule, nullptr);
|
||||||
|
vkDestroyShaderModule(device, vertShaderModule, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FaceApp::setup_descriptor_set_layout_bg()
|
void FaceApp::setup_descriptor_set_layout_bg()
|
||||||
@@ -1101,21 +1119,158 @@ void FaceApp::setup_descriptor_set_bg()
|
|||||||
vkUpdateDescriptorSets(device, static_cast<uint32_t>(write_descriptor_sets.size()), write_descriptor_sets.data(), 0, NULL);
|
vkUpdateDescriptorSets(device, static_cast<uint32_t>(write_descriptor_sets.size()), write_descriptor_sets.data(), 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FaceApp::destroyTexture(VkDevice device, Texture& texture) {
|
||||||
|
// 注意销毁顺序:先销毁依赖对象,后销毁被依赖对象
|
||||||
|
|
||||||
|
// 1. 销毁采样器
|
||||||
|
if (texture.sampler != VK_NULL_HANDLE) {
|
||||||
|
vkDestroySampler(device, texture.sampler, nullptr);
|
||||||
|
texture.sampler = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 销毁图像视图
|
||||||
|
if (texture.view != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImageView(device, texture.view, nullptr);
|
||||||
|
texture.view = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 销毁图像
|
||||||
|
if (texture.image != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyImage(device, texture.image, nullptr);
|
||||||
|
texture.image = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 释放设备内存
|
||||||
|
if (texture.device_memory != VK_NULL_HANDLE) {
|
||||||
|
vkFreeMemory(device, texture.device_memory, nullptr);
|
||||||
|
texture.device_memory = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture.stagingBuffer != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vkDestroyBuffer(device, texture.stagingBuffer, nullptr);
|
||||||
|
texture.stagingBuffer = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture.stagingBufferMemory != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vkFreeMemory(device, texture.stagingBufferMemory, nullptr);
|
||||||
|
texture.stagingBufferMemory = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceApp::cleanupResources(VkDevice device, VmaAllocator allocator) {
|
||||||
|
// 销毁图形管线
|
||||||
|
if (m_graphicsPipeline != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipeline(device, m_graphicsPipeline, nullptr);
|
||||||
|
m_graphicsPipeline = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 销毁管线布局
|
||||||
|
if (m_pipelineLayout != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipelineLayout(device, m_pipelineLayout, nullptr);
|
||||||
|
m_pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 销毁描述符集布局
|
||||||
|
if (m_descriptorSetLayout != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyDescriptorSetLayout(device, m_descriptorSetLayout, nullptr);
|
||||||
|
m_descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 销毁图形管线
|
||||||
|
if (m_graphicsPipeline_bg != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipeline(device, m_graphicsPipeline_bg, nullptr);
|
||||||
|
m_graphicsPipeline_bg = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 销毁管线布局
|
||||||
|
if (m_pipelineLayout_bg != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipelineLayout(device, m_pipelineLayout_bg, nullptr);
|
||||||
|
m_pipelineLayout_bg = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 销毁描述符集布局
|
||||||
|
if (m_descriptorSetLayout_bg != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyDescriptorSetLayout(device, m_descriptorSetLayout_bg, nullptr);
|
||||||
|
m_descriptorSetLayout_bg = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 销毁顶点缓冲区
|
||||||
|
if (m_vertexBuffer != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyBuffer(device, m_vertexBuffer, nullptr);
|
||||||
|
m_vertexBuffer = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
if (m_vertexBufferAllocation != VK_NULL_HANDLE) {
|
||||||
|
vmaFreeMemory(allocator, m_vertexBufferAllocation);
|
||||||
|
m_vertexBufferAllocation = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 销毁暂存缓冲区
|
||||||
|
if (m_stagingBuffer != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyBuffer(device, m_stagingBuffer, nullptr);
|
||||||
|
m_stagingBuffer = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
if (m_stagingBufferAllocation != VK_NULL_HANDLE) {
|
||||||
|
vmaFreeMemory(allocator, m_stagingBufferAllocation);
|
||||||
|
m_stagingBufferAllocation = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 销毁索引缓冲区
|
||||||
|
if (m_indexBuffer != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyBuffer(device, m_indexBuffer, nullptr);
|
||||||
|
m_indexBuffer = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
if (m_indexBufferAllocation != VK_NULL_HANDLE) {
|
||||||
|
vmaFreeMemory(allocator, m_indexBufferAllocation);
|
||||||
|
m_indexBufferAllocation = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor_pool != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vkDestroyDescriptorPool(device, descriptor_pool, nullptr);
|
||||||
|
descriptor_pool = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空描述符集列表(不需要单独销毁,由描述符池管理)
|
||||||
|
m_descriptor_sets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void FaceApp::cleanup()
|
void FaceApp::cleanup()
|
||||||
{
|
{
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
|
if (uniform_buffer_mapped != nullptr)
|
||||||
|
{
|
||||||
|
vmaUnmapMemory(allocator, uniform_buffer_allocation);
|
||||||
|
uniform_buffer_mapped = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uniform_buffer_vs != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vmaDestroyBuffer(allocator, uniform_buffer_vs, uniform_buffer_allocation);
|
||||||
|
uniform_buffer_vs = VK_NULL_HANDLE;
|
||||||
|
uniform_buffer_allocation = VK_NULL_HANDLE; // 可选,但推荐重置
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanupResources(device, allocator);
|
||||||
|
for (int i = 0; i < this->m_texs.size(); ++i)
|
||||||
|
{
|
||||||
|
destroyTexture(device, m_texs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < this->m_texs_next.size(); ++i)
|
||||||
|
{
|
||||||
|
destroyTexture(device, m_texs_next[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyTexture(device, tex_bg);
|
||||||
vkDestroyCommandPool(device, commandPool, nullptr);
|
vkDestroyCommandPool(device, commandPool, nullptr);
|
||||||
vkDestroyPipeline(device, m_graphicsPipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(device, m_pipelineLayout, nullptr);
|
|
||||||
//vmaUnmapMemory(allocator, m_stagingBufferAllocation);
|
|
||||||
//vmaUnmapMemory(allocator, uniform_buffer_allocation);
|
|
||||||
//vmaDestroyBuffer(allocator, uniform_buffer_vs, uniform_buffer_allocation);
|
|
||||||
//vmaDestroyBuffer(allocator, m_indexBuffer, m_indexBufferAllocation);
|
|
||||||
//vmaDestroyBuffer(allocator, m_vertexBuffer, m_vertexBufferAllocation);
|
|
||||||
//vmaDestroyBuffer(allocator, m_stagingBuffer, m_stagingBufferAllocation);
|
|
||||||
vkDestroyDescriptorSetLayout(device, m_descriptorSetLayout, nullptr);
|
|
||||||
Application::cleanup();
|
Application::cleanup();
|
||||||
|
//if (allocator != VK_NULL_HANDLE) {
|
||||||
|
// vmaDestroyAllocator(allocator);
|
||||||
|
// allocator = VK_NULL_HANDLE;
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1127,6 +1282,37 @@ void FaceApp::SetInitArg(const char* arg)
|
|||||||
|
|
||||||
void FaceApp::drawFrame(long long frameTime)
|
void FaceApp::drawFrame(long long frameTime)
|
||||||
{
|
{
|
||||||
|
if (!_running)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_motionState == loading_next_motion)
|
||||||
|
{
|
||||||
|
int i = _nextMotionIndex;
|
||||||
|
//for (int i = 0; i < _curMotion.png_names.size(); ++i)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
string path = "pic";
|
||||||
|
string path_name = path + "/" + _nextMotion.type + "/" + _nextMotion.png_names[i];// +std::to_string(i) + ".png";
|
||||||
|
loadTextureExample(UTF8ToWideString(path_name), m_texs_next[i], true);
|
||||||
|
#else
|
||||||
|
//string path = _curMotion.type + "/" + _curMotion.technique + "/" + _curMotion.step + "/" + _curMotion.show_type;
|
||||||
|
string path = "pic";
|
||||||
|
string path_name = path + "/" + _nextMotion.type + "/" + _nextMotion.png_names[i];// +std::to_string(i) + ".png";
|
||||||
|
loadTexture(path_name, m_texs_next[i], true);
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
_nextMotionIndex++;
|
||||||
|
if (_nextMotionIndex >= _nextMotion.png_names.size())
|
||||||
|
{
|
||||||
|
_motionState = load_next_motion_finished;
|
||||||
|
_callback(_nextMotion.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_lock lock(changeMotionMtx);
|
std::unique_lock lock(changeMotionMtx);
|
||||||
static long long game_time = 0;
|
static long long game_time = 0;
|
||||||
game_time += frameTime;
|
game_time += frameTime;
|
||||||
@@ -1134,7 +1320,7 @@ void FaceApp::drawFrame(long long frameTime)
|
|||||||
if (game_time > actionTime)
|
if (game_time > actionTime)
|
||||||
{
|
{
|
||||||
_curTexIndex++;
|
_curTexIndex++;
|
||||||
if (_curTexIndex >= _curMotion.png_names.size())
|
if (_curTexIndex >= _curMotion_png_size)
|
||||||
{
|
{
|
||||||
_curTexIndex = 0;
|
_curTexIndex = 0;
|
||||||
}
|
}
|
||||||
@@ -1143,44 +1329,90 @@ void FaceApp::drawFrame(long long frameTime)
|
|||||||
Application::drawFrame(frameTime);
|
Application::drawFrame(frameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FaceApp::changeMotion(const char* json)
|
//void FaceApp::changeMotion(const char* motion_type)
|
||||||
|
//{
|
||||||
|
// //Motion motion = json::parse(json);
|
||||||
|
// changeMotion(motion);
|
||||||
|
//}
|
||||||
|
|
||||||
|
string FaceApp::preReadyMotion(const std::string& json, Callback callback)
|
||||||
{
|
{
|
||||||
Motion motion = json::parse(json);
|
if (_motionState == loading_next_motion)
|
||||||
changeMotion(motion);
|
{
|
||||||
|
return "busy on loading:" + _nextMotion.type;
|
||||||
|
}
|
||||||
|
else if (_motionState == load_next_motion_finished)
|
||||||
|
{
|
||||||
|
return "waitting change next action:" + _nextMotion.type;
|
||||||
|
}
|
||||||
|
else if (_motionState == ready)
|
||||||
|
{
|
||||||
|
Motion motion = json::parse(json);
|
||||||
|
_nextMotion = motion;
|
||||||
|
_motionState = loading_next_motion;
|
||||||
|
_nextMotionIndex = 0;
|
||||||
|
_callback = callback;
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
return "failure";
|
||||||
}
|
}
|
||||||
|
|
||||||
void FaceApp::changeMotion(Motion& motion)
|
void FaceApp::changeMotion(const string motion_type)
|
||||||
{
|
{
|
||||||
if (_curMotion.getMotionId() == motion.getMotionId())
|
if (_curMotion_type == motion_type)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::unique_lock<std::mutex> lock_changeMotion(changeMotionMtx);
|
|
||||||
_curMotion = motion;
|
if (_motionState != load_next_motion_finished)
|
||||||
for (int i = 0; i < _curMotion.png_names.size(); ++i)
|
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
#ifdef _WIN32
|
|
||||||
//string path = _curMotion.type + "/" + _curMotion.technique + "/" + _curMotion.step + "/" + _curMotion.show_type;
|
|
||||||
string path = "pic";
|
|
||||||
string path_name = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i];// +std::to_string(i) + ".png";
|
|
||||||
loadTextureExample(UTF8ToWideString(path_name), m_texs[i], true);
|
|
||||||
if (kThick)
|
|
||||||
{
|
|
||||||
string path_name_ex = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i] + std::to_string(i) + "_thick.png";
|
|
||||||
loadTextureExample(UTF8ToWideString(path_name_ex), m_texs_ex[i], true);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
//string path = _curMotion.type + "/" + _curMotion.technique + "/" + _curMotion.step + "/" + _curMotion.show_type;
|
|
||||||
string path = "pic";
|
|
||||||
string path_name = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i];// +std::to_string(i) + ".png";
|
|
||||||
loadTexture(path_name, m_texs[i], true);
|
|
||||||
if (kThick)
|
|
||||||
{
|
|
||||||
loadTexture(path_name, m_texs_ex[i], true);
|
|
||||||
}
|
|
||||||
#endif // _WIN32
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock_changeMotion(changeMotionMtx);
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < _nextMotion.png_names.size(); ++i)
|
||||||
|
{
|
||||||
|
destroyTexture(device, m_texs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _nextMotion.png_names.size(); ++i)
|
||||||
|
{
|
||||||
|
m_texs[i] = m_texs_next[i];
|
||||||
|
m_texs_next[i].reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
update_descriptor_set(m_texs);
|
||||||
|
_curMotion_type = motion_type;
|
||||||
|
_curMotion_png_size = _nextMotion.png_names.size();
|
||||||
|
_motionState = ready;
|
||||||
|
|
||||||
|
|
||||||
|
// for (int i = 0; i < _curMotion.png_names.size(); ++i)
|
||||||
|
// {
|
||||||
|
//
|
||||||
|
//#ifdef _WIN32
|
||||||
|
// //string path = _curMotion.type + "/" + _curMotion.technique + "/" + _curMotion.step + "/" + _curMotion.show_type;
|
||||||
|
// string path = "pic";
|
||||||
|
// string path_name = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i];// +std::to_string(i) + ".png";
|
||||||
|
// loadTextureExample(UTF8ToWideString(path_name), m_texs[i], true);
|
||||||
|
// if (kThick)
|
||||||
|
// {
|
||||||
|
// string path_name_ex = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i] + std::to_string(i) + "_thick.png";
|
||||||
|
// loadTextureExample(UTF8ToWideString(path_name_ex), m_texs_ex[i], true);
|
||||||
|
// }
|
||||||
|
//#else
|
||||||
|
// //string path = _curMotion.type + "/" + _curMotion.technique + "/" + _curMotion.step + "/" + _curMotion.show_type;
|
||||||
|
// string path = "pic";
|
||||||
|
// string path_name = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i];// +std::to_string(i) + ".png";
|
||||||
|
// loadTexture(path_name, m_texs[i], true);
|
||||||
|
// if (kThick)
|
||||||
|
// {
|
||||||
|
// loadTexture(path_name, m_texs_ex[i], true);
|
||||||
|
// }
|
||||||
|
//#endif // _WIN32
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#define __FaceApp_H__
|
#define __FaceApp_H__
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include <functional>
|
||||||
#include "../third_party/vma/include/vk_mem_alloc.h"
|
#include "../third_party/vma/include/vk_mem_alloc.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
@@ -24,8 +25,8 @@ struct InitArg
|
|||||||
{
|
{
|
||||||
int action_fps;
|
int action_fps;
|
||||||
float zoom;
|
float zoom;
|
||||||
Motion motion;
|
//Motion motion;
|
||||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(InitArg, action_fps, zoom, motion);
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE(InitArg, action_fps, zoom);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ struct PushConstants {
|
|||||||
float myValue;
|
float myValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using Callback = std::function<void(const std::string&)>;
|
||||||
|
|
||||||
class FaceApp :public Application
|
class FaceApp :public Application
|
||||||
{
|
{
|
||||||
@@ -79,6 +80,7 @@ private:
|
|||||||
void setup_descriptor_pool();
|
void setup_descriptor_pool();
|
||||||
void setup_descriptor_set_layout();
|
void setup_descriptor_set_layout();
|
||||||
void setup_descriptor_set();
|
void setup_descriptor_set();
|
||||||
|
void update_descriptor_set(vector<Texture>& texs);
|
||||||
const bool kThick = false;
|
const bool kThick = false;
|
||||||
|
|
||||||
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
|
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
|
||||||
@@ -100,8 +102,9 @@ private:
|
|||||||
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
|
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
|
||||||
VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
|
VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
vector<VkDescriptorSet> m_descriptor_sets;
|
vector<VkDescriptorSet> m_descriptor_sets;
|
||||||
const uint32_t kMaxTexture = 30;
|
const uint32_t kMaxTexture = 60;
|
||||||
vector<Texture> m_texs;
|
vector<Texture> m_texs;
|
||||||
|
vector<Texture> m_texs_next;
|
||||||
vector<Texture> m_texs_ex;
|
vector<Texture> m_texs_ex;
|
||||||
|
|
||||||
|
|
||||||
@@ -135,14 +138,34 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void changeMotion(const char* json);
|
Callback _callback;
|
||||||
void changeMotion(Motion& motion);
|
string preReadyMotion(const std::string& json, Callback callback);
|
||||||
|
void changeMotion(const string motion_type);
|
||||||
|
//void changeMotion(Motion& motion);
|
||||||
InitArg _initArg;
|
InitArg _initArg;
|
||||||
Motion _curMotion;
|
//Motion _curMotion;
|
||||||
|
string _curMotion_type;
|
||||||
|
int _curMotion_png_size;
|
||||||
|
Motion _nextMotion;
|
||||||
|
int _nextMotionIndex;
|
||||||
|
|
||||||
|
enum MotionState {
|
||||||
|
ready,
|
||||||
|
loading_next_motion,
|
||||||
|
load_next_motion_finished,
|
||||||
|
};
|
||||||
|
|
||||||
|
MotionState _motionState = ready;
|
||||||
|
|
||||||
int _curTexIndex = 0;
|
int _curTexIndex = 0;
|
||||||
void SetInitArg(const char* arg);
|
void SetInitArg(const char* arg);
|
||||||
|
|
||||||
void drawFrame(long long frameTime)override;
|
void drawFrame(long long frameTime)override;
|
||||||
|
|
||||||
|
void destroyTexture(VkDevice device, Texture& texture);
|
||||||
|
void cleanupResources(VkDevice device, VmaAllocator allocator);
|
||||||
|
|
||||||
|
bool _running = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -39,6 +39,12 @@ std::wstring ReadFileWithChinesePath(const std::wstring& filePath) {
|
|||||||
return AppBase::UTF8ToWideString(context);
|
return AppBase::UTF8ToWideString(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FaceApp* g_app;
|
||||||
|
|
||||||
|
void CppCallback(const string& motion_type)
|
||||||
|
{
|
||||||
|
g_app->changeMotion(motion_type.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
@@ -49,7 +55,8 @@ int main() {
|
|||||||
|
|
||||||
InitArg init_arg;
|
InitArg init_arg;
|
||||||
Motion motion;
|
Motion motion;
|
||||||
motion.type = "action24";
|
motion.type = "4";
|
||||||
|
motion.png_names.push_back("4.png");
|
||||||
for (int i = 0; i < 25; ++i)
|
for (int i = 0; i < 25; ++i)
|
||||||
{
|
{
|
||||||
if (i < 10)
|
if (i < 10)
|
||||||
@@ -66,7 +73,7 @@ int main() {
|
|||||||
|
|
||||||
#
|
#
|
||||||
|
|
||||||
init_arg.motion = motion;
|
//init_arg.motion = motion;
|
||||||
|
|
||||||
|
|
||||||
init_arg.action_fps = 10;
|
init_arg.action_fps = 10;
|
||||||
@@ -75,8 +82,22 @@ int main() {
|
|||||||
string json_str = json(init_arg).dump();
|
string json_str = json(init_arg).dump();
|
||||||
|
|
||||||
FaceApp app;
|
FaceApp app;
|
||||||
|
g_app = &app;
|
||||||
app.SetInitArg(json_str.c_str());
|
app.SetInitArg(json_str.c_str());
|
||||||
app.initVulkan();
|
app.initVulkan();
|
||||||
|
app._running = true;
|
||||||
|
auto motion_json = json(motion);
|
||||||
|
if (!motion_json.is_object()) {
|
||||||
|
std::cout << "Invalid JSON structure" << std::endl;
|
||||||
|
}
|
||||||
|
std::string motion_str = motion_json.dump();
|
||||||
|
// 添加完整性检查
|
||||||
|
if (motion_str.empty()) {
|
||||||
|
std::cout << "Warning: Empty motion string" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
app.preReadyMotion(motion_str, CppCallback);
|
||||||
app.mainLoop();
|
app.mainLoop();
|
||||||
//try {
|
//try {
|
||||||
// app.mainLoop();
|
// app.mainLoop();
|
||||||
|
|||||||