diff --git a/android/distancefieldfonts/.gitignore b/android/distancefieldfonts/.gitignore new file mode 100644 index 00000000..7a5d249c --- /dev/null +++ b/android/distancefieldfonts/.gitignore @@ -0,0 +1,10 @@ +/assets/ +/res/ +/bin/ +/libs/ +/obj/ +/build.xml +/local.properties +/project.properties +/proguard-project.txt +*.apk \ No newline at end of file diff --git a/android/distancefieldfonts/AndroidManifest.xml b/android/distancefieldfonts/AndroidManifest.xml new file mode 100644 index 00000000..a1fdbb46 --- /dev/null +++ b/android/distancefieldfonts/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/android/distancefieldfonts/build.bat b/android/distancefieldfonts/build.bat new file mode 100644 index 00000000..9f5fddb6 --- /dev/null +++ b/android/distancefieldfonts/build.bat @@ -0,0 +1,23 @@ +cd jni +call ndk-build +if %ERRORLEVEL% EQU 0 ( + echo ndk-build has failed, build cancelled + cd.. + + mkdir "assets\shaders\distancefieldfonts" + xcopy "..\..\data\shaders\distancefieldfonts\*.spv" "assets\shaders\distancefieldfonts" /Y + + mkdir "assets\textures" + xcopy "..\..\data\textures\font_sdf_rgba.ktx" "assets\textures" /Y + xcopy "..\..\data\textures\font_bitmap_rgba.ktx" "assets\textures" /Y + + xcopy "..\..\data\font.fnt" "assets" /Y + + mkdir "res\drawable" + xcopy "..\..\android\images\icon.png" "res\drawable" /Y + + call ant debug -Dout.final.file=vulkanDistancefieldfonts.apk +) ELSE ( + echo error : ndk-build failed with errors! + cd.. +) diff --git a/android/distancefieldfonts/jni/Android.mk b/android/distancefieldfonts/jni/Android.mk new file mode 100644 index 00000000..aabab29c --- /dev/null +++ b/android/distancefieldfonts/jni/Android.mk @@ -0,0 +1,50 @@ +LOCAL_PATH := $(call my-dir)/../../distancefieldfonts + +# assimp + +include $(CLEAR_VARS) + +LOCAL_MODULE := assimp +LOCAL_SRC_FILES := $(LOCAL_PATH)/../../libs/assimp/$(TARGET_ARCH_ABI)/libassimp.a +include $(PREBUILT_STATIC_LIBRARY) + +# vulkan example + +DATADIR := $(LOCAL_PATH)/../../data + +include $(CLEAR_VARS) + +LOCAL_MODULE := vulkanDistancefieldfonts + +PROJECT_FILES := $(wildcard $(LOCAL_PATH)/../../distancefieldfonts/*.cpp) +PROJECT_FILES += $(wildcard $(LOCAL_PATH)/../../base/*.cpp) + +# stringstream usage causes some warnings that would fail the build +LOCAL_DISABLE_FATAL_LINKER_WARNINGS := true + +LOCAL_CPPFLAGS := -std=c++11 +LOCAL_CPPFLAGS += -D__STDC_LIMIT_MACROS +LOCAL_CPPFLAGS += -DVK_NO_PROTOTYPES +LOCAL_CPPFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../external/ +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../external/glm +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../external/gli +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../external/assimp +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../base/ +#LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../base/android + +LOCAL_SRC_FILES := $(PROJECT_FILES) + +LOCAL_LDLIBS := -landroid -llog -lz + +LOCAL_DISABLE_FORMAT_STRING_CHECKS := true + +LOCAL_STATIC_LIBRARIES += android_native_app_glue +LOCAL_STATIC_LIBRARIES += cpufeatures +LOCAL_STATIC_LIBRARIES += libassimp + +include $(BUILD_SHARED_LIBRARY) + +$(call import-module, android/native_app_glue) +$(call import-module, android/cpufeatures) diff --git a/android/distancefieldfonts/jni/Application.mk b/android/distancefieldfonts/jni/Application.mk new file mode 100644 index 00000000..62020feb --- /dev/null +++ b/android/distancefieldfonts/jni/Application.mk @@ -0,0 +1,5 @@ +APP_PLATFORM := android-19 +APP_ABI := armeabi-v7a +APP_STL := c++_static +APP_CPPFLAGS := -std=c++11 +NDK_TOOLCHAIN_VERSION := clang diff --git a/distancefieldfonts/distancefieldfonts.cpp b/distancefieldfonts/distancefieldfonts.cpp index 15c768c3..587a5217 100644 --- a/distancefieldfonts/distancefieldfonts.cpp +++ b/distancefieldfonts/distancefieldfonts.cpp @@ -58,43 +58,6 @@ int32_t nextValuePair(std::stringstream *stream) return val; } -void parsebmFont() -{ - const char *filename = "../data/font.fnt"; - - std::ifstream fstream(filename); - assert(fstream.good()); - - while (!fstream.eof()) - { - std::string line; - std::stringstream lineStream; - std::getline(fstream, line); - lineStream << line; - - std::string info; - lineStream >> info; - - if (info == "char") - { - std::string pair; - - // char id - uint32_t charid = nextValuePair(&lineStream); - // Char properties - fontChars[charid].x = nextValuePair(&lineStream); - fontChars[charid].y = nextValuePair(&lineStream); - fontChars[charid].width = nextValuePair(&lineStream); - fontChars[charid].height = nextValuePair(&lineStream); - fontChars[charid].xoffset = nextValuePair(&lineStream); - fontChars[charid].yoffset = nextValuePair(&lineStream); - fontChars[charid].xadvance = nextValuePair(&lineStream); - fontChars[charid].page = nextValuePair(&lineStream); - } - } - -} - class VulkanExample : public VulkanExampleBase { public: @@ -179,14 +142,73 @@ public: vkFreeMemory(device, uniformData.vs.memory, nullptr); } + // Basic parser fpr AngelCode bitmap font format files + // See http://www.angelcode.com/products/bmfont/doc/file_format.html for details + void parsebmFont() + { + std::string fileName = getAssetPath() + "font.fnt"; + +#if defined(__ANDROID__) + // Font description file is stored inside the apk + // So we need to load it using the asset manager + AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, fileName.c_str(), AASSET_MODE_STREAMING); + assert(asset); + size_t size = AAsset_getLength(asset); + + assert(size > 0); + + void *fileData = malloc(size); + AAsset_read(asset, fileData, size); + AAsset_close(asset); + + std::stringbuf sbuf((const char*)fileData); + std::istream istream(&sbuf); +#else + FILE *file = fopen(fileName.c_str(), "r"); + std::filebuf fileBuffer(file); + std::istream istream(&fileBuffer); +#endif + + assert(istream.good()); + + while (!istream.eof()) + { + std::string line; + std::stringstream lineStream; + std::getline(istream, line); + lineStream << line; + + std::string info; + lineStream >> info; + + if (info == "char") + { + std::string pair; + + // char id + uint32_t charid = nextValuePair(&lineStream); + // Char properties + fontChars[charid].x = nextValuePair(&lineStream); + fontChars[charid].y = nextValuePair(&lineStream); + fontChars[charid].width = nextValuePair(&lineStream); + fontChars[charid].height = nextValuePair(&lineStream); + fontChars[charid].xoffset = nextValuePair(&lineStream); + fontChars[charid].yoffset = nextValuePair(&lineStream); + fontChars[charid].xadvance = nextValuePair(&lineStream); + fontChars[charid].page = nextValuePair(&lineStream); + } + } + + } + void loadTextures() { textureLoader->loadTexture( - "./../data/textures/font_sdf_rgba.ktx", + getAssetPath() + "textures/font_sdf_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, &textures.fontSDF); textureLoader->loadTexture( - "./../data/textures/font_bitmap_rgba.ktx", + getAssetPath() + "textures/font_bitmap_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, &textures.fontBitmap); } @@ -207,7 +229,6 @@ public: VkClearValue clearValues[2]; clearValues[0].color = defaultClearColor; - clearValues[0].color = { {0.0f, 0.0f, 0.2f, 0.0f} }; clearValues[1].depthStencil = { 1.0f, 0 }; VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo(); @@ -555,13 +576,14 @@ public: 0xf, VK_TRUE); + blendAttachmentState.blendEnable = VK_TRUE; + blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; - blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR; - blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; - blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - blendAttachmentState.blendEnable = VK_FALSE; + blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; VkPipelineColorBlendStateCreateInfo colorBlendState = vkTools::initializers::pipelineColorBlendStateCreateInfo( @@ -595,8 +617,8 @@ public: // Load shaders std::array shaderStages; - shaderStages[0] = loadShader("./../data/shaders/distancefieldfonts/sdf.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader("./../data/shaders/distancefieldfonts/sdf.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + shaderStages[0] = loadShader(getAssetPath() + "shaders/distancefieldfonts/sdf.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getAssetPath() + "shaders/distancefieldfonts/sdf.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); VkGraphicsPipelineCreateInfo pipelineCreateInfo = vkTools::initializers::pipelineCreateInfo( @@ -619,8 +641,8 @@ public: assert(!err); // Default bitmap font rendering pipeline - shaderStages[0] = loadShader("./../data/shaders/distancefieldfonts/bitmap.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader("./../data/shaders/distancefieldfonts/bitmap.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + shaderStages[0] = loadShader(getAssetPath() + "shaders/distancefieldfonts/bitmap.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getAssetPath() + "shaders/distancefieldfonts/bitmap.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.bitmap); assert(!err); } @@ -728,8 +750,7 @@ public: VulkanExample *vulkanExample; -#ifdef _WIN32 - +#if defined(_WIN32) LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (vulkanExample != NULL) @@ -750,9 +771,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } return (DefWindowProc(hWnd, uMsg, wParam, lParam)); } - -#else - +#elif defined(__linux__) && !defined(__ANDROID__) static void handleEvent(const xcb_generic_event_t *event) { if (vulkanExample != NULL) @@ -762,21 +781,42 @@ static void handleEvent(const xcb_generic_event_t *event) } #endif -#ifdef _WIN32 +// Main entry point +#if defined(_WIN32) +// Windows entry point int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow) -#else +#elif defined(__ANDROID__) +// Android entry point +void android_main(android_app* state) +#elif defined(__linux__) +// Linux entry point int main(const int argc, const char *argv[]) #endif { +#if defined(__ANDROID__) + // Removing this may cause the compiler to omit the main entry point + // which would make the application crash at start + app_dummy(); +#endif vulkanExample = new VulkanExample(); -#ifdef _WIN32 +#if defined(_WIN32) vulkanExample->setupWindow(hInstance, WndProc); -#else +#elif defined(__ANDROID__) + // Attach vulkan example to global android application state + state->userData = vulkanExample; + state->onAppCmd = VulkanExample::handleAppCommand; + state->onInputEvent = VulkanExample::handleAppInput; + vulkanExample->androidApp = state; +#elif defined(__linux__) vulkanExample->setupWindow(); #endif +#if !defined(__ANDROID__) vulkanExample->initSwapchain(); vulkanExample->prepare(); +#endif vulkanExample->renderLoop(); +#if !defined(__ANDROID__) delete(vulkanExample); return 0; -} +#endif +} \ No newline at end of file