451 lines
14 KiB
C++
451 lines
14 KiB
C++
#include "AppBase.h"
|
|
#include <assert.h>
|
|
|
|
#ifdef _WIN32
|
|
#else
|
|
#include <android/asset_manager.h>
|
|
extern AAssetManager* g_assetManager;
|
|
#endif // _WIN32
|
|
|
|
|
|
void VK_CHECK(VkResult ret)
|
|
{
|
|
assert(ret == VK_SUCCESS);
|
|
}
|
|
|
|
//std::string AppBase::getPath(const std::string path)
|
|
//{
|
|
//#ifdef _WIN32
|
|
// std::string android_path = "app/src/main/assets/" + path;
|
|
// return android_path;
|
|
//#endif
|
|
// return path;
|
|
//}
|
|
|
|
std::vector<unsigned char> AppBase::readFileUnsignedChar(const std::string& path, bool example)
|
|
{
|
|
std::vector<unsigned char> buffer;
|
|
#ifdef _WIN32
|
|
std::string enginePath = "app/src/main/assets/" + path;
|
|
if (example)
|
|
{
|
|
enginePath = "example/src/main/assets/" + path;
|
|
}
|
|
std::ifstream file{ enginePath, std::ios::ate | std::ios::binary };
|
|
|
|
if (!file.is_open())
|
|
{
|
|
throw std::runtime_error("failed to open file: " + enginePath);
|
|
}
|
|
|
|
size_t fileSize = static_cast<size_t>(file.tellg());
|
|
buffer.resize(fileSize);
|
|
|
|
file.seekg(0);
|
|
file.read((char*)buffer.data(), fileSize);
|
|
file.close();
|
|
#else
|
|
AAsset* asset = AAssetManager_open(g_assetManager, path.c_str(), AASSET_MODE_BUFFER);
|
|
if (!asset) {
|
|
logOut << "Failed to load file: " << path.c_str() << std::endl;
|
|
return buffer;
|
|
}
|
|
|
|
size_t length = AAsset_getLength(asset);
|
|
buffer.resize(length);
|
|
AAsset_read(asset, (char*)buffer.data(), length);
|
|
AAsset_close(asset);
|
|
#endif // _WIN32
|
|
return buffer;
|
|
}
|
|
|
|
std::vector<char> AppBase::readFile(const std::string& path)
|
|
{
|
|
std::vector<char> buffer;
|
|
#ifdef _WIN32
|
|
std::string enginePath = "app/src/main/assets/" + path;
|
|
std::ifstream file{ enginePath, std::ios::ate | std::ios::binary };
|
|
|
|
if (!file.is_open())
|
|
{
|
|
throw std::runtime_error("failed to open file: " + enginePath);
|
|
}
|
|
|
|
size_t fileSize = static_cast<size_t>(file.tellg());
|
|
buffer.resize(fileSize);
|
|
|
|
file.seekg(0);
|
|
file.read(buffer.data(), fileSize);
|
|
file.close();
|
|
#else
|
|
AAsset* asset = AAssetManager_open(g_assetManager, path.c_str(), AASSET_MODE_BUFFER);
|
|
if (!asset) {
|
|
logOut << "Failed to load file: " << path.c_str() << std::endl;
|
|
return buffer;
|
|
}
|
|
|
|
size_t length = AAsset_getLength(asset);
|
|
buffer.resize(length);
|
|
AAsset_read(asset, buffer.data(), length);
|
|
AAsset_close(asset);
|
|
#endif // _WIN32
|
|
return buffer;
|
|
}
|
|
|
|
VkShaderModule AppBase::createShaderModule(VkDevice& device, const std::vector<char>& code)
|
|
{
|
|
VkShaderModuleCreateInfo createInfo{};
|
|
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
createInfo.codeSize = code.size();
|
|
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
|
|
|
|
VkShaderModule shaderModule;
|
|
if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS)
|
|
{
|
|
throw std::runtime_error("failed to create shader module!");
|
|
}
|
|
|
|
return shaderModule;
|
|
}
|
|
|
|
bool AppBase::checkValidationLayerSupport() {
|
|
uint32_t layerCount;
|
|
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
|
|
|
std::vector<VkLayerProperties> availableLayers(layerCount);
|
|
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
|
for (const char* layerName : validationLayers) {
|
|
bool layerFound = false;
|
|
|
|
for (const auto& layerProperties : availableLayers) {
|
|
if (strcmp(layerName, layerProperties.layerName) == 0) {
|
|
layerFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!layerFound) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void checkInstanceExtensions() {
|
|
uint32_t extensionCount = 0;
|
|
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
|
|
|
|
std::vector<VkExtensionProperties> extensions(extensionCount);
|
|
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
|
|
|
|
logOut << "Android Available instance extensions:" << std::endl;
|
|
for (const auto& extension : extensions) {
|
|
logOut << "ExtensionName:" << extension.extensionName << " Version:" << extension.specVersion << std::endl;
|
|
}
|
|
}
|
|
|
|
void AppBase::createInstance()
|
|
{
|
|
if (enableValidationLayers && !checkValidationLayerSupport()) {
|
|
throw std::runtime_error("validation layers requested, but not available!");
|
|
}
|
|
|
|
VkApplicationInfo appInfo{};
|
|
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
appInfo.pApplicationName = "example";
|
|
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
|
|
appInfo.pEngineName = "No Engine";
|
|
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
|
appInfo.apiVersion = VK_API_VERSION_1_0;
|
|
|
|
VkInstanceCreateInfo createInfo{};
|
|
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
createInfo.pApplicationInfo = &appInfo;
|
|
std::vector<const char*> extensions;
|
|
#ifdef _WIN32
|
|
// 获取 GLFW 所需的扩展
|
|
uint32_t glfwExtensionCount = 0;
|
|
const char** glfwExtensions;
|
|
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
|
|
|
// 添加调试扩展
|
|
for(int i = 0; i < glfwExtensionCount; i++) {
|
|
extensions.push_back(glfwExtensions[i]);
|
|
}
|
|
#else
|
|
checkInstanceExtensions();
|
|
// Android: 手动添加必要的扩展
|
|
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
|
|
|
// 可选:添加这些扩展以获得更好的兼容性
|
|
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
|
#endif
|
|
|
|
if (enableValidationLayers) {
|
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
|
}
|
|
|
|
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
|
createInfo.ppEnabledExtensionNames = extensions.data();
|
|
|
|
if (enableValidationLayers) {
|
|
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
|
|
createInfo.ppEnabledLayerNames = validationLayers.data();
|
|
}
|
|
else {
|
|
createInfo.enabledLayerCount = 0;
|
|
}
|
|
|
|
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
|
|
throw std::runtime_error("failed to create instance!");
|
|
}
|
|
}
|
|
|
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
|
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
|
void* pUserData) {
|
|
|
|
std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
|
|
|
|
return VK_FALSE;
|
|
}
|
|
|
|
VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) {
|
|
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
|
if (func != nullptr) {
|
|
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
|
|
}
|
|
else {
|
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
|
}
|
|
}
|
|
|
|
void AppBase::setupDebugMessenger() {
|
|
if (!enableValidationLayers)
|
|
return;
|
|
|
|
VkDebugUtilsMessengerCreateInfoEXT createInfo{};
|
|
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
|
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
|
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
|
createInfo.pfnUserCallback = debugCallback;
|
|
createInfo.pUserData = nullptr; // Optional
|
|
|
|
if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
|
|
throw std::runtime_error("failed to set up debug messenger!");
|
|
}
|
|
}
|
|
|
|
|
|
QueueFamilyIndices AppBase::findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR& surface) {
|
|
QueueFamilyIndices indices;
|
|
|
|
uint32_t queueFamilyCount = 0;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
|
|
|
|
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
|
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
|
|
|
|
int i = 0;
|
|
for (const auto& queueFamily : queueFamilies) {
|
|
if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
|
indices.graphicsFamily = i;
|
|
}
|
|
VkBool32 presentSupport = false;
|
|
VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport));
|
|
if (presentSupport) {
|
|
indices.presentFamily = i;
|
|
}
|
|
if (indices.isComplete()) {
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
return indices;
|
|
}
|
|
|
|
bool AppBase::checkSwapChainSupport(VkPhysicalDevice device, VkSurfaceKHR& surface) {
|
|
uint32_t formatCount;
|
|
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
|
|
|
|
uint32_t presentModeCount;
|
|
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
|
|
|
|
return formatCount > 0 && presentModeCount > 0;
|
|
}
|
|
|
|
bool AppBase::checkDeviceExtensionSupport(VkPhysicalDevice device) {
|
|
// 获取设备支持的扩展数量
|
|
uint32_t extensionCount;
|
|
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
|
|
|
|
// 获取设备支持的扩展列表
|
|
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
|
|
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
|
|
|
|
// 定义需要的扩展
|
|
const std::vector<const char*> requiredExtensions = {
|
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
|
};
|
|
|
|
// 检查所有需要的扩展是否都支持
|
|
for (const char* requiredExtension : requiredExtensions) {
|
|
bool extensionFound = false;
|
|
for (const auto& extension : availableExtensions) {
|
|
if (strcmp(requiredExtension, extension.extensionName) == 0) {
|
|
extensionFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!extensionFound) {
|
|
return false; // 如果有一个扩展不支持,返回 false
|
|
}
|
|
}
|
|
|
|
return true; // 所有扩展都支持
|
|
}
|
|
|
|
|
|
bool AppBase::isDeviceSuitable(VkPhysicalDevice device, VkSurfaceKHR& surface) {
|
|
QueueFamilyIndices indices = findQueueFamilies(device, surface);
|
|
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
|
bool swapChainAdequate = false;
|
|
if (extensionsSupported) {
|
|
swapChainAdequate = checkSwapChainSupport(device, surface);
|
|
}
|
|
return indices.isComplete() && extensionsSupported && swapChainAdequate;
|
|
}
|
|
|
|
void AppBase::pickPhysicalDevice(VkPhysicalDevice& physicalDevice, VkSurfaceKHR& surface)
|
|
{
|
|
uint32_t deviceCount = 0;
|
|
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
|
|
if (deviceCount == 0) {
|
|
throw std::runtime_error("failed to find GPUs with Vulkan support!");
|
|
}
|
|
std::vector<VkPhysicalDevice> devices(deviceCount);
|
|
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
|
|
|
for (const auto& device : devices) {
|
|
if (isDeviceSuitable(device, surface)) {
|
|
physicalDevice = device;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (physicalDevice == VK_NULL_HANDLE) {
|
|
throw std::runtime_error("failed to find a suitable GPU!");
|
|
}
|
|
}
|
|
|
|
|
|
// 计算面的法线
|
|
void AppBase::calculateFaceNormal(const TextureLoadingVertexStructure& v0,
|
|
const TextureLoadingVertexStructure& v1,
|
|
const TextureLoadingVertexStructure& v2,
|
|
float* outNormal)
|
|
{
|
|
// 计算两个边向量
|
|
float edge1[3] = { v1.pos[0] - v0.pos[0], v1.pos[1] - v0.pos[1], v1.pos[2] - v0.pos[2] };
|
|
float edge2[3] = { v2.pos[0] - v0.pos[0], v2.pos[1] - v0.pos[1], v2.pos[2] - v0.pos[2] };
|
|
|
|
// 叉积计算法线
|
|
outNormal[0] = edge1[1] * edge2[2] - edge1[2] * edge2[1];
|
|
outNormal[1] = edge1[2] * edge2[0] - edge1[0] * edge2[2];
|
|
outNormal[2] = edge1[0] * edge2[1] - edge1[1] * edge2[0];
|
|
|
|
// 归一化
|
|
float length = std::sqrt(outNormal[0] * outNormal[0] +
|
|
outNormal[1] * outNormal[1] +
|
|
outNormal[2] * outNormal[2]);
|
|
|
|
if (length > 0.0f) {
|
|
outNormal[0] /= length;
|
|
outNormal[1] /= length;
|
|
outNormal[2] /= length;
|
|
}
|
|
}
|
|
|
|
// 计算所有顶点的法线
|
|
void AppBase::calculateVertexNormals(std::vector<TextureLoadingVertexStructure>& obj_vertices,
|
|
const std::vector<uint32_t>& obj_indices)
|
|
{
|
|
// 验证索引数量是3的倍数
|
|
if (obj_indices.size() % 3 != 0) {
|
|
return; // 或者抛出异常
|
|
}
|
|
|
|
// 为每个顶点创建法线累加器和计数
|
|
std::vector<std::array<float, 3>> normalSums(obj_vertices.size(), { 0.0f, 0.0f, 0.0f });
|
|
std::vector<int> normalCounts(obj_vertices.size(), 0);
|
|
|
|
// 遍历所有三角形
|
|
for (size_t i = 0; i < obj_indices.size(); i += 3) {
|
|
uint32_t idx0 = obj_indices[i];
|
|
uint32_t idx1 = obj_indices[i + 1];
|
|
uint32_t idx2 = obj_indices[i + 2];
|
|
|
|
// 验证索引有效性
|
|
if (idx0 >= obj_vertices.size() || idx1 >= obj_vertices.size() || idx2 >= obj_vertices.size()) {
|
|
continue;
|
|
}
|
|
|
|
// 获取三角形的三个顶点
|
|
const auto& v0 = obj_vertices[idx0];
|
|
const auto& v1 = obj_vertices[idx1];
|
|
const auto& v2 = obj_vertices[idx2];
|
|
|
|
// 计算面的法线
|
|
float faceNormal[3];
|
|
calculateFaceNormal(v0, v1, v2, faceNormal);
|
|
|
|
// 将面法线累加到每个顶点
|
|
for (int j = 0; j < 3; j++) {
|
|
normalSums[idx0][j] += faceNormal[j];
|
|
normalSums[idx1][j] += faceNormal[j];
|
|
normalSums[idx2][j] += faceNormal[j];
|
|
}
|
|
|
|
normalCounts[idx0]++;
|
|
normalCounts[idx1]++;
|
|
normalCounts[idx2]++;
|
|
}
|
|
|
|
// 计算每个顶点的平均法线并归一化
|
|
for (size_t i = 0; i < obj_vertices.size(); i++) {
|
|
if (normalCounts[i] > 0) {
|
|
// 计算平均值
|
|
float avgNormal[3] = {
|
|
normalSums[i][0] / normalCounts[i],
|
|
normalSums[i][1] / normalCounts[i],
|
|
normalSums[i][2] / normalCounts[i]
|
|
};
|
|
|
|
// 归一化
|
|
float length = std::sqrt(avgNormal[0] * avgNormal[0] +
|
|
avgNormal[1] * avgNormal[1] +
|
|
avgNormal[2] * avgNormal[2]);
|
|
|
|
if (length > 0.0f) {
|
|
obj_vertices[i].normal[0] = avgNormal[0] / length;
|
|
obj_vertices[i].normal[1] = avgNormal[1] / length;
|
|
obj_vertices[i].normal[2] = avgNormal[2] / length;
|
|
}
|
|
else {
|
|
// 如果法线长度为0,设置为默认值
|
|
obj_vertices[i].normal[0] = 0.0f;
|
|
obj_vertices[i].normal[1] = 1.0f;
|
|
obj_vertices[i].normal[2] = 0.0f;
|
|
}
|
|
}
|
|
else {
|
|
// 如果没有面使用这个顶点,设置默认法线
|
|
obj_vertices[i].normal[0] = 0.0f;
|
|
obj_vertices[i].normal[1] = 1.0f;
|
|
obj_vertices[i].normal[2] = 0.0f;
|
|
}
|
|
}
|
|
} |