Added android support for distance field fonts example (#97) Fixes (#109)

This commit is contained in:
saschawillems 2016-03-25 21:53:09 +01:00
parent 83eb3de1c0
commit 8ab69b84e0
6 changed files with 214 additions and 59 deletions

10
android/distancefieldfonts/.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
/assets/
/res/
/bin/
/libs/
/obj/
/build.xml
/local.properties
/project.properties
/proguard-project.txt
*.apk

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.saschawillems.vulkanDistancefieldfonts"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="19" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<uses-feature android:name="android.hardware.gamepad" android:required="false"/>
<uses-feature android:name="android.software.leanback" android:required="false"/>
<application android:label="vulkanDistancefieldfonts" android:icon="@drawable/icon" android:hasCode="false">
<activity android:name="android.app.NativeActivity"
android:label="Distance Field Fonts"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:launchMode="singleTask"
android:configChanges="orientation|screenSize|keyboardHidden">
<meta-data android:name="android.app.lib_name" android:value="vulkanDistancefieldfonts" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -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..
)

View file

@ -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)

View file

@ -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

View file

@ -58,43 +58,6 @@ int32_t nextValuePair(std::stringstream *stream)
return val; 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 class VulkanExample : public VulkanExampleBase
{ {
public: public:
@ -179,14 +142,73 @@ public:
vkFreeMemory(device, uniformData.vs.memory, nullptr); 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() void loadTextures()
{ {
textureLoader->loadTexture( textureLoader->loadTexture(
"./../data/textures/font_sdf_rgba.ktx", getAssetPath() + "textures/font_sdf_rgba.ktx",
VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM,
&textures.fontSDF); &textures.fontSDF);
textureLoader->loadTexture( textureLoader->loadTexture(
"./../data/textures/font_bitmap_rgba.ktx", getAssetPath() + "textures/font_bitmap_rgba.ktx",
VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM,
&textures.fontBitmap); &textures.fontBitmap);
} }
@ -207,7 +229,6 @@ public:
VkClearValue clearValues[2]; VkClearValue clearValues[2];
clearValues[0].color = defaultClearColor; clearValues[0].color = defaultClearColor;
clearValues[0].color = { {0.0f, 0.0f, 0.2f, 0.0f} };
clearValues[1].depthStencil = { 1.0f, 0 }; clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo(); VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo();
@ -555,13 +576,14 @@ public:
0xf, 0xf,
VK_TRUE); 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.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR; blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo colorBlendState = VkPipelineColorBlendStateCreateInfo colorBlendState =
vkTools::initializers::pipelineColorBlendStateCreateInfo( vkTools::initializers::pipelineColorBlendStateCreateInfo(
@ -595,8 +617,8 @@ public:
// Load shaders // Load shaders
std::array<VkPipelineShaderStageCreateInfo,2> shaderStages; std::array<VkPipelineShaderStageCreateInfo,2> shaderStages;
shaderStages[0] = loadShader("./../data/shaders/distancefieldfonts/sdf.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[0] = loadShader(getAssetPath() + "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[1] = loadShader(getAssetPath() + "shaders/distancefieldfonts/sdf.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
VkGraphicsPipelineCreateInfo pipelineCreateInfo = VkGraphicsPipelineCreateInfo pipelineCreateInfo =
vkTools::initializers::pipelineCreateInfo( vkTools::initializers::pipelineCreateInfo(
@ -619,8 +641,8 @@ public:
assert(!err); assert(!err);
// Default bitmap font rendering pipeline // Default bitmap font rendering pipeline
shaderStages[0] = loadShader("./../data/shaders/distancefieldfonts/bitmap.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[0] = loadShader(getAssetPath() + "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[1] = loadShader(getAssetPath() + "shaders/distancefieldfonts/bitmap.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.bitmap); err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.bitmap);
assert(!err); assert(!err);
} }
@ -728,8 +750,7 @@ public:
VulkanExample *vulkanExample; VulkanExample *vulkanExample;
#ifdef _WIN32 #if defined(_WIN32)
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
if (vulkanExample != NULL) if (vulkanExample != NULL)
@ -750,9 +771,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
} }
return (DefWindowProc(hWnd, uMsg, wParam, lParam)); return (DefWindowProc(hWnd, uMsg, wParam, lParam));
} }
#elif defined(__linux__) && !defined(__ANDROID__)
#else
static void handleEvent(const xcb_generic_event_t *event) static void handleEvent(const xcb_generic_event_t *event)
{ {
if (vulkanExample != NULL) if (vulkanExample != NULL)
@ -762,21 +781,42 @@ static void handleEvent(const xcb_generic_event_t *event)
} }
#endif #endif
#ifdef _WIN32 // Main entry point
#if defined(_WIN32)
// Windows entry point
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow) 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[]) int main(const int argc, const char *argv[])
#endif #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(); vulkanExample = new VulkanExample();
#ifdef _WIN32 #if defined(_WIN32)
vulkanExample->setupWindow(hInstance, WndProc); 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(); vulkanExample->setupWindow();
#endif #endif
#if !defined(__ANDROID__)
vulkanExample->initSwapchain(); vulkanExample->initSwapchain();
vulkanExample->prepare(); vulkanExample->prepare();
#endif
vulkanExample->renderLoop(); vulkanExample->renderLoop();
#if !defined(__ANDROID__)
delete(vulkanExample); delete(vulkanExample);
return 0; return 0;
} #endif
}