save code
This commit is contained in:
+142
-84
@@ -110,7 +110,8 @@ void TextureLoadProcessWithVulkan(uint8_t* data, int width, int height, int rowS
|
||||
oldestFrame.dataSize,
|
||||
tex_bg,
|
||||
false,
|
||||
FaceApp::Get()->commandPool
|
||||
FaceApp::Get()->commandPool,
|
||||
"data_from_camera"
|
||||
);
|
||||
|
||||
frameQueue.pop();
|
||||
@@ -524,13 +525,26 @@ void FaceApp::setup_descriptor_set_layout()
|
||||
pipeline_layout_create_info.setLayoutCount = 1;
|
||||
pipeline_layout_create_info.pSetLayouts = &m_descriptorSetLayout;
|
||||
|
||||
VkPushConstantRange pushConstantRange{};
|
||||
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
pushConstantRange.offset = 0;
|
||||
pushConstantRange.size = sizeof(float);
|
||||
//VkPushConstantRange pushConstantRange{};
|
||||
//pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
//pushConstantRange.offset = 0;
|
||||
//pushConstantRange.size = sizeof(float);
|
||||
|
||||
//pipeline_layout_create_info.pushConstantRangeCount = 1;
|
||||
//pipeline_layout_create_info.pPushConstantRanges = &pushConstantRange;
|
||||
|
||||
VkPushConstantRange pushConstantRanges[1];
|
||||
pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT| VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
pushConstantRanges[0].offset = 0;
|
||||
pushConstantRanges[0].size = sizeof(float)*3;
|
||||
|
||||
//pushConstantRanges[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
//pushConstantRanges[1].offset = sizeof(float);
|
||||
//pushConstantRanges[1].size = 2*sizeof(float);
|
||||
|
||||
|
||||
pipeline_layout_create_info.pushConstantRangeCount = 1;
|
||||
pipeline_layout_create_info.pPushConstantRanges = &pushConstantRange;
|
||||
pipeline_layout_create_info.pPushConstantRanges = &pushConstantRanges[0];
|
||||
|
||||
VK_CHECK(vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, &m_pipelineLayout));
|
||||
}
|
||||
@@ -541,11 +555,11 @@ void FaceApp::setup_descriptor_pool()
|
||||
std::vector<VkDescriptorPoolSize> pool_sizes = {
|
||||
{
|
||||
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = kMaxTexture
|
||||
.descriptorCount = (kTextureMax *2)
|
||||
},
|
||||
{
|
||||
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = (kMaxTexture + 1)
|
||||
.descriptorCount = ((kTextureMax + 1)*2)
|
||||
},
|
||||
// 如果需要其他类型的描述符,在这里添加
|
||||
};
|
||||
@@ -554,7 +568,7 @@ void FaceApp::setup_descriptor_pool()
|
||||
descriptor_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
descriptor_pool_info.poolSizeCount = static_cast<uint32_t>(pool_sizes.size());
|
||||
descriptor_pool_info.pPoolSizes = pool_sizes.data();
|
||||
descriptor_pool_info.maxSets = kMaxTexture + (kMaxTexture + 1);
|
||||
descriptor_pool_info.maxSets = kTextureMax + (kTextureMax + 1 + kTextureMax);
|
||||
descriptor_pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
||||
|
||||
VK_CHECK(vkCreateDescriptorPool(device, &descriptor_pool_info, nullptr, &descriptor_pool));
|
||||
@@ -563,21 +577,31 @@ void FaceApp::setup_descriptor_pool()
|
||||
|
||||
void FaceApp::setup_descriptor_set()
|
||||
{
|
||||
m_descriptor_sets.resize(kMaxTexture);
|
||||
std::vector<VkDescriptorSetLayout> layouts(kMaxTexture, m_descriptorSetLayout);
|
||||
m_descriptor_sets_left.resize(kTextureMax);
|
||||
std::vector<VkDescriptorSetLayout> layouts(kTextureMax, m_descriptorSetLayout);
|
||||
VkDescriptorSetAllocateInfo alloc_info{};
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
alloc_info.descriptorPool = descriptor_pool;
|
||||
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);
|
||||
alloc_info.descriptorSetCount = m_descriptor_sets_left.size();
|
||||
VK_CHECK(vkAllocateDescriptorSets(device, &alloc_info, m_descriptor_sets_left.data()));
|
||||
update_descriptor_set(m_texs_left, m_descriptor_sets_left);
|
||||
|
||||
|
||||
m_descriptor_sets_right.resize(kTextureMax);
|
||||
VK_CHECK(vkAllocateDescriptorSets(device, &alloc_info, m_descriptor_sets_right.data()));
|
||||
update_descriptor_set(m_texs_left, m_descriptor_sets_right);
|
||||
}
|
||||
|
||||
void FaceApp::update_descriptor_set(vector<Texture>& texs)
|
||||
void FaceApp::update_descriptor_set(vector<Texture>& texs, vector<VkDescriptorSet>& descriptSet)
|
||||
{
|
||||
for (int i = 0; i < kMaxTexture; ++i)
|
||||
for (int i = 0; i < kTextureMax; ++i)
|
||||
{
|
||||
if (texs[i].image == VK_NULL_HANDLE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
VkDescriptorBufferInfo buffer_descriptor{};
|
||||
buffer_descriptor.buffer = uniform_buffer_vs;
|
||||
buffer_descriptor.range = VK_WHOLE_SIZE;
|
||||
@@ -591,7 +615,7 @@ void FaceApp::update_descriptor_set(vector<Texture>& texs)
|
||||
|
||||
VkWriteDescriptorSet write_descriptor_set_uniform{};
|
||||
write_descriptor_set_uniform.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set_uniform.dstSet = m_descriptor_sets[i];
|
||||
write_descriptor_set_uniform.dstSet = descriptSet[i];
|
||||
write_descriptor_set_uniform.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
write_descriptor_set_uniform.dstBinding = 0;
|
||||
write_descriptor_set_uniform.pBufferInfo = &buffer_descriptor;
|
||||
@@ -600,7 +624,7 @@ void FaceApp::update_descriptor_set(vector<Texture>& texs)
|
||||
|
||||
VkWriteDescriptorSet write_descriptor_set_image{};
|
||||
write_descriptor_set_image.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set_image.dstSet = m_descriptor_sets[i];
|
||||
write_descriptor_set_image.dstSet = descriptSet[i];
|
||||
write_descriptor_set_image.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
write_descriptor_set_image.dstBinding = 1;
|
||||
write_descriptor_set_image.pImageInfo = &image_descriptor;
|
||||
@@ -610,14 +634,14 @@ void FaceApp::update_descriptor_set(vector<Texture>& texs)
|
||||
{
|
||||
// 第二个纹理描述符 - 假设你的第二个纹理变量名为 tex_demo1
|
||||
VkDescriptorImageInfo image_descriptor1;
|
||||
image_descriptor1.imageView = m_texs_ex[i].view;
|
||||
image_descriptor1.sampler = m_texs_ex[i].sampler;
|
||||
image_descriptor1.imageLayout = m_texs_ex[i].image_layout;
|
||||
image_descriptor1.imageView = m_texs_thick[i].view;
|
||||
image_descriptor1.sampler = m_texs_thick[i].sampler;
|
||||
image_descriptor1.imageLayout = m_texs_thick[i].image_layout;
|
||||
|
||||
// 添加第二个纹理的写入描述符
|
||||
VkWriteDescriptorSet write_descriptor_set_image1{};
|
||||
write_descriptor_set_image1.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set_image1.dstSet = m_descriptor_sets[i];
|
||||
write_descriptor_set_image1.dstSet = descriptSet[i];
|
||||
write_descriptor_set_image1.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
write_descriptor_set_image1.dstBinding = 2; // 绑定到位置2
|
||||
write_descriptor_set_image1.pImageInfo = &image_descriptor1;
|
||||
@@ -656,34 +680,42 @@ void FaceApp::render(VkCommandBuffer commandBuffer, long long frameTime)
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout_bg, 0, 1, &m_descriptor_set_bg, 0, NULL);
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline_bg);
|
||||
|
||||
|
||||
vkCmdPushConstants(commandBuffer, m_pipelineLayout_bg, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float), &myFloatValue);
|
||||
|
||||
|
||||
float fsValues[2] = { 0, 0 };
|
||||
|
||||
vkCmdDraw(commandBuffer, 6, 1, 0, 0);
|
||||
|
||||
|
||||
if (cur_left)
|
||||
{
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descriptor_sets_left[_curMotionIndex], 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descriptor_sets_right[_curMotionIndex], 0, NULL);
|
||||
}
|
||||
|
||||
float fsValues[3] = { myFloatValue, 0 , 0};
|
||||
if (_curMotionIndex < _curMotions.size())
|
||||
{
|
||||
if (_curFrameIndex < _curMotions[_curMotionIndex].frames.size())
|
||||
{
|
||||
float ux = _curMotions[_curMotionIndex].frames[_curFrameIndex].x;
|
||||
float uy = _curMotions[_curMotionIndex].frames[_curFrameIndex].y;
|
||||
fsValues[0] = ux;
|
||||
fsValues[1] = uy;
|
||||
fsValues[1] = ux;
|
||||
fsValues[2] = uy;
|
||||
}
|
||||
}
|
||||
//fsValues[1] = 0;
|
||||
//fsValues[2] = 360;
|
||||
|
||||
vkCmdPushConstants(commandBuffer, m_pipelineLayout_bg, VK_SHADER_STAGE_FRAGMENT_BIT, 4, sizeof(fsValues), fsValues);
|
||||
|
||||
vkCmdDraw(commandBuffer, 6, 1, 0, 0);
|
||||
vkCmdPushConstants(commandBuffer, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT| VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(fsValues), &fsValues);
|
||||
//vkCmdPushConstants(commandBuffer, m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(fsValues), fsValues);
|
||||
|
||||
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descriptor_sets[_curMotionIndex], 0, NULL);
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
||||
|
||||
vkCmdPushConstants(commandBuffer, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float), &myFloatValue);
|
||||
|
||||
VkDeviceSize offsets[1] = { 0 };
|
||||
VkBuffer vertexBuffers[] = { m_vertexBuffer };
|
||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
|
||||
@@ -730,25 +762,24 @@ void FaceApp::initVulkan()
|
||||
Application::initVulkan();
|
||||
createVmaAllocator();
|
||||
LoadOBJ("face_picture_3dmax.obj", obj_vertices, obj_indices);
|
||||
m_texs.resize(kMaxTexture);
|
||||
m_texs_next.resize(kMaxTexture);
|
||||
m_texs_left.resize(kTextureMax);
|
||||
m_texs_right.resize(kTextureMax);
|
||||
if (kThick)
|
||||
{
|
||||
m_texs_ex.resize(kMaxTexture);
|
||||
m_texs_thick.resize(kTextureMax);
|
||||
}
|
||||
|
||||
std::vector<unsigned char> data = readFileUnsignedChar("dummy.png", false);
|
||||
std::vector<unsigned char> image;
|
||||
unsigned w, h;
|
||||
unsigned error = lodepng::decode(image, w, h, data, LCT_RGBA, 8);
|
||||
unsigned error = lodepng::decode(dummy_data, dummy_w, dummy_h, data, LCT_RGBA, 8);
|
||||
|
||||
for (int i = 0; i < kMaxTexture; ++i)
|
||||
for (int i = 0; i < kTextureInit; ++i)
|
||||
{
|
||||
loadTexture(image, image.size(), w, h, m_texs[i], true, commandPool);
|
||||
loadTexture(image, image.size(), w, h, m_texs_next[i], true, commandPool);
|
||||
string id_str = std::to_string(i);
|
||||
loadTexture(dummy_data, dummy_data.size(), dummy_w, dummy_h, m_texs_left[i], true, commandPool, "dummy.png_left_" + id_str);
|
||||
loadTexture(dummy_data, dummy_data.size(), dummy_w, dummy_h, m_texs_right[i], true, commandPool, "dummy.png_right_" + id_str);
|
||||
if (kThick)
|
||||
{
|
||||
loadTexture(image, image.size(), w, h, m_texs_ex[i], true, commandPool);
|
||||
loadTexture(dummy_data, dummy_data.size(), dummy_w, dummy_h, m_texs_thick[i], true, commandPool, "dummy.png_thick_" + id_str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1096,16 +1127,12 @@ void FaceApp::setup_descriptor_set_layout_bg()
|
||||
pipeline_layout_create_info.pSetLayouts = &m_descriptorSetLayout_bg;
|
||||
|
||||
|
||||
VkPushConstantRange pushConstantRanges[2];
|
||||
pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; // 只在片段着色器中使用
|
||||
VkPushConstantRange pushConstantRanges[1];
|
||||
pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
pushConstantRanges[0].offset = 0;
|
||||
pushConstantRanges[0].size = sizeof(float); // 或者 sizeof(PushConstants)
|
||||
pushConstantRanges[0].size = sizeof(float);
|
||||
|
||||
pushConstantRanges[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; // 只在片段着色器中使用
|
||||
pushConstantRanges[1].offset = sizeof(float);
|
||||
pushConstantRanges[1].size = 2 * sizeof(float); // 或者 sizeof(PushConstants)
|
||||
|
||||
pipeline_layout_create_info.pushConstantRangeCount = 2;
|
||||
pipeline_layout_create_info.pushConstantRangeCount = 1;
|
||||
pipeline_layout_create_info.pPushConstantRanges = &pushConstantRanges[0];
|
||||
|
||||
VK_CHECK(vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, &m_pipelineLayout_bg));
|
||||
@@ -1167,6 +1194,7 @@ void FaceApp::destroyTexture(VkDevice device, Texture& texture) {
|
||||
if (texture.device_memory != VK_NULL_HANDLE) {
|
||||
vkFreeMemory(device, texture.device_memory, nullptr);
|
||||
texture.device_memory = VK_NULL_HANDLE;
|
||||
//std::cout << "vkFreeMemory device_memory " << texture.texture_path << std::endl;
|
||||
}
|
||||
|
||||
if (texture.stagingBuffer != VK_NULL_HANDLE)
|
||||
@@ -1178,6 +1206,7 @@ void FaceApp::destroyTexture(VkDevice device, Texture& texture) {
|
||||
if (texture.stagingBufferMemory != VK_NULL_HANDLE)
|
||||
{
|
||||
vkFreeMemory(device, texture.stagingBufferMemory, nullptr);
|
||||
//std::cout << "vkFreeMemory stagingBufferMemory " << texture.texture_path << std::endl;
|
||||
texture.stagingBufferMemory = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
@@ -1256,7 +1285,8 @@ void FaceApp::cleanupResources(VkDevice device, VmaAllocator allocator) {
|
||||
}
|
||||
|
||||
// 清空描述符集列表(不需要单独销毁,由描述符池管理)
|
||||
m_descriptor_sets.clear();
|
||||
m_descriptor_sets_left.clear();
|
||||
m_descriptor_sets_right.clear();
|
||||
}
|
||||
|
||||
void FaceApp::cleanup()
|
||||
@@ -1277,18 +1307,19 @@ void FaceApp::cleanup()
|
||||
}
|
||||
|
||||
cleanupResources(device, allocator);
|
||||
for (int i = 0; i < this->m_texs.size(); ++i)
|
||||
for (int i = 0; i < this->m_texs_left.size(); ++i)
|
||||
{
|
||||
destroyTexture(device, m_texs[i]);
|
||||
destroyTexture(device, m_texs_left[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < this->m_texs_next.size(); ++i)
|
||||
for (int i = 0; i < this->m_texs_right.size(); ++i)
|
||||
{
|
||||
destroyTexture(device, m_texs_next[i]);
|
||||
destroyTexture(device, m_texs_right[i]);
|
||||
}
|
||||
|
||||
destroyTexture(device, tex_bg);
|
||||
vkDestroyCommandPool(device, commandPool, nullptr);
|
||||
vkDestroyCommandPool(device, commandPool_ex, nullptr);
|
||||
Application::cleanup();
|
||||
//if (allocator != VK_NULL_HANDLE) {
|
||||
// vmaDestroyAllocator(allocator);
|
||||
@@ -1340,6 +1371,7 @@ void FaceApp::drawFrame(long long frameTime)
|
||||
|
||||
std::unique_lock lock(changeMotionMtx);
|
||||
|
||||
|
||||
if (_curMotions.size() > 0)
|
||||
{
|
||||
static long long game_time = 0;
|
||||
@@ -1407,21 +1439,38 @@ string FaceApp::preLoadMotionList(string motion_list_str, Callback callback)
|
||||
|
||||
void FaceApp::loadMotionThread()
|
||||
{
|
||||
while (!_running)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
vector<Texture>* load_text = nullptr;
|
||||
if (cur_left)
|
||||
{
|
||||
load_text = &m_texs_right;
|
||||
}
|
||||
else
|
||||
{
|
||||
load_text = &m_texs_left;
|
||||
}
|
||||
|
||||
vector<Texture>& pre_texs = *load_text;
|
||||
for (int i = 0; i < _preLoadMotions.size(); ++i)
|
||||
{
|
||||
if (!_running)
|
||||
if (pre_texs[i].image == VK_NULL_HANDLE)
|
||||
{
|
||||
break;
|
||||
loadTexture(dummy_data, dummy_data.size(), dummy_w, dummy_h, pre_texs[i], true, commandPool, "");
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
string path = "pic";
|
||||
string path_name = path + "/" + _preLoadMotions[i].name + "/" + _preLoadMotions[i].name + "ex.png";
|
||||
loadTextureExample(UTF8ToWideString(path_name), m_texs_next[i], true, commandPool_ex);
|
||||
loadTextureExample(UTF8ToWideString(path_name), pre_texs[i], true, commandPool_ex);
|
||||
#else
|
||||
string path = "pic";
|
||||
string path_name = path + "/" + _preLoadMotions[i].name + "/" + _preLoadMotions[i].name + "ex.png";
|
||||
loadTexture(path_name, m_texs_next[i], true, commandPool_ex);
|
||||
loadTexture(path_name, pre_texs[i], true, commandPool_ex);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
@@ -1429,28 +1478,6 @@ void FaceApp::loadMotionThread()
|
||||
_callback_loadfinish();
|
||||
}
|
||||
|
||||
void FaceApp::doChangeMotion()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock_changeMotion(changeMotionMtx);
|
||||
|
||||
|
||||
for (int i = 0; i < _preLoadMotions.size(); ++i)
|
||||
{
|
||||
destroyTexture(device, m_texs[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _preLoadMotions.size(); ++i)
|
||||
{
|
||||
m_texs[i] = m_texs_next[i];
|
||||
m_texs_next[i].reset();
|
||||
}
|
||||
|
||||
update_descriptor_set(m_texs);
|
||||
_curMotions = _preLoadMotions;
|
||||
|
||||
_curFrameIndex = 0;
|
||||
_curMotionIndex = 0;
|
||||
}
|
||||
|
||||
void FaceApp::changeMotionList(AnimationFinishedCallback callback, bool loop)
|
||||
{
|
||||
@@ -1458,9 +1485,40 @@ void FaceApp::changeMotionList(AnimationFinishedCallback callback, bool loop)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock_changeMotion(changeMotionMtx);
|
||||
|
||||
//for (int i = 0; i < _preLoadMotions.size(); ++i)
|
||||
//{
|
||||
// destroyTexture(device, m_texs[i]);
|
||||
//}
|
||||
|
||||
//for (int i = 0; i < _preLoadMotions.size(); ++i)
|
||||
//{
|
||||
// m_texs[i] = m_texs_next[i];
|
||||
// //m_texs_next[i].reset();
|
||||
//}
|
||||
|
||||
|
||||
if (cur_left)
|
||||
{
|
||||
update_descriptor_set(m_texs_right, m_descriptor_sets_right);
|
||||
cur_left = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
update_descriptor_set(m_texs_left, m_descriptor_sets_left);
|
||||
cur_left = true;
|
||||
}
|
||||
|
||||
_curMotions = _preLoadMotions;
|
||||
|
||||
_curFrameIndex = 0;
|
||||
_curMotionIndex = 0;
|
||||
|
||||
_animationFinishedCallback = callback;
|
||||
_animationLoop = loop;
|
||||
_needChangeMotion = true;
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user