11 Commits
Author SHA1 Message Date
xsl da2c97e412 修改检测参数,降低置信度,提高检测的延时 2025-12-06 11:59:00 +08:00
xsl db80a5dbbd asdf 2025-12-02 20:36:32 +08:00
xsl 634d22f3be 完成动画切换 2025-11-30 12:22:43 +08:00
xsl 835f768a4a 基本调通 回调 2025-11-29 23:44:22 +08:00
xsl 1859706412 优化内存读取 2025-11-29 11:35:56 +08:00
xsl 9c71e40c97 新版本f1118 更新图片 修复_running bug 2025-11-17 22:36:59 +08:00
xsl 84d567674f 化妆切换完成 2025-11-12 15:13:55 +08:00
xsl 43b00c8446 添加是否运行的标致 2025-11-12 15:05:31 +08:00
xsl e23ccd75cd 清理所有资源,有两处内存泄漏,暂时找不到了 2025-11-12 15:03:15 +08:00
xsl 8623b71ab7 总算是编译通过了 2025-11-12 10:53:41 +08:00
xsl 16efcbcff3 现在才真的能打包正确的 aar 2025-11-09 10:25:43 +08:00
91 changed files with 3182 additions and 2613 deletions
+35 -15
View File
@@ -1,7 +1,8 @@
plugins {
//alias(libs.plugins.android.application)
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'
@@ -30,6 +31,17 @@ android {
debug {
debuggable true
jniDebuggable true
externalNativeBuild {
cmake {
arguments "-DCMAKE_BUILD_TYPE=Debug"
cppFlags "-DDEBUG -O0 -g"
}
}
ndk {
debugSymbolLevel 'FULL' // Debug 版本包含完整符号
}
}
release {
@@ -43,13 +55,13 @@ android {
}
// 添加 Kotlin 编译选项
kotlinOptions {
jvmTarget = '17' // 与 Java 版本保持一致
}
// kotlinOptions {
// jvmTarget = '17' // 与 Java 版本保持一致
// }
kotlin {
jvmToolchain(21)
}
// kotlin {
// jvmToolchain(17)
// }
buildFeatures {
prefab true
@@ -62,10 +74,10 @@ android {
'libs/tasks-vision/jni',
'libs/tasks-core/jni'
]
java.srcDirs += [
'libs/tasks-vision/vision_classes',
'libs/tasks-core/core_classes'
]
//java.srcDirs += [
// 'libs/tasks-vision/vision_classes',
// 'libs/tasks-core/core_classes'
//]
res.srcDirs += [
'libs/tasks-vision/res',
'libs/tasks-core/res'
@@ -79,6 +91,13 @@ android {
version '3.22.1'
}
}
packagingOptions {
pickFirst '**/*.jar'
}
kotlinOptions {
jvmTarget = '17'
}
}
dependencies {
@@ -86,16 +105,17 @@ dependencies {
implementation libs.appcompat
implementation libs.material
implementation libs.games.activity
implementation libs.androidx.core.core.ktx
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
//implementation 'com.google.protobuf:protobuf-javalite:3.21.12'
//implementation files('libs/tasks-vision.jar', 'libs/tasks-core.jar')
implementation 'com.google.protobuf:protobuf-javalite:3.21.12'
implementation files('libs/tasks-vision.jar', 'libs/tasks-core.jar')
implementation fileTree(dir: 'libs/tasks-vision', include: ['*.jar'])
implementation fileTree(dir: 'libs/tasks-core', include: ['*.jar'])
//implementation fileTree(dir: 'libs/tasks-vision', include: ['*.jar'])
//implementation fileTree(dir: 'libs/tasks-core', include: ['*.jar'])
def camerax_version = '1.4.2'
File diff suppressed because it is too large Load Diff
+107 -1
View File
@@ -15,6 +15,8 @@ android_app* g_android_app = nullptr;
FaceApp* g_Application = nullptr;
AAssetManager* g_assetManager = nullptr;
jobject g_callback = nullptr;
void handle_cmd(android_app *pApp, int32_t cmd) {
switch (cmd) {
case APP_CMD_INIT_WINDOW:
@@ -80,7 +82,7 @@ void android_main(struct android_app *pApp) {
auto frameTime = end_time - last_update_time;
last_update_time = end_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)
{
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);
}
}
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 方法
private native void processImageNative(ByteBuffer buffer, int width, int height,
int format, int rowStride, int pixelStride,
@@ -266,8 +272,17 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
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 void ChangeState(String json){
protected void ChangeMotion(String json){
Log.i("FaceActivity", "ChangeState:" + json);
ChangeStateCpp(json);
}
@@ -276,6 +291,6 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
@Override
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 {
val baseOptions = baseOptionBuilder.build()
// Create an option builder with base options and specific
@@ -238,32 +241,33 @@ class FaceLandmarkerHelper(
val frameId = result.timestampMs()
if( result.faceLandmarks().size > 0 ) {
// 计算各种延时
val timings = frameTimings[frameId]
if (timings != null) {
val totalLatency = resultTime - timings.captureTime
val preprocessLatency = timings.preprocessEndTime - timings.preprocessStartTime
val detectionLatency = resultTime - timings.detectionStartTime
val captureToDetectionLatency = timings.detectionStartTime - timings.captureTime
Log.i("TimeLatency",
"总延时: ${totalLatency}ms | " +
"预处理: ${preprocessLatency}ms | " +
"检测: ${detectionLatency}ms | " +
"捕获到检测: ${captureToDetectionLatency}ms | " +
"FPS: ${String.format("%.1f", currentFps)}"
)
val finishTimeMs = SystemClock.uptimeMillis()
val inferenceTime = finishTimeMs - result.timestampMs()
faceLandmarkerHelperListener?.onResults(
ResultBundle(
result,
inferenceTime, // 主要是检测时间
input.height,
input.width,
)
)
} else {
// val timings = frameTimings[frameId]
// if (timings != null) {
// val totalLatency = resultTime - timings.captureTime
// val preprocessLatency = timings.preprocessEndTime - timings.preprocessStartTime
// val detectionLatency = resultTime - timings.detectionStartTime
// val captureToDetectionLatency = timings.detectionStartTime - timings.captureTime
//
// Log.i("TimeLatency",
// "总延时: ${totalLatency}ms | " +
// "预处理: ${preprocessLatency}ms | " +
// "检测: ${detectionLatency}ms | " +
// "捕获到检测: ${captureToDetectionLatency}ms | " +
// "FPS: ${String.format("%.1f", currentFps)}"
// )
//
// val finishTimeMs = SystemClock.uptimeMillis()
// val inferenceTime = finishTimeMs - result.timestampMs()
// faceLandmarkerHelperListener?.onResults(
// ResultBundle(
// result,
// inferenceTime, // 主要是检测时间
// input.height,
// input.width,
// )
// )
// } else
//{
val finishTimeMs = SystemClock.uptimeMillis()
val inferenceTime = finishTimeMs - result.timestampMs()
Log.i("TimeLatency",
@@ -277,7 +281,7 @@ class FaceLandmarkerHelper(
input.width
)
)
}
//}
}
else {
faceLandmarkerHelperListener?.onEmpty()
@@ -4,13 +4,12 @@ import org.json.JSONObject;
public class InitArg {
public int action_fps;
public float zoom;
public Motion motion;
public String toJson() {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("action_fps", action_fps);
jsonObject.put("zoom", zoom);
jsonObject.put("motion", motion.toJsonObject());
return jsonObject.toString();
} catch (Exception e) {
e.printStackTrace();
+15 -2
View File
@@ -1,6 +1,19 @@
// 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 {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false // 添加这行
id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
alias(libs.plugins.android.library) 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
}
+29 -2
View File
@@ -1,13 +1,15 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
//alias(libs.plugins.kotlin.android)
}
android {
namespace 'com.hmwl.example'
namespace 'com.inewme.uvmirror'
compileSdk 36
defaultConfig {
applicationId "com.hmwl.f20251110"
applicationId "com.inewme.uvmirror.f20251129"
minSdk 30
targetSdk 36
versionCode 1
@@ -18,6 +20,7 @@ android {
buildTypes {
release {
signingConfig signingConfigs.debug
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
@@ -26,6 +29,20 @@ android {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.5.1'
}
kotlinOptions {
jvmTarget = '17'
}
// kotlinOptions {
// jvmTarget = '17'
// }
}
dependencies {
@@ -33,11 +50,21 @@ dependencies {
implementation libs.appcompat
implementation libs.material
implementation libs.games.activity
implementation libs.core.ktx
implementation libs.androidx.core.ktx
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
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'
implementation "androidx.camera:camera-core:$camerax_version"
+4
View File
@@ -20,6 +20,10 @@
android:name="android.app.lib_name"
android:value="face_sdk" />
</activity>
<activity
android:name=".MakeupActivity"
android:exported="false" />
</application>
</manifest>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

+28 -28
View File
@@ -1,6 +1,30 @@
{
"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.png"
@@ -86,37 +110,13 @@
"78": [
"78.png"
],
"80": [
"80.png"
],
"81": [
"81.png"
],
"82": [
"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"
]
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

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 -1
View File
@@ -1,3 +1,3 @@
<resources>
<string name="app_name">f20251110</string>
<string name="app_name">f20251129</string>
</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);
}
}
+9
View File
@@ -6,6 +6,11 @@ espressoCore = "3.7.0"
appcompat = "1.7.1"
material = "1.13.0"
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]
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" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
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]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" }
+56 -33
View File
@@ -599,12 +599,23 @@ void Application::cleanup() {
vkDestroyImageView(device, imageView, nullptr);
}
for (auto framebuffer : swapChainFramebuffers)
{
if (framebuffer != VK_NULL_HANDLE)
{
vkDestroyFramebuffer(device, framebuffer, nullptr);
}
}
swapChainFramebuffers.clear();
vkDestroySwapchainKHR(device, swapChain, nullptr);
vkDestroyDevice(device, nullptr);
vkDestroySurfaceKHR(instance, surface, nullptr);
vkDestroyInstance(instance, nullptr);
#ifdef _WIN32
glfwDestroyWindow(window);
glfwTerminate();
@@ -630,24 +641,31 @@ uint32_t Application::findMemoryType(VkPhysicalDevice physicalDevice, uint32_t t
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> image;
unsigned w, h;
unsigned error = lodepng::decode(image, w, h, data, LCT_RGBA, 8);
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
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> image;
unsigned w, h;
unsigned error = lodepng::decode(image, w, h, data, LCT_RGBA, 8);
processWithVulkan(image.data(), w, h, w * 4, image.size(), tex, srgb);
return tex;
//return tex;
}
#endif // _WIN32
@@ -751,6 +769,7 @@ void Application::createTexture(VkDevice device, VkPhysicalDevice physicalDevice
}
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)
@@ -809,38 +828,44 @@ void Application::updateTexture(VkDevice device, VkPhysicalDevice physicalDevice
uint8_t* data, int width, int height,
int rowStride, size_t dataSize, Texture& texture)
{
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
//VkBuffer stagingBuffer;
//VkDeviceMemory stagingBufferMemory;
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, &stagingBuffer) != VK_SUCCESS)
if (texture.stagingBuffer == nullptr)
{
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;
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)
if (texture.stagingBufferMemory == nullptr)
{
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;
vkMapMemory(device, stagingBufferMemory, 0, dataSize, 0, &mappedData);
vkMapMemory(device, texture.stagingBufferMemory, 0, dataSize, 0, &mappedData);
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);
@@ -880,7 +905,7 @@ void Application::updateTexture(VkDevice device, VkPhysicalDevice physicalDevice
region.imageExtent = { static_cast<uint32_t>(width),
static_cast<uint32_t>(height), 1 };
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, texture.image,
vkCmdCopyBufferToImage(commandBuffer, texture.stagingBuffer, texture.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
transitionImageLayout(commandBuffer, texture.image,
@@ -889,8 +914,6 @@ void Application::updateTexture(VkDevice device, VkPhysicalDevice physicalDevice
endSingleTimeCommands(device, commandPool, queue, commandBuffer);
vkDestroyBuffer(device, stagingBuffer, nullptr);
vkFreeMemory(device, stagingBufferMemory, nullptr);
texture.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
+14 -2
View File
@@ -15,6 +15,17 @@ struct Texture
VkImageView view;
uint32_t width, height;
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
@@ -74,9 +85,10 @@ 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
Texture loadTextureExample(std::wstring path, Texture& tex, bool srgb);
void loadTextureExample(std::wstring path, Texture& tex, bool srgb);
#endif
uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter,
+290 -58
View File
@@ -1,5 +1,6 @@
#include "FaceApp.h"
#include "hardcode_data.h"
#include "lodepng.h"
#include <sstream>
#include <queue>
#include <vector>
@@ -454,6 +455,10 @@ void FaceApp::create_face_pipelines()
pipeline_create_info.pStages = shader_stages;
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.descriptorSetCount = m_descriptor_sets.size();
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)
{
VkDescriptorBufferInfo buffer_descriptor{};
@@ -572,9 +581,9 @@ void FaceApp::setup_descriptor_set()
VkDescriptorImageInfo image_descriptor;
image_descriptor.imageView = m_texs[i].view;
image_descriptor.sampler = m_texs[i].sampler;
image_descriptor.imageLayout = m_texs[i].image_layout;
image_descriptor.imageView = texs[i].view;
image_descriptor.sampler = texs[i].sampler;
image_descriptor.imageLayout = texs[i].image_layout;
VkWriteDescriptorSet write_descriptor_set_uniform{};
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);
}
}
}
void FaceApp::render(VkCommandBuffer commandBuffer, long long frameTime)
@@ -713,11 +712,25 @@ void FaceApp::initVulkan()
createVmaAllocator();
LoadOBJ("face_picture_3dmax.obj", obj_vertices, obj_indices);
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)
{
loadTexture("demo0.png", m_texs[i], true);
loadTexture("demo0_ex.png", m_texs_ex[i], true);
loadTexture(image, image.size(), w, h, m_texs[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);
@@ -736,7 +749,8 @@ void FaceApp::initVulkan()
uploadVertexData();
last_update_time = getCurrentTimeMillis();
changeMotion(_initArg.motion);
//changeMotion(_initArg.motion);
_running = true;
faceAppInited = true;
#if _WIN32
std::vector<float> floatArray;
@@ -1032,6 +1046,10 @@ void FaceApp::create_pipelines_bg()
pipeline_create_info.pStages = shader_stages;
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()
@@ -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);
}
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()
{
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);
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();
//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)
{
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);
static long long game_time = 0;
game_time += frameTime;
@@ -1134,7 +1320,7 @@ void FaceApp::drawFrame(long long frameTime)
if (game_time > actionTime)
{
_curTexIndex++;
if (_curTexIndex >= _curMotion.png_names.size())
if (_curTexIndex >= _curMotion_png_size)
{
_curTexIndex = 0;
}
@@ -1143,44 +1329,90 @@ void FaceApp::drawFrame(long long 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);
changeMotion(motion);
if (_motionState == loading_next_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;
}
std::unique_lock<std::mutex> lock_changeMotion(changeMotionMtx);
_curMotion = motion;
for (int i = 0; i < _curMotion.png_names.size(); ++i)
if (_motionState != load_next_motion_finished)
{
#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
return;
}
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
//
//
// }
}
+30 -7
View File
@@ -2,6 +2,7 @@
#define __FaceApp_H__
#include "Application.h"
#include <functional>
#include "../third_party/vma/include/vk_mem_alloc.h"
#include <map>
#include <glm/glm.hpp>
@@ -24,8 +25,8 @@ struct InitArg
{
int action_fps;
float zoom;
Motion motion;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(InitArg, action_fps, zoom, motion);
//Motion motion;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(InitArg, action_fps, zoom);
};
@@ -33,7 +34,7 @@ struct PushConstants {
float myValue;
};
using Callback = std::function<void(const std::string&)>;
class FaceApp :public Application
{
@@ -79,6 +80,7 @@ private:
void setup_descriptor_pool();
void setup_descriptor_set_layout();
void setup_descriptor_set();
void update_descriptor_set(vector<Texture>& texs);
const bool kThick = false;
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
@@ -100,8 +102,9 @@ private:
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
vector<VkDescriptorSet> m_descriptor_sets;
const uint32_t kMaxTexture = 30;
const uint32_t kMaxTexture = 60;
vector<Texture> m_texs;
vector<Texture> m_texs_next;
vector<Texture> m_texs_ex;
@@ -135,14 +138,34 @@ private:
public:
void changeMotion(const char* json);
void changeMotion(Motion& motion);
Callback _callback;
string preReadyMotion(const std::string& json, Callback callback);
void changeMotion(const string motion_type);
//void changeMotion(Motion& motion);
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;
void SetInitArg(const char* arg);
void drawFrame(long long frameTime)override;
void destroyTexture(VkDevice device, Texture& texture);
void cleanupResources(VkDevice device, VmaAllocator allocator);
bool _running = false;
};
#endif
+23 -2
View File
@@ -39,6 +39,12 @@ std::wstring ReadFileWithChinesePath(const std::wstring& filePath) {
return AppBase::UTF8ToWideString(context);
}
FaceApp* g_app;
void CppCallback(const string& motion_type)
{
g_app->changeMotion(motion_type.c_str());
}
int main() {
@@ -49,7 +55,8 @@ int main() {
InitArg init_arg;
Motion motion;
motion.type = "action24";
motion.type = "4";
motion.png_names.push_back("4.png");
for (int i = 0; i < 25; ++i)
{
if (i < 10)
@@ -66,7 +73,7 @@ int main() {
#
init_arg.motion = motion;
//init_arg.motion = motion;
init_arg.action_fps = 10;
@@ -75,8 +82,22 @@ int main() {
string json_str = json(init_arg).dump();
FaceApp app;
g_app = &app;
app.SetInitArg(json_str.c_str());
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();
//try {
// app.mainLoop();