Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da2c97e412 | ||
|
|
db80a5dbbd | ||
|
|
634d22f3be | ||
|
|
835f768a4a | ||
|
|
1859706412 | ||
|
|
9c71e40c97 | ||
|
|
84d567674f | ||
|
|
43b00c8446 | ||
|
|
e23ccd75cd | ||
|
|
8623b71ab7 | ||
|
|
16efcbcff3 |
@@ -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'
|
||||
|
||||
@@ -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)));
|
||||
@@ -163,3 +165,107 @@ 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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
android:name="android.app.lib_name"
|
||||
android:value="face_sdk" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".MakeupActivity"
|
||||
android:exported="false" />
|
||||
</application>
|
||||
|
||||
</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.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"
|
||||
]
|
||||
}
|
||||
|
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>
|
||||
<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);
|
||||
}
|
||||
}
|
||||
@@ -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" }
|
||||
|
||||
@@ -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, ®ion);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
//
|
||||
//
|
||||
// }
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||