Compare commits
123 Commits
release-1.
...
master
Author | SHA1 | Date |
---|---|---|
|
214ae33246 | |
|
3c54bc474c | |
|
0da56dd552 | |
|
b86a27531b | |
|
8b149bf8f4 | |
|
61a96c7988 | |
|
0d64c98854 | |
|
a02d1ba71e | |
|
849599afd8 | |
|
874fec434a | |
|
e4f020d359 | |
|
f144bfdb2d | |
|
75b5046684 | |
|
669ed5e098 | |
|
8b47314e72 | |
|
b8e7957d91 | |
|
2eb571b1ff | |
|
010c6b097c | |
|
3125bb9c95 | |
|
4cc2c03afe | |
|
06e42ead57 | |
|
a23dbdfe15 | |
|
7b8d2db565 | |
|
eed6d4751c | |
|
2bafd5dbd7 | |
|
14b2d22fbd | |
|
2823aa3197 | |
|
261e7f41d6 | |
|
02418aa42a | |
|
e08f6e2022 | |
|
dd14ed30ea | |
|
35958b13f7 | |
|
5b57d55c28 | |
|
d779d17b3d | |
|
5e80aa1a04 | |
|
f75a469e38 | |
|
8c66e7aa7a | |
|
3f13440acb | |
|
c637b407c8 | |
|
f2d6b04782 | |
|
85b5184d29 | |
|
64c63d4184 | |
|
915b896636 | |
|
d61b2c45d6 | |
|
e9be4d45d2 | |
|
ba7c823c91 | |
|
0b1220c114 | |
|
5f8f70ed53 | |
|
05252bfae8 | |
|
ea93f80aa1 | |
|
48fb1589c6 | |
|
01bffc71ac | |
|
e6d89add57 | |
|
37afc006d2 | |
|
10d411bafd | |
|
ddecaddccc | |
|
ae825faf32 | |
|
a07d32e44a | |
|
9ff2e51ff1 | |
|
2ca0bb9b5b | |
|
169e05c970 | |
|
001b3b60ec | |
|
6e952e511e | |
|
8503c549d7 | |
|
96d6a52a74 | |
|
10823cd459 | |
|
26514fd142 | |
|
fb7f91185d | |
|
f56cc119bf | |
|
478bb8ecb1 | |
|
79482d1c4d | |
|
ecd2a8d738 | |
|
2c1d55fc30 | |
|
571a21914c | |
|
26a1270702 | |
|
e65d37e846 | |
|
19910be27e | |
|
34a73082a6 | |
|
38813f98b4 | |
|
c5171ffc03 | |
|
e509588f61 | |
|
6bad0ac9c0 | |
|
cccc6ca8c3 | |
|
0398903585 | |
|
392c4eaf8f | |
|
3dc48ef05e | |
|
c6546b43b5 | |
|
1148e48085 | |
|
ce440f2913 | |
|
b07ce8514e | |
|
467e73d3a8 | |
|
1b9faac310 | |
|
615c39a4fe | |
|
709029f22c | |
|
8e6589ec67 | |
|
69a05c00e9 | |
|
d7e444fa81 | |
|
8a87597911 | |
|
22d80d6152 | |
|
67632ff144 | |
|
8fd24a3c1a | |
|
305b23738c | |
|
83400a0b52 | |
|
fdbbb2a6fd | |
|
ab4c0c7e57 | |
|
325b07d844 | |
|
05b86a38c1 | |
|
0876203d82 | |
|
f54835e5f3 | |
|
ba246eca7f | |
|
068656ddc2 | |
|
00f57bab05 | |
|
3bc8785469 | |
|
5c6e414a15 | |
|
1d1452d4aa | |
|
557eb517cb | |
|
e376b1bc17 | |
|
76fb19ab3a | |
|
a39efa5d3c | |
|
7b637a95d9 | |
|
29ce485ca3 | |
|
7d458859d7 | |
|
685b17aba6 |
|
@ -1,7 +1,2 @@
|
|||
BasedOnStyle: Chromium
|
||||
Standard: Cpp11
|
||||
|
||||
MacroBlockBegin: "^\
|
||||
RENDER_COMMAND_BEGIN$"
|
||||
MacroBlockEnd: "^\
|
||||
RENDER_COMMAND_END$"
|
||||
|
|
|
@ -4,8 +4,4 @@ build/android/*.idsig
|
|||
build/android/app/.cxx
|
||||
build/android/app/build
|
||||
build/android/build
|
||||
build/linux/demo_x86_64_debug
|
||||
build/linux/demo_x86_64_release
|
||||
build/linux/obj
|
||||
build/linux/woom
|
||||
out
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# The location of the build configuration file.
|
||||
buildconfig = "//build/BUILDCONFIG.gn"
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [
|
||||
"OS_LINUX"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Mac",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [
|
||||
"OS_MAC"
|
||||
],
|
||||
"macFrameworkPath": [
|
||||
"/System/Library/Frameworks",
|
||||
"/Library/Frameworks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [
|
||||
"OS_WIN"
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
|
@ -5,13 +5,13 @@
|
|||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(gdb) Launch",
|
||||
"name": "Debug demo - Linux",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/linux/demo_x86_64_debug",
|
||||
"program": "${workspaceFolder}/out/debug/demo",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}/build/linux",
|
||||
"cwd": "${workspaceFolder}/out/debug",
|
||||
"environment": [],
|
||||
"console": "externalTerminal",
|
||||
"MIMode": "gdb",
|
||||
|
@ -22,6 +22,19 @@
|
|||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
"preLaunchTask": "Build project",
|
||||
},
|
||||
{
|
||||
"name": "Debug demo - Windows",
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}\\out\\debug\\demo.exe",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}\\out\\debug",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"preLaunchTask": "Build project",
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"algorithm": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cctype": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"future": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"span": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"thread": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"variant": "cpp"
|
||||
}
|
||||
"git.ignoreLimitWarning": true,
|
||||
|
||||
// These settings should really be in github sync or something, if only it
|
||||
// worked in linux...
|
||||
"debug.openExplorerOnEnd": true,
|
||||
"debug.console.closeOnEnd": true,
|
||||
"editor.tabSize": 2,
|
||||
"editor.rulers": [
|
||||
80,
|
||||
],
|
||||
"workbench.editor.closeEmptyGroups": false,
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build project",
|
||||
"type": "shell",
|
||||
"linux": {
|
||||
"command": "~/code/work/chromium/src/third_party/ninja/ninja",
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
"osx": {
|
||||
"command": "ninja",
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
"windows": {
|
||||
"command": "ninja.exe",
|
||||
"problemMatcher": [
|
||||
"$msCompile"
|
||||
]
|
||||
},
|
||||
"args": [
|
||||
"-C",
|
||||
"${workspaceFolder}/out/debug"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"detail": "Build the project with ninja."
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
group("all") {
|
||||
deps = [
|
||||
"//src/demo",
|
||||
"//src/hello_world",
|
||||
]
|
||||
}
|
86
README.md
|
@ -1,20 +1,87 @@
|
|||
# Kaliber
|
||||
|
||||
A simple, cross-platform 2D game engine with OpenGL and Vulkan renderers.
|
||||
Supports Linux and Android platforms.
|
||||
Supports Linux, Windows and Android platforms.
|
||||
This is a personal hobby project. I've published a little game on
|
||||
[Google Play](https://play.google.com/store/apps/details?id=com.woom.game)
|
||||
based on this engine. Full game code and assets are included in this repository.
|
||||
#### Building the demo
|
||||
Linux:
|
||||
|
||||
## Pre-requisites:
|
||||
|
||||
GN build system is required for all platforms:\
|
||||
https://gn.googlesource.com/gn/
|
||||
|
||||
## Building from the command-line:
|
||||
|
||||
### All platforms except Android:
|
||||
#### Setup:
|
||||
Generate build files for Ninja in release and debug modes.
|
||||
```text
|
||||
cd build/linux
|
||||
make
|
||||
gn gen out/release
|
||||
gn gen --args='is_debug=true' out/debug
|
||||
```
|
||||
Android:
|
||||
#### Building and running:
|
||||
Build all games in release mode and run "hello_world".
|
||||
```text
|
||||
ninja -C out/release
|
||||
./out/release/hello_world
|
||||
```
|
||||
Build "demo" in debug mode and run.
|
||||
```text
|
||||
ninja -C out/debug demo
|
||||
./out/debug/demo
|
||||
```
|
||||
|
||||
### Android:
|
||||
Build "hello_world" in debug mode for all ABIs and install. GN will be run by
|
||||
Gradle so no setup is required. Location of gn and ninja executables can be
|
||||
specified via "gn" and "ninja" properties (-Pgn="path/gn").
|
||||
```text
|
||||
cd build/android
|
||||
./gradlew :app:assembleRelease
|
||||
./gradlew :app:installHelloWorldAllArchsDebug
|
||||
```
|
||||
#### Third-party libraries:
|
||||
Build "demo" in debug mode for x86_64 ABI and install. Valid ABI targets are
|
||||
Arm7, Arm8, X86, X86_64, AllArchs, ArmOnly, X86Only.
|
||||
```text
|
||||
./gradlew :app:installDemoX86_64Debug
|
||||
```
|
||||
|
||||
### Generate Visual Studio solution:
|
||||
```text
|
||||
gn.exe gen --args="is_debug=true" --ide=vs2022 out\vs
|
||||
devenv out\vs\all.sln
|
||||
```
|
||||
|
||||
## Hello World example:
|
||||
|
||||
Shows a smoothly rotating "Hello World".
|
||||
```cpp
|
||||
class HelloWorld final : public eng::Game {
|
||||
public:
|
||||
bool Initialize() final {
|
||||
eng::Engine::Get().SetImageSource(
|
||||
"hello_world_image",
|
||||
std::bind(&eng::Engine::Print, &eng::Engine::Get(), "Hello World",
|
||||
/*bg_color*/ base::Vector4f(1, 1, 1, 0)));
|
||||
|
||||
hello_world_.Create("hello_world_image").SetVisible(true);
|
||||
animator_.Attach(&hello_world_);
|
||||
animator_.SetRotation(base::PI2f, /*duration*/ 3,
|
||||
std::bind(base::SmootherStep, std::placeholders::_1));
|
||||
animator_.Play(eng::Animator::kRotation, /*loop*/ true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
eng::ImageQuad hello_world_;
|
||||
eng::Animator animator_;
|
||||
};
|
||||
|
||||
GAME_FACTORIES{GAME_CLASS(HelloWorld)};
|
||||
```
|
||||
|
||||
## Third-party libraries:
|
||||
|
||||
[glew](https://github.com/nigels-com/glew),
|
||||
[jsoncpp](https://github.com/open-source-parsers/jsoncpp),
|
||||
[minimp3](https://github.com/lieff/minimp3),
|
||||
|
@ -26,4 +93,5 @@ cd build/android
|
|||
[spirv-reflect](https://github.com/KhronosGroup/SPIRV-Reflect),
|
||||
[vma](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator),
|
||||
[vulkan-sdk](https://vulkan.lunarg.com),
|
||||
[volk](https://github.com/zeux/volk)
|
||||
[volk](https://github.com/zeux/volk),
|
||||
[imgui](https://github.com/ocornut/imgui)
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
copy("demo") {
|
||||
sources = [
|
||||
"bead.png",
|
||||
"boss_explosion.mp3",
|
||||
"boss_intro.mp3",
|
||||
"Boss_ok_lvl2.png",
|
||||
"Boss_ok_lvl3.png",
|
||||
"Boss_ok.png",
|
||||
"chromatic_aberration.glsl_fragment",
|
||||
"chromatic_aberration.glsl_vertex",
|
||||
"enemy_anims_01_frames_ok.png",
|
||||
"enemy_anims_02_frames_ok.png",
|
||||
"enemy_anims_blast_ok.png",
|
||||
"enemy_anims_flare_ok.png",
|
||||
"enemy_ray_ok.png",
|
||||
"enemy_target_single_ok.png",
|
||||
"explosion.mp3",
|
||||
"Game_2_Boss.mp3",
|
||||
"Game_2_Main.mp3",
|
||||
"hit.mp3",
|
||||
"laser.mp3",
|
||||
"menu_click.mp3",
|
||||
"menu_icons.png",
|
||||
"no_nuke.mp3",
|
||||
"nuke_frames.png",
|
||||
"nuke_pack_OK.png",
|
||||
"nuke.mp3",
|
||||
"PixelCaps!.ttf",
|
||||
"powerup-pick.mp3",
|
||||
"powerup-spawn.mp3",
|
||||
"renderer_logo.png",
|
||||
"shield.mp3",
|
||||
"sky_without_nebula.glsl_fragment",
|
||||
"sky_without_nebula.glsl_vertex",
|
||||
"sky.glsl_fragment",
|
||||
"sky.glsl_vertex",
|
||||
"stealth.mp3",
|
||||
"woom_enemy_shield.png",
|
||||
"woom_logo_start_frames_01.png",
|
||||
"woom_logo_start_frames_02-03.png",
|
||||
]
|
||||
|
||||
outputs = ["$root_out_dir/assets/demo/{{source_file_part}}"]
|
||||
}
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 507 B After Width: | Height: | Size: 507 B |
Before Width: | Height: | Size: 332 KiB After Width: | Height: | Size: 332 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 219 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 143 KiB |
Before Width: | Height: | Size: 255 KiB After Width: | Height: | Size: 255 KiB |
|
@ -0,0 +1,13 @@
|
|||
copy("engine") {
|
||||
sources = [
|
||||
"RobotoMono-Regular.ttf",
|
||||
"imgui.glsl_fragment",
|
||||
"imgui.glsl_vertex",
|
||||
"pass_through.glsl_fragment",
|
||||
"pass_through.glsl_vertex",
|
||||
"solid.glsl_fragment",
|
||||
"solid.glsl_vertex",
|
||||
]
|
||||
|
||||
outputs = [ "$root_out_dir/assets/engine/{{source_file_part}}" ]
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
IN(0) vec2 tex_coord_0;
|
||||
IN(1) vec4 color;
|
||||
|
||||
UNIFORM_BEGIN
|
||||
UNIFORM_V(mat4 projection)
|
||||
UNIFORM_END
|
||||
|
||||
SAMPLER(0, sampler2D texture_0)
|
||||
|
||||
FRAG_COLOR_OUT(frag_color)
|
||||
|
||||
void main() {
|
||||
FRAG_COLOR(frag_color) = TEXTURE(texture_0, tex_coord_0) * color;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
IN(0) vec2 in_position;
|
||||
IN(1) vec2 in_tex_coord_0;
|
||||
IN(2) vec4 in_color;
|
||||
|
||||
UNIFORM_BEGIN
|
||||
UNIFORM_V(mat4 projection)
|
||||
UNIFORM_END
|
||||
|
||||
OUT(0) vec2 tex_coord_0;
|
||||
OUT(1) vec4 color;
|
||||
|
||||
void main() {
|
||||
tex_coord_0 = in_tex_coord_0;
|
||||
color = in_color;
|
||||
|
||||
gl_Position = PARAM(projection) * vec4(in_position, 0.0, 1.0);
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
config("default") {
|
||||
if (is_android) {
|
||||
defines = [ "OS_ANDROID" ]
|
||||
} else if (is_ios) {
|
||||
defines = [ "OS_IOS" ]
|
||||
} else if (is_linux) {
|
||||
defines = [ "OS_LINUX" ]
|
||||
} else if (is_mac) {
|
||||
defines = [ "OS_MAC" ]
|
||||
} else if (is_win) {
|
||||
defines = [ "OS_WIN" ]
|
||||
}
|
||||
if (is_ios || is_mac) {
|
||||
defines += [ "OS_APPLE" ]
|
||||
}
|
||||
|
||||
cflags_cc = []
|
||||
if (is_win) {
|
||||
cflags_cc += [ "/std:c++20" ]
|
||||
} else {
|
||||
cflags_cc += [ "-std=c++20" ]
|
||||
}
|
||||
|
||||
cflags = []
|
||||
if (is_win) {
|
||||
cflags += [
|
||||
"/permissive-", # Don't enable nonconforming code to compile.
|
||||
"/EHsc", # Use C++ exception handling.
|
||||
"/Gd", # __cdecl calling convention.
|
||||
"/utf-8", # Set Source and Executable character set.
|
||||
]
|
||||
defines += [
|
||||
# Windows headers from MS and third party expects these to be set.
|
||||
"_WINDOWS",
|
||||
"_UNICODE",
|
||||
"UNICODE",
|
||||
|
||||
# Don't want MS specific extensions for C stdlib functions.
|
||||
"_CRT_SECURE_NO_WARNINGS",
|
||||
|
||||
# Clean up the Windows headers.
|
||||
"WIN32_LEAN_AND_MEAN",
|
||||
"NOMINMAX",
|
||||
]
|
||||
} else {
|
||||
# cflags += [
|
||||
# "-fstrict-aliasing", # Optimizations allowed for type aliasing.
|
||||
# "-fvisibility=hidden", # Only let symbols be visible inside it's own
|
||||
# # library.
|
||||
# ]
|
||||
# cflags_cc += [
|
||||
# "-fvisibility-inlines-hidden", # Inline methods may not generate symbols.
|
||||
# # "-stdlib=libc++",
|
||||
# ]
|
||||
|
||||
if (is_linux) {
|
||||
cflags += [
|
||||
"-fPIC", # Emit position-independent code suitable for dynamic linking.
|
||||
]
|
||||
libs = [
|
||||
"pthread", # Use the POSIX thread library.
|
||||
]
|
||||
} else if (is_mac) {
|
||||
asmflags = [
|
||||
"-target",
|
||||
"arm64-apple-macos11",
|
||||
]
|
||||
cflags += [
|
||||
# "-fPIC", # Emit position-independent code suitable for dynamic linking.
|
||||
"-target",
|
||||
"arm64-apple-macos11",
|
||||
]
|
||||
ldflags = [
|
||||
"-target",
|
||||
"arm64-apple-macos11",
|
||||
]
|
||||
} else if (is_android) {
|
||||
cflags += [
|
||||
"--sysroot=$ndk/toolchains/llvm/prebuilt/$ndk_host/sysroot",
|
||||
"-fPIC", # Emit position-independent code suitable for dynamic linking.
|
||||
]
|
||||
ldflags = [ "-static-libstdc++" ]
|
||||
}
|
||||
}
|
||||
|
||||
# Avoid relative paths everywhere.
|
||||
include_dirs = [
|
||||
"//src",
|
||||
]
|
||||
}
|
||||
|
||||
config("debug") {
|
||||
defines = [ "_DEBUG" ]
|
||||
|
||||
if (is_win) {
|
||||
cflags = [
|
||||
"/GS", # Buffer security checks (buffer overruns).
|
||||
"/sdl", # Enable additional security features and warnings.
|
||||
"/RTC1", # Enable fast run-time checks.
|
||||
"/Od", # Disable optimizations.
|
||||
"/fp:precise", # Floating points are predictable.
|
||||
"/MDd", # Link with multithread debug DLL run-time libraries.
|
||||
"/Z7", # Produce obj files that contain full symbolic debugging
|
||||
# information.
|
||||
]
|
||||
ldflags = [ "/DEBUG:FASTLINK" ] # Reference the debug symbols in the obj
|
||||
# files instead of a PDB file.
|
||||
} else {
|
||||
cflags = [
|
||||
"-g", # Debug symbols.
|
||||
# TODO: This makes it hard to step through code on Linux.
|
||||
# "-Og", # Optimizations that works well with debugger.
|
||||
]
|
||||
|
||||
if (is_unix) {
|
||||
defines += [
|
||||
"_GLIBCXX_DEBUG=1", # Enable asserts in stl headers.
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config("release") {
|
||||
defines = [ "NDEBUG" ]
|
||||
|
||||
if (is_win) {
|
||||
cflags = [
|
||||
"/GL", # Link-time code generation / Whole program optimization.
|
||||
"/Gy", # Allows converting inline functions to separate functions.
|
||||
"/O2", # Optimize for maximum speed.
|
||||
"/Oi", # Enable intrinsics.
|
||||
"/fp:fast", # Floating points are fast.
|
||||
"/MD", # Link with multithread release DLL run-time libraries.
|
||||
|
||||
# "/arch:AVX2", # Minimum CPU architecture.
|
||||
]
|
||||
ldflags = [
|
||||
"/LTCG", # Link time code generation.
|
||||
"/OPT:ICF", # COMDAT (common data) folding, e.g. vtables and big inline
|
||||
# functions that can't be inlined, but also if identical code
|
||||
# happens to be generated though common math operations or
|
||||
# similar.
|
||||
"/OPT:REF", # Eliminate unreferenced code and data.
|
||||
]
|
||||
} else {
|
||||
cflags = [
|
||||
"-Ofast", # Full optimization and disregard strict standard compliance.
|
||||
"-fno-math-errno", # Do not check or set errno for invalid input to sqrt
|
||||
# and other math functions.
|
||||
]
|
||||
|
||||
if (is_apple) {
|
||||
ldflags = [ "-dead-strip" ]
|
||||
} else {
|
||||
# Place both data and functions in it's their own sections.
|
||||
# Linker optimization that allows for smaller binaries.
|
||||
cflags += [
|
||||
"-fdata-sections",
|
||||
"-ffunction-sections",
|
||||
]
|
||||
ldflags = [ "-Wl,--gc-sections" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config("warnings") {
|
||||
if (is_win) {
|
||||
cflags = [
|
||||
"/WX", # Treat warnings as errors.
|
||||
"/Wall", # Enable all warnings.
|
||||
|
||||
# Disable the following warnings:
|
||||
"/wd4061", # enumerator in switch with a default case not explicitly
|
||||
# handled by a case label.
|
||||
"/wd4100", # nonstandard extension used: nameless struct/union.
|
||||
"/wd4201", # enumerator in switch with a default case not explicitly
|
||||
# handled by a case label.
|
||||
"/wd4324", # structure was padded due to alignment specifier
|
||||
"/wd4371", # layout of class may have changed from a previous version of
|
||||
# the compiler due to better packing of member
|
||||
"/wd4514", # unreferenced inline function has been removed.
|
||||
"/wd4710", # function not inlined
|
||||
"/wd4711", # function selected for automatic inline expansion
|
||||
"/wd4820", # padding added after data member.
|
||||
"/wd5045", # compiler will insert Spectre mitigation for memory load if
|
||||
# switch specified.
|
||||
"/wd4355", # 'this': used in base member initializer list
|
||||
|
||||
# TODO: Not sure how I feel about these conversion warnings.
|
||||
"/Wv:18",
|
||||
"/wd4191", # 'type cast': unsafe conversion
|
||||
"/wd4244", # conversion, possible loss of data. 'int' to 'float'
|
||||
"/wd4245", # conversion from 'int' to 'const unsigned int'
|
||||
"/wd4305", # truncation from 'double' to 'float'.
|
||||
"/wd4365", # conversion, signed/unsigned mismatch.
|
||||
"/wd4722", # destructor never returns, potential memory leak
|
||||
"/wd4702", # unreachable code
|
||||
"/wd4625", # copy constructor was implicitly defined as deleted
|
||||
"/wd4626", # assignment operator was implicitly defined as deleted
|
||||
|
||||
# Possible compiler bug? Needs investigation.
|
||||
"/wd4668", # '__STDC_WANT_SECURE_LIB__' is not defined as a preprocessor
|
||||
# macro, replacing with '0' for '#if/#elif'
|
||||
]
|
||||
|
||||
defines = [
|
||||
"_CRT_NONSTDC_NO_DEPRECATE",
|
||||
"_SILENCE_CXX17_STRSTREAM_DEPRECATION_WARNING",
|
||||
"_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS",
|
||||
]
|
||||
} else if (is_mac) {
|
||||
cflags = [
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Wno-inconsistent-missing-override",
|
||||
"-Wno-pointer-sign",
|
||||
]
|
||||
} else {
|
||||
cflags = [
|
||||
# Enable as much warnings as possible.
|
||||
"-Werror", # Make all warnings into errors.
|
||||
"-Wall", # Enable (almost) all warnings.
|
||||
"-Wextra", # Enable even more warnings.
|
||||
|
||||
# forbidden extensions.
|
||||
"-Wvla", # Warn if variable-length array is used in code.
|
||||
|
||||
# Disable the following warnings:
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-sign-compare",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
config("executable") {
|
||||
if (is_android) {
|
||||
ldflags = [
|
||||
"-pie",
|
||||
"-rdynamic",
|
||||
]
|
||||
} else if (is_linux) {
|
||||
ldflags = [
|
||||
"-Wl,-rpath,\$ORIGIN", # Add directory to runtime library search path.
|
||||
]
|
||||
} else if (is_mac) {
|
||||
ldflags = [ "-Wl,-rpath,@loader_path/." ]
|
||||
}
|
||||
}
|
||||
|
||||
config("shared_library") {
|
||||
if (is_android) {
|
||||
ldflags = [
|
||||
"-Wl,--build-id=sha1",
|
||||
"-Wl,--no-rosegment",
|
||||
"-Wl,--fatal-warnings",
|
||||
"-Wl,--no-undefined",
|
||||
"-Qunused-arguments",
|
||||
"-u ANativeActivity_onCreate",
|
||||
]
|
||||
} else if (is_linux) {
|
||||
ldflags = [
|
||||
"-Wl,-rpath,\$ORIGIN", # Add directory to runtime library search path.
|
||||
]
|
||||
} else if (is_mac) {
|
||||
ldflags = [ "-Wl,-rpath,@loader_path/." ]
|
||||
}
|
||||
}
|
||||
|
||||
# TODO: This needs some more investigation.
|
||||
# Is it possible to avoid setting it and rely on defaults?
|
||||
# Some tools will be console apps while games will be gui apps.
|
||||
# GLFW seems to be using console in debug mode and gui in release mode.
|
||||
if (is_win) {
|
||||
config("win_gui") {
|
||||
ldflags = [ "/SUBSYSTEM:WINDOWS" ]
|
||||
}
|
||||
|
||||
config("win_console") {
|
||||
ldflags = [ "/SUBSYSTEM:CONSOLE" ]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
declare_args() {
|
||||
is_debug = false
|
||||
|
||||
# Note that this uses the 'cc' and 'c++' links that should map to GCC on linux
|
||||
# systems and clang on macs.
|
||||
ar = "ar"
|
||||
cc = "cc"
|
||||
cxx = "c++"
|
||||
|
||||
ndk = ""
|
||||
ndk_api = 24
|
||||
}
|
||||
|
||||
# Platform detection
|
||||
if (target_os == "") {
|
||||
target_os = host_os
|
||||
}
|
||||
if (current_os == "") {
|
||||
current_os = target_os
|
||||
}
|
||||
|
||||
is_android = current_os == "android"
|
||||
is_ios = current_os == "ios"
|
||||
is_linux = current_os == "linux"
|
||||
is_mac = current_os == "mac"
|
||||
is_win = current_os == "win"
|
||||
|
||||
is_apple = is_mac || is_ios
|
||||
is_desktop = is_mac || is_linux || is_win
|
||||
is_mobile = is_android || is_ios
|
||||
is_unix = is_android || is_linux
|
||||
|
||||
if (target_cpu == "") {
|
||||
if (is_mobile) {
|
||||
target_cpu = "arm64"
|
||||
} else {
|
||||
target_cpu = host_cpu
|
||||
}
|
||||
}
|
||||
if (target_cpu == "x86_64") {
|
||||
target_cpu = "x64"
|
||||
}
|
||||
if (current_cpu == "") {
|
||||
current_cpu = target_cpu
|
||||
}
|
||||
|
||||
if (is_android) {
|
||||
assert(ndk != "", "NDK path argument is empty")
|
||||
|
||||
ndk_host = ""
|
||||
ndk_target = ""
|
||||
|
||||
if (host_os == "linux") {
|
||||
ndk_host = "linux-x86_64"
|
||||
} else if (host_os == "mac") {
|
||||
ndk_host = "darwin-x86_64"
|
||||
} else if (host_os == "win") {
|
||||
ndk_host = "windows-x86_64"
|
||||
}
|
||||
|
||||
if (target_cpu == "arm64") {
|
||||
ndk_target = "aarch64-linux-android"
|
||||
} else if (target_cpu == "arm") {
|
||||
ndk_target = "armv7a-linux-androideabi"
|
||||
} else if (target_cpu == "x64") {
|
||||
ndk_target = "x86_64-linux-android"
|
||||
} else if (target_cpu == "x86") {
|
||||
ndk_target = "i686-linux-android"
|
||||
}
|
||||
|
||||
_prefix = "$ndk/toolchains/llvm/prebuilt/$ndk_host/bin"
|
||||
if (host_os == "win") {
|
||||
ar = "$_prefix/llvm-ar.exe"
|
||||
cc = "$_prefix/clang.exe --target=$ndk_target$ndk_api -fno-addrsig"
|
||||
cxx = "$_prefix/clang++.exe --target=$ndk_target$ndk_api -fno-addrsig"
|
||||
} else {
|
||||
ar = "$_prefix/llvm-ar"
|
||||
cc = "$_prefix/$ndk_target$ndk_api-clang"
|
||||
cxx = "$_prefix/$ndk_target$ndk_api-clang++"
|
||||
}
|
||||
}
|
||||
|
||||
# Set defaults
|
||||
_default_config = [
|
||||
"//build:default",
|
||||
"//build:warnings",
|
||||
]
|
||||
|
||||
if (is_debug) {
|
||||
_default_config += [ "//build:debug" ]
|
||||
} else {
|
||||
_default_config += [ "//build:release" ]
|
||||
}
|
||||
|
||||
set_defaults("executable") {
|
||||
configs = [ "//build:executable" ] + _default_config
|
||||
}
|
||||
set_defaults("static_library") {
|
||||
configs = _default_config
|
||||
}
|
||||
set_defaults("shared_library") {
|
||||
configs = [ "//build:shared_library" ] + _default_config
|
||||
}
|
||||
set_defaults("source_set") {
|
||||
configs = _default_config
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
set_default_toolchain("//build/toolchain/msvc")
|
||||
} else {
|
||||
# Clang behaves like GCC in most cases.
|
||||
set_default_toolchain("//build/toolchain/gcc")
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.22.1)
|
||||
|
||||
# common_config
|
||||
add_library(common_config INTERFACE)
|
||||
|
||||
target_compile_options(common_config INTERFACE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-std=c++20>
|
||||
#$<$<NOT:$<CONFIG:DEBUG>>:-Ofast>
|
||||
-Wall
|
||||
-Werror
|
||||
-Wno-unused-but-set-variable
|
||||
-Wno-deprecated-enum-enum-conversion
|
||||
-Wno-unsequenced
|
||||
-Wno-nullability-completeness
|
||||
)
|
||||
|
||||
target_compile_definitions(common_config INTERFACE
|
||||
VK_USE_PLATFORM_ANDROID_KHR
|
||||
VMA_STATIC_VULKAN_FUNCTIONS=1
|
||||
$<$<CONFIG:DEBUG>:_DEBUG>
|
||||
)
|
||||
|
||||
target_include_directories(common_config INTERFACE
|
||||
../../../src
|
||||
../../../src/third_party/glslang
|
||||
../../../src/third_party/vulkan/include
|
||||
)
|
||||
|
||||
# oboe
|
||||
set (OBOE_DIR ../../../src/third_party/oboe)
|
||||
add_subdirectory(${OBOE_DIR} ./oboe-bin)
|
||||
|
||||
# cpufeatures
|
||||
add_library(cpufeatures STATIC ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
|
||||
target_include_directories(cpufeatures PUBLIC ${ANDROID_NDK}/sources/android/cpufeatures)
|
||||
|
||||
# native_app_glue
|
||||
add_library(native_app_glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
|
||||
target_include_directories(native_app_glue PUBLIC ${ANDROID_NDK}/sources/android/native_app_glue)
|
||||
set_property(TARGET native_app_glue PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# Export ANativeActivity_onCreate(),
|
||||
# Refer to: https://github.com/android-ndk/ndk/issues/381.
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
|
||||
|
||||
# kaliber
|
||||
project(kaliber)
|
||||
|
||||
add_library(kaliber SHARED
|
||||
../../../src/base/collusion_test.cc
|
||||
../../../src/base/log.cc
|
||||
../../../src/base/sinc_resampler.cc
|
||||
../../../src/base/task_runner.cc
|
||||
../../../src/base/thread_pool.cc
|
||||
../../../src/base/timer.cc
|
||||
../../../src/demo/credits.cc
|
||||
../../../src/demo/demo.cc
|
||||
../../../src/demo/enemy.cc
|
||||
../../../src/demo/hud.cc
|
||||
../../../src/demo/menu.cc
|
||||
../../../src/demo/player.cc
|
||||
../../../src/demo/sky_quad.cc
|
||||
../../../src/engine/animatable.cc
|
||||
../../../src/engine/animator.cc
|
||||
../../../src/engine/audio/audio_mixer.cc
|
||||
../../../src/engine/audio/audio_sink_oboe.cc
|
||||
../../../src/engine/drawable.cc
|
||||
../../../src/engine/engine.cc
|
||||
../../../src/engine/font.cc
|
||||
../../../src/engine/image_quad.cc
|
||||
../../../src/engine/image.cc
|
||||
../../../src/engine/mesh.cc
|
||||
../../../src/engine/persistent_data.cc
|
||||
../../../src/engine/platform/asset_file_android.cc
|
||||
../../../src/engine/platform/asset_file.cc
|
||||
../../../src/engine/platform/platform_android.cc
|
||||
../../../src/engine/renderer/geometry.cc
|
||||
../../../src/engine/renderer/opengl/render_command.cc
|
||||
../../../src/engine/renderer/opengl/renderer_opengl_android.cc
|
||||
../../../src/engine/renderer/opengl/renderer_opengl.cc
|
||||
../../../src/engine/renderer/renderer_types.cc
|
||||
../../../src/engine/renderer/shader.cc
|
||||
../../../src/engine/renderer/texture.cc
|
||||
../../../src/engine/renderer/vulkan/renderer_vulkan_android.cc
|
||||
../../../src/engine/renderer/vulkan/renderer_vulkan.cc
|
||||
../../../src/engine/renderer/vulkan/vulkan_context_android.cc
|
||||
../../../src/engine/renderer/vulkan/vulkan_context.cc
|
||||
../../../src/engine/shader_source.cc
|
||||
../../../src/engine/solid_quad.cc
|
||||
../../../src/engine/sound_player.cc
|
||||
../../../src/engine/sound.cc
|
||||
../../../src/third_party/android/gl3stub.c
|
||||
../../../src/third_party/android/GLContext.cpp
|
||||
../../../src/third_party/glslang/glslang/GenericCodeGen/CodeGen.cpp
|
||||
../../../src/third_party/glslang/glslang/GenericCodeGen/Link.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/attribute.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/Constant.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/glslang_tab.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/InfoSink.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/Initialize.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/Intermediate.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/intermOut.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/IntermTraverse.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/iomapper.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/limits.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/linkValidate.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/parseConst.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/ParseContextBase.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/ParseHelper.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/PoolAlloc.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/propagateNoContraction.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/reflection.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/RemoveTree.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/Scan.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/ShaderLang.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/SymbolTable.cpp
|
||||
../../../src/third_party/glslang/glslang/MachineIndependent/Versions.cpp
|
||||
../../../src/third_party/glslang/glslang/OSDependent/Unix/ossource.cpp
|
||||
../../../src/third_party/glslang/OGLCompilersDLL/InitializeDll.cpp
|
||||
../../../src/third_party/glslang/SPIRV/disassemble.cpp
|
||||
../../../src/third_party/glslang/SPIRV/doc.cpp
|
||||
../../../src/third_party/glslang/SPIRV/GlslangToSpv.cpp
|
||||
../../../src/third_party/glslang/SPIRV/InReadableOrder.cpp
|
||||
../../../src/third_party/glslang/SPIRV/Logger.cpp
|
||||
../../../src/third_party/glslang/SPIRV/SpvBuilder.cpp
|
||||
../../../src/third_party/glslang/SPIRV/SpvPostProcess.cpp
|
||||
../../../src/third_party/glslang/SPIRV/SPVRemapper.cpp
|
||||
../../../src/third_party/glslang/SPIRV/SpvTools.cpp
|
||||
../../../src/third_party/jsoncpp/jsoncpp.cpp
|
||||
../../../src/third_party/minizip/ioapi.c
|
||||
../../../src/third_party/minizip/unzip.c
|
||||
../../../src/third_party/spirv-reflect/spirv_reflect.c
|
||||
../../../src/third_party/stb/stb_image.c
|
||||
../../../src/third_party/texture_compressor/dxt_encoder_internals.cc
|
||||
../../../src/third_party/texture_compressor/dxt_encoder.cc
|
||||
../../../src/third_party/texture_compressor/texture_compressor_etc1.cc
|
||||
../../../src/third_party/texture_compressor/texture_compressor.cc
|
||||
../../../src/third_party/vma/vk_mem_alloc.cpp
|
||||
../../../src/third_party/volk/volk.c
|
||||
)
|
||||
|
||||
if (ANDROID_ABI STREQUAL armeabi-v7a)
|
||||
target_sources(kaliber PRIVATE ../../../src/third_party/texture_compressor/dxt_encoder_neon.cc)
|
||||
target_sources(kaliber PRIVATE ../../../src/third_party/texture_compressor/texture_compressor_etc1_neon.cc)
|
||||
set_source_files_properties(../../../src/third_party/texture_compressor/dxt_encoder_neon.cc PROPERTIES COMPILE_FLAGS -mfpu=neon)
|
||||
set_source_files_properties(../../../src/third_party/texture_compressor/texture_compressor_etc1_neon.cc PROPERTIES COMPILE_FLAGS -mfpu=neon)
|
||||
endif()
|
||||
|
||||
if (ANDROID_ABI STREQUAL arm64-v8a)
|
||||
target_sources(kaliber PRIVATE ../../../src/third_party/texture_compressor/dxt_encoder_neon.cc)
|
||||
target_sources(kaliber PRIVATE ../../../src/third_party/texture_compressor/texture_compressor_etc1_neon.cc)
|
||||
endif()
|
||||
|
||||
target_link_libraries(kaliber PRIVATE
|
||||
common_config
|
||||
android
|
||||
native_app_glue
|
||||
oboe
|
||||
cpufeatures
|
||||
EGL
|
||||
GLESv2
|
||||
log
|
||||
z
|
||||
)
|
|
@ -1,45 +1,131 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: Utils
|
||||
|
||||
android {
|
||||
compileSdk 33
|
||||
ndkVersion '25.2.9519653'
|
||||
compileSdk rootProject.ext.compileSdk
|
||||
ndkVersion rootProject.ext.ndkVersion
|
||||
|
||||
defaultConfig {
|
||||
applicationId = 'com.woom.game'
|
||||
minSdk 24
|
||||
targetSdk 33
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments '-DANDROID_STL=c++_static'
|
||||
}
|
||||
}
|
||||
minSdk rootProject.ext.minSdk
|
||||
targetSdk rootProject.ext.targetSdk
|
||||
ndk {
|
||||
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
|
||||
abiFilters = []
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
||||
'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions 'game', 'arch'
|
||||
|
||||
productFlavors {
|
||||
helloWorld {
|
||||
dimension 'game'
|
||||
applicationId 'com.kaliber.helloworld'
|
||||
resValue "string", "app_name", "Kaliber Hello World"
|
||||
manifestPlaceholders = [appIcon: "@mipmap/ic_launcher"]
|
||||
ext {
|
||||
gnTarget = "hello_world"
|
||||
}
|
||||
}
|
||||
demo {
|
||||
dimension 'game'
|
||||
applicationId 'com.kaliber.woom'
|
||||
resValue "string", "app_name", "Kaliber Demo"
|
||||
manifestPlaceholders = [appIcon: "@mipmap/ic_launcher"]
|
||||
ext {
|
||||
gnTarget = "demo"
|
||||
}
|
||||
}
|
||||
woom {
|
||||
dimension 'game'
|
||||
applicationId 'com.woom.game'
|
||||
resValue "string", "app_name", "woom"
|
||||
resValue "string", "interstitial_ad_unit_id", "ca-app-pub-1321063817979967/8373182022"
|
||||
resValue "string", "admob_application_id", "ca-app-pub-1321063817979967~1100949243"
|
||||
manifestPlaceholders = [appIcon: "@mipmap/ic_launcher"]
|
||||
ext {
|
||||
gnTarget = "demo"
|
||||
}
|
||||
}
|
||||
|
||||
arm7 {
|
||||
dimension 'arch'
|
||||
ndk {
|
||||
debugSymbolLevel 'FULL'
|
||||
abiFilters = ["armeabi-v7a"]
|
||||
}
|
||||
}
|
||||
arm8 {
|
||||
dimension 'arch'
|
||||
ndk {
|
||||
abiFilters = ["arm64-v8a"]
|
||||
}
|
||||
}
|
||||
x86 {
|
||||
dimension 'arch'
|
||||
ndk {
|
||||
abiFilters = ["x86"]
|
||||
}
|
||||
}
|
||||
x86_64 {
|
||||
dimension 'arch'
|
||||
ndk {
|
||||
abiFilters = ["x86_64"]
|
||||
}
|
||||
}
|
||||
|
||||
allArchs {
|
||||
dimension 'arch'
|
||||
ndk {
|
||||
abiFilters = ["armeabi-v7a", "arm64-v8a", "x86_64", "x86"]
|
||||
}
|
||||
}
|
||||
armOnly {
|
||||
dimension 'arch'
|
||||
ndk {
|
||||
abiFilters = ["armeabi-v7a", "arm64-v8a"]
|
||||
}
|
||||
}
|
||||
x86Only {
|
||||
dimension 'arch'
|
||||
ndk {
|
||||
abiFilters = ["x86_64", "x86"]
|
||||
}
|
||||
}
|
||||
|
||||
// Native library name is same as GN target name.
|
||||
android.productFlavors.each { flavor ->
|
||||
if (flavor.dimension == 'game') {
|
||||
"${flavor.name}" {
|
||||
resValue "string", "lib_name", flavor.ext.gnTarget
|
||||
buildConfigField 'String', 'NATIVE_LIBRARY', "\"${flavor.ext.gnTarget}\""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version '3.22.1'
|
||||
path 'CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDirs += ['../../../src/engine/platform/java/com/kaliber/base']
|
||||
assets.srcDirs = ['../../../assets']
|
||||
android.buildTypes.each { buildType ->
|
||||
"${buildType.name}" {
|
||||
assets.srcDirs = ["${utils.getGnOutDir(buildType.name)}/assets"]
|
||||
}
|
||||
}
|
||||
}
|
||||
android.buildTypes.each { buildType ->
|
||||
"${buildType.name}" {
|
||||
jniLibs.srcDirs = ["${utils.getGnOutDir(buildType.name)}/jniLibs"]
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace 'com.woom.game'
|
||||
|
||||
namespace "com.kaliber.base"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -48,3 +134,247 @@ dependencies {
|
|||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'com.google.android.gms:play-services-ads:22.0.0'
|
||||
}
|
||||
|
||||
//
|
||||
// Tasks for GN build
|
||||
//
|
||||
|
||||
// Generate `args.gn` which is used by GN to take in build arguments.
|
||||
utils.addTask('generateGnArgsFor') { String taskName, String buildType, String arch ->
|
||||
task(taskName, type: WriteFileTask) {
|
||||
content = utils.generateGnArgsContent(buildType, arch)
|
||||
target = project.layout.file(provider { new File("${utils.getGnOutDir(buildType)}/${arch}", 'args.gn') })
|
||||
}
|
||||
}
|
||||
|
||||
// Run `gn gen` to generate ninja files.
|
||||
utils.addTask('runGnFor') { String taskName, String buildType, String arch ->
|
||||
task(taskName, type: Exec) {
|
||||
dependsOn "generateGnArgsFor${arch}${buildType}"
|
||||
|
||||
executable rootProject.ext.gn
|
||||
args '--fail-on-unused-args', 'gen', "${utils.getGnOutDir(buildType)}/${arch}"
|
||||
|
||||
// Need to run gn only once unless the configuration in `args.gn` changes.
|
||||
inputs.file(new File("${utils.getGnOutDir(buildType)}/${arch}", 'args.gn'))
|
||||
outputs.file(new File("${utils.getGnOutDir(buildType)}/${arch}", 'build.ninja'))
|
||||
}
|
||||
}
|
||||
|
||||
// Build the native library for the target game using ninja.
|
||||
utils.addGameTask('runNinjaFor') { String taskName, String buildType, String arch, String game ->
|
||||
task(taskName, type: Exec) {
|
||||
dependsOn "runGnFor${arch}${buildType}"
|
||||
|
||||
executable rootProject.ext.ninja
|
||||
args '-C', "${utils.getGnOutDir(buildType)}/${arch}", "src/${utils.getGnTargetFor(game)}"
|
||||
|
||||
// Always run ninja and let it figure out what needs to be compiled.
|
||||
outputs.upToDateWhen { false }
|
||||
}
|
||||
}
|
||||
|
||||
// Assets can be obtained from the output directory of any arch but it would be good to combine them
|
||||
// in a single directory in case we are buildig multi-arch and some build config have different assets.
|
||||
utils.addGameTask('copyAssetsFor') { String taskName, String buildType, String arch, String game ->
|
||||
task(taskName, type: Copy) {
|
||||
dependsOn "runNinjaFor${game}${arch}${buildType}"
|
||||
|
||||
from "${utils.getGnOutDir(buildType)}/${arch}/assets"
|
||||
into "${utils.getGnOutDir(buildType)}/assets"
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the native library to a directory denoting its arch code as the Android Gradle plugin expects.
|
||||
utils.addGameTask('copyJniLibsFor') { String taskName, String buildType, String arch, String game ->
|
||||
task(taskName, type: Copy) {
|
||||
dependsOn "runNinjaFor${game}${arch}${buildType}"
|
||||
|
||||
from("${utils.getGnOutDir(buildType)}/${arch}") {
|
||||
include "lib${utils.getGnTargetFor(game)}.so"
|
||||
}
|
||||
into "${utils.getGnOutDir(buildType)}/jniLibs/${utils.getAbiCodeFor(arch)}"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.configureEach { task ->
|
||||
def variantPattern = /(\w+)(${utils.getArchTypesRegExp()})(${utils.getBuildTypesRegExp()})/
|
||||
|
||||
def match = task.name =~ /^merge/ + variantPattern + /JniLibFolders$/
|
||||
if (match) {
|
||||
utils.project.android.productFlavors.find { arch ->
|
||||
if (arch.dimension == 'arch' && arch.name.capitalize() == match.group(2)) {
|
||||
// Depends on each arch type for multi-arch build flavors.
|
||||
arch.ndk.abiFilters.each { abi ->
|
||||
task.dependsOn "copyJniLibsFor${match.group(1)}${utils.ARCH_CODES[abi]}${match.group(3)}"
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
match = task.name =~ /^generate/ + variantPattern + /Assets$/
|
||||
if (match) {
|
||||
utils.project.android.productFlavors.find { arch ->
|
||||
if (arch.dimension == 'arch' && arch.name.capitalize() == match.group(2)) {
|
||||
// Depends on each arch type for multi-arch build flavors.
|
||||
arch.ndk.abiFilters.each { abi ->
|
||||
task.dependsOn "copyAssetsFor${match.group(1)}${utils.ARCH_CODES[abi]}${match.group(3)}"
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
match = task.name =~ /^lintVitalAnalyze/ + variantPattern + /$/
|
||||
if (match) {
|
||||
utils.project.android.productFlavors.find { arch ->
|
||||
if (arch.dimension == 'arch' && arch.name.capitalize() == match.group(2)) {
|
||||
// Depends on each arch type for multi-arch build flavors.
|
||||
arch.ndk.abiFilters.each { abi ->
|
||||
task.dependsOn "copyAssetsFor${match.group(1)}${utils.ARCH_CODES[abi]}${match.group(3)}"
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Utils plugin
|
||||
//
|
||||
|
||||
class Utils implements Plugin<Project> {
|
||||
final def ARCH_CODES = ["armeabi-v7a": "Arm7",
|
||||
"arm64-v8a": "Arm8",
|
||||
"x86_64": "X86_64",
|
||||
"x86": "X86"].asImmutable()
|
||||
final def GN_CPU_CODES = ["Arm7": "arm",
|
||||
"Arm8": "arm64",
|
||||
"X86_64": "x64",
|
||||
"X86": "x86"].asImmutable()
|
||||
|
||||
def project
|
||||
|
||||
@Inject
|
||||
Utils(Project project) {
|
||||
this.project = project
|
||||
}
|
||||
|
||||
void apply(Project project) {
|
||||
project.extensions.create('utils', Utils)
|
||||
}
|
||||
|
||||
// Add a task for archs and buildTypes variants.
|
||||
void addTask(String prefix, Closure taskClosure) {
|
||||
forEachBuildVariant { String arch, String buildType ->
|
||||
def taskName = "${prefix}${arch}${buildType}"
|
||||
taskClosure(taskName, buildType, arch)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a task for games, archs and buildTypes variants.
|
||||
void addGameTask(String prefix, Closure taskClosure) {
|
||||
forEachGameBuildVariant { String game, String arch, String buildType ->
|
||||
def taskName = "${prefix}${game}${arch}${buildType}"
|
||||
taskClosure(taskName, buildType, arch, game)
|
||||
}
|
||||
}
|
||||
|
||||
void forEachBuildVariant(Closure callback) {
|
||||
project.android.productFlavors.each { arch ->
|
||||
// Only need to add tasks for arch types which maps to a single ABI
|
||||
if (arch.dimension == 'arch' && arch.ndk.abiFilters.size() == 1) {
|
||||
project.android.buildTypes.each { buildType ->
|
||||
callback(arch.name.capitalize(), buildType.name.capitalize())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void forEachGameBuildVariant(Closure callback) {
|
||||
project.android.productFlavors.each { game ->
|
||||
if (game.dimension == 'game') {
|
||||
project.android.productFlavors.each { arch ->
|
||||
// Only need to add tasks for arch types which maps to a single ABI
|
||||
if (arch.dimension == 'arch' && arch.ndk.abiFilters.size() == 1) {
|
||||
project.android.buildTypes.each { buildType ->
|
||||
callback(game.name.capitalize(), arch.name.capitalize(), buildType.name.capitalize())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def getBuildTypesRegExp() {
|
||||
def outList = []
|
||||
project.android.buildTypes.each { buildType ->
|
||||
outList += buildType.name.capitalize()
|
||||
}
|
||||
return outList.join('|')
|
||||
}
|
||||
|
||||
def getArchTypesRegExp() {
|
||||
def outList = []
|
||||
project.android.productFlavors.each { flavor ->
|
||||
if (flavor.dimension == 'arch') {
|
||||
outList += flavor.name.capitalize()
|
||||
}
|
||||
}
|
||||
return outList.join('|')
|
||||
}
|
||||
|
||||
def getAbiCodeFor(String arch) {
|
||||
def outStr = ''
|
||||
project.android.productFlavors.find { flavor ->
|
||||
if (flavor.name.capitalize() == arch) {
|
||||
outStr = flavor.ndk.abiFilters.first()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return outStr
|
||||
}
|
||||
|
||||
def getGnTargetFor(String game) {
|
||||
def outStr = ''
|
||||
project.android.productFlavors.find { flavor ->
|
||||
if (flavor.dimension == 'game' && flavor.name.capitalize() == game) {
|
||||
outStr = flavor.ext.gnTarget
|
||||
return true
|
||||
}
|
||||
}
|
||||
return outStr
|
||||
}
|
||||
|
||||
def generateGnArgsContent(String buildType, String arch) {
|
||||
def content = 'target_os="android"\n'
|
||||
content += 'target_cpu="' + GN_CPU_CODES[arch] + '"\n'
|
||||
content += "is_debug=${buildType != 'Release'}\n"
|
||||
content += 'ndk="' + project.android.ndkDirectory + '"\n'
|
||||
content += "ndk_api=${project.rootProject.ext.minSdk}\n"
|
||||
return content
|
||||
}
|
||||
|
||||
def getGnOutDir(String buildType) {
|
||||
return "${project.buildDir}/gn_out/${buildType.toLowerCase()}"
|
||||
}
|
||||
}
|
||||
|
||||
abstract class WriteFileTask extends DefaultTask {
|
||||
@Input
|
||||
abstract Property<String> getContent()
|
||||
|
||||
@OutputFile
|
||||
abstract RegularFileProperty getTarget()
|
||||
|
||||
@TaskAction
|
||||
void run() {
|
||||
def file = target.get().asFile
|
||||
file.parentFile.mkdirs()
|
||||
def text = content.get()
|
||||
if (!file.exists() || text != file.text)
|
||||
file.text = text
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="18"
|
||||
android:versionName="1.0.2">
|
||||
android:versionCode="22"
|
||||
android:versionName="1.0.4">
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:fullBackupContent="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:icon="${appIcon}"
|
||||
android:label="@string/app_name">
|
||||
|
||||
<activity
|
||||
|
@ -27,16 +27,16 @@
|
|||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.app.lib_name"
|
||||
android:value="kaliber" />
|
||||
android:value="@string/lib_name" />
|
||||
</activity>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.ads.APPLICATION_ID"
|
||||
android:value="ca-app-pub-1321063817979967~1100949243" />
|
||||
android:value="@string/admob_application_id" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="com.woom.game.fileprovider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">woom</string>
|
||||
<string name="interstitial_ad_unit_id">ca-app-pub-1321063817979967/8373182022</string>
|
||||
<string name="app_name">Kaliber app</string>
|
||||
<string name="interstitial_ad_unit_id"></string>
|
||||
<string name="admob_application_id">ca-app-pub-3940256099942544~3347511713</string>
|
||||
</resources>
|
||||
|
|
|
@ -5,7 +5,7 @@ buildscript {
|
|||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.0.1'
|
||||
classpath 'com.android.tools.build:gradle:8.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,3 +19,17 @@ allprojects {
|
|||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
ext {
|
||||
ndkVersion = '25.2.9519653'
|
||||
minSdk = 24
|
||||
compileSdk = 33
|
||||
targetSdk = 33
|
||||
|
||||
if (!project.hasProperty('gn')) {
|
||||
gn = "gn"
|
||||
}
|
||||
if (!project.hasProperty('ninja')) {
|
||||
ninja = "ninja"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
BUILD="$1"
|
||||
if [[ -z "$1" ]]; then
|
||||
BUILD="debug"
|
||||
fi
|
||||
adb logcat | ndk-stack -sym ./app/build/intermediates/merged_native_libs/"$BUILD"/out/lib/arm64-v8a
|
|
@ -1,282 +0,0 @@
|
|||
.DEFAULT_GOAL := all
|
||||
|
||||
# --- Input variables ---
|
||||
|
||||
BUILD ?= release
|
||||
ifeq ($(findstring $(BUILD),debug release),)
|
||||
$(error BUILD must be set to debug or release)
|
||||
endif
|
||||
|
||||
# Build all executables by default.
|
||||
APPS ?= demo
|
||||
|
||||
# If the VERBOSE flag isn't set, then mute superfluous output.
|
||||
ifeq ($(VERBOSE),)
|
||||
HUSH_COMPILE = @echo "Compiling $<";
|
||||
HUSH_LINK = @echo "Linking $@";
|
||||
HUSH_GENERATE = @echo "Generating $@";
|
||||
HUSH_CLEAN = @
|
||||
endif
|
||||
|
||||
# --- Internal variables ---
|
||||
|
||||
ARCH := $(shell uname -p)
|
||||
SRC_ROOT := $(abspath ../../src)
|
||||
OUTPUT_DIR := $(abspath .)
|
||||
INTERMEDIATE_DIR := $(OUTPUT_DIR)/obj
|
||||
BUILD_DIR := $(INTERMEDIATE_DIR)/$(BUILD)
|
||||
|
||||
ARFLAGS = r
|
||||
LDFLAGS = -lX11 -lGL -pthread -lasound -ldl
|
||||
|
||||
# Always enable debug information.
|
||||
CFLAGS += -g
|
||||
|
||||
# Enable extra warnings and make all warnings into errors.
|
||||
CFLAGS += -Wextra -Werror
|
||||
|
||||
# Flags to generate dependency information.
|
||||
CFLAGS += -MD -MP -MT $@
|
||||
|
||||
# Predefined flags.
|
||||
ifeq ($(BUILD), debug)
|
||||
CFLAGS += -D_DEBUG
|
||||
CFLAGS += -D_GLIBCXX_DEBUG
|
||||
endif
|
||||
|
||||
# Enable compiler optimizations for everything except debug.
|
||||
# Note that a very aggresssive optimization level is used and it may not be
|
||||
# valid for all standard compliant programs. Reduce this level on individual
|
||||
# files or modules as needed.
|
||||
ifneq ($(BUILD), debug)
|
||||
CFLAGS += -Ofast
|
||||
endif
|
||||
|
||||
# Flag to turn on extended instruction sets for the compiler.
|
||||
CFLAGS += -msse2
|
||||
|
||||
# Let C++ inherit all C flags.
|
||||
CXXFLAGS = $(CFLAGS) -I$(SRC_ROOT)
|
||||
|
||||
# Enable C++20
|
||||
CXXFLAGS += -std=c++20
|
||||
|
||||
# Vulkan config
|
||||
CFLAGS += -DVK_USE_PLATFORM_XLIB_KHR
|
||||
CFLAGS += -DVMA_STATIC_VULKAN_FUNCTIONS=1
|
||||
CFLAGS += -I$(SRC_ROOT)/third_party/vulkan/include
|
||||
CXXFLAGS += -I$(SRC_ROOT)/third_party/glslang
|
||||
|
||||
# --- Internal functions ---
|
||||
|
||||
app_exe = $(OUTPUT_DIR)/$(1)_$(ARCH)_$(BUILD)
|
||||
objs_from_src = $(patsubst $(SRC_ROOT)/%, $(BUILD_DIR)/%.o, $(basename $(1)))
|
||||
objs_from_src_in = $(call objs_from_src, $(shell find $(1) -name "*.cc" -o -name "*.cpp" -o -name "*.c"))
|
||||
|
||||
# --- Base ---
|
||||
|
||||
BASE_SRC := \
|
||||
$(SRC_ROOT)/base/collusion_test.cc \
|
||||
$(SRC_ROOT)/base/log.cc \
|
||||
$(SRC_ROOT)/base/sinc_resampler.cc \
|
||||
$(SRC_ROOT)/base/task_runner.cc \
|
||||
$(SRC_ROOT)/base/thread_pool.cc \
|
||||
$(SRC_ROOT)/base/timer.cc
|
||||
|
||||
BASE_LIB := $(BUILD_DIR)/libengine.a
|
||||
BASE_OBJS := $(call objs_from_src, $(BASE_SRC))
|
||||
LIBS += $(BASE_LIB)
|
||||
OBJS += $(BASE_OBJS)
|
||||
|
||||
$(BASE_LIB): $(BASE_OBJS)
|
||||
|
||||
# --- Engine ---
|
||||
|
||||
ENGINE_SRC := \
|
||||
$(SRC_ROOT)/engine/animatable.cc \
|
||||
$(SRC_ROOT)/engine/animator.cc \
|
||||
$(SRC_ROOT)/engine/audio/audio_mixer.cc \
|
||||
$(SRC_ROOT)/engine/audio/audio_sink_alsa.cc \
|
||||
$(SRC_ROOT)/engine/drawable.cc \
|
||||
$(SRC_ROOT)/engine/engine.cc \
|
||||
$(SRC_ROOT)/engine/font.cc \
|
||||
$(SRC_ROOT)/engine/image_quad.cc \
|
||||
$(SRC_ROOT)/engine/image.cc \
|
||||
$(SRC_ROOT)/engine/mesh.cc \
|
||||
$(SRC_ROOT)/engine/persistent_data.cc \
|
||||
$(SRC_ROOT)/engine/platform/asset_file_linux.cc \
|
||||
$(SRC_ROOT)/engine/platform/asset_file.cc \
|
||||
$(SRC_ROOT)/engine/platform/platform_linux.cc \
|
||||
$(SRC_ROOT)/engine/renderer/geometry.cc \
|
||||
$(SRC_ROOT)/engine/renderer/opengl/render_command.cc \
|
||||
$(SRC_ROOT)/engine/renderer/opengl/renderer_opengl_linux.cc \
|
||||
$(SRC_ROOT)/engine/renderer/opengl/renderer_opengl.cc \
|
||||
$(SRC_ROOT)/engine/renderer/renderer_types.cc \
|
||||
$(SRC_ROOT)/engine/renderer/shader.cc \
|
||||
$(SRC_ROOT)/engine/renderer/texture.cc \
|
||||
$(SRC_ROOT)/engine/renderer/vulkan/renderer_vulkan_linux.cc \
|
||||
$(SRC_ROOT)/engine/renderer/vulkan/renderer_vulkan.cc \
|
||||
$(SRC_ROOT)/engine/renderer/vulkan/vulkan_context_linux.cc \
|
||||
$(SRC_ROOT)/engine/renderer/vulkan/vulkan_context.cc \
|
||||
$(SRC_ROOT)/engine/shader_source.cc \
|
||||
$(SRC_ROOT)/engine/solid_quad.cc \
|
||||
$(SRC_ROOT)/engine/sound_player.cc \
|
||||
$(SRC_ROOT)/engine/sound.cc
|
||||
|
||||
ENGINE_LIB := $(BUILD_DIR)/libengine.a
|
||||
ENGINE_OBJS := $(call objs_from_src, $(ENGINE_SRC))
|
||||
LIBS += $(ENGINE_LIB)
|
||||
OBJS += $(ENGINE_OBJS)
|
||||
|
||||
$(ENGINE_LIB): $(ENGINE_OBJS)
|
||||
|
||||
# --- Third-party ---
|
||||
|
||||
# Ignore warnings.
|
||||
THIRD_PARTY_CFLAGS = $(CFLAGS)
|
||||
THIRD_PARTY_CFLAGS := $(filter-out -Wextra -Werror, $(THIRD_PARTY_CFLAGS))
|
||||
|
||||
THIRD_PARTY_CXXFLAGS = $(CXXFLAGS)
|
||||
THIRD_PARTY_CXXFLAGS := $(filter-out -Wextra -Werror, $(THIRD_PARTY_CXXFLAGS))
|
||||
|
||||
THIRD_PARTY_SRC := \
|
||||
$(SRC_ROOT)/third_party/glew/glew.c \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/GenericCodeGen/CodeGen.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/GenericCodeGen/Link.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/attribute.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/Constant.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/glslang_tab.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/InfoSink.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/Initialize.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/Intermediate.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/intermOut.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/IntermTraverse.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/iomapper.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/limits.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/linkValidate.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/parseConst.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/ParseContextBase.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/ParseHelper.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/PoolAlloc.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/propagateNoContraction.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/reflection.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/RemoveTree.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/Scan.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/ShaderLang.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/SymbolTable.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/MachineIndependent/Versions.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/glslang/OSDependent/Unix/ossource.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/OGLCompilersDLL/InitializeDll.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/SPIRV/disassemble.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/SPIRV/doc.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/SPIRV/GlslangToSpv.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/SPIRV/InReadableOrder.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/SPIRV/Logger.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/SPIRV/SpvBuilder.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/SPIRV/SpvPostProcess.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/SPIRV/SPVRemapper.cpp \
|
||||
$(SRC_ROOT)/third_party/glslang/SPIRV/SpvTools.cpp \
|
||||
$(SRC_ROOT)/third_party/jsoncpp/jsoncpp.cpp \
|
||||
$(SRC_ROOT)/third_party/spirv-reflect/spirv_reflect.c \
|
||||
$(SRC_ROOT)/third_party/stb/stb_image.c \
|
||||
$(SRC_ROOT)/third_party/texture_compressor/dxt_encoder_internals.cc \
|
||||
$(SRC_ROOT)/third_party/texture_compressor/dxt_encoder.cc \
|
||||
$(SRC_ROOT)/third_party/texture_compressor/texture_compressor_etc1.cc \
|
||||
$(SRC_ROOT)/third_party/texture_compressor/texture_compressor.cc \
|
||||
$(SRC_ROOT)/third_party/vma/vk_mem_alloc.cpp \
|
||||
$(SRC_ROOT)/third_party/volk/volk.c
|
||||
|
||||
$(BUILD_DIR)/third_party/%.o: $(SRC_ROOT)/third_party/%.c
|
||||
@mkdir -p $(@D)
|
||||
$(HUSH_COMPILE) $(CC) -c $(THIRD_PARTY_CFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_DIR)/third_party/%.o: $(SRC_ROOT)/third_party/%.cc
|
||||
@mkdir -p $(@D)
|
||||
$(HUSH_COMPILE) $(CXX) -c $(THIRD_PARTY_CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_DIR)/third_party/%.o: $(SRC_ROOT)/third_party/%.cpp
|
||||
@mkdir -p $(@D)
|
||||
$(HUSH_COMPILE) $(CXX) -c $(THIRD_PARTY_CXXFLAGS) -o $@ $<
|
||||
|
||||
THIRD_PARTY_LIB := $(BUILD_DIR)/libthirdparty.a
|
||||
THIRD_PARTY_OBJS := $(call objs_from_src, $(THIRD_PARTY_SRC))
|
||||
LIBS += $(THIRD_PARTY_LIB)
|
||||
OBJS += $(THIRD_PARTY_OBJS)
|
||||
|
||||
$(THIRD_PARTY_LIB): $(THIRD_PARTY_OBJS)
|
||||
|
||||
# --- demo application ---
|
||||
|
||||
ifneq ($(filter demo,$(APPS)),)
|
||||
|
||||
DEMO_SRC := \
|
||||
$(SRC_ROOT)/demo/credits.cc \
|
||||
$(SRC_ROOT)/demo/demo.cc \
|
||||
$(SRC_ROOT)/demo/enemy.cc \
|
||||
$(SRC_ROOT)/demo/hud.cc \
|
||||
$(SRC_ROOT)/demo/menu.cc \
|
||||
$(SRC_ROOT)/demo/player.cc \
|
||||
$(SRC_ROOT)/demo/sky_quad.cc
|
||||
|
||||
DEMO_EXE := $(call app_exe,demo)
|
||||
DEMO_OBJS := $(call objs_from_src, $(DEMO_SRC))
|
||||
EXES += $(DEMO_EXE)
|
||||
OBJS += $(DEMO_OBJS)
|
||||
|
||||
$(DEMO_EXE): $(DEMO_OBJS) $(LIBS)
|
||||
|
||||
endif
|
||||
|
||||
# --- Build rules ---
|
||||
|
||||
# Dependencies.
|
||||
DEPS = $(OBJS:.o=.d)
|
||||
-include $(DEPS)
|
||||
|
||||
.PHONY: all clean cleanall help
|
||||
|
||||
all: $(EXES)
|
||||
|
||||
clean:
|
||||
@echo "Cleaning..."
|
||||
$(HUSH_CLEAN) $(RM) -r $(BUILD_DIR)
|
||||
|
||||
cleanall:
|
||||
@echo "Cleaning all..."
|
||||
$(HUSH_CLEAN) $(RM) -r $(INTERMEDIATE_DIR)
|
||||
|
||||
help:
|
||||
@echo "BUILD = Build mode. One of:"
|
||||
@echo " debug (no optimizations)"
|
||||
@echo " release (optimizations, the default)"
|
||||
@echo "APPS = Applications to build. Defaults to all."
|
||||
@echo "VERBOSE = Full output from commands if set."
|
||||
|
||||
# It's important that libraries are specified last as Ubuntu uses "ld --as-needed" by default.
|
||||
# Only the static libraries referenced by the object files will be linked into the executable.
|
||||
# Beware that circular dependencies doesn't work with this flag.
|
||||
$(EXES):
|
||||
@mkdir -p $(@D)
|
||||
$(HUSH_LINK) $(CXX) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
$(BUILD_DIR)/%.a:
|
||||
@mkdir -p $(@D)
|
||||
$(HUSH_GENERATE) $(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_ROOT)/%.c
|
||||
@mkdir -p $(@D)
|
||||
$(HUSH_COMPILE) $(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_ROOT)/%.cc
|
||||
@mkdir -p $(@D)
|
||||
$(HUSH_COMPILE) $(CXX) -c $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_ROOT)/%.cpp
|
||||
@mkdir -p $(@D)
|
||||
$(HUSH_COMPILE) $(CXX) -c $(CXXFLAGS) -o $@ $<
|
|
@ -0,0 +1,11 @@
|
|||
# Build a shared library for Android. Build an executable for other platforms.
|
||||
template("game") {
|
||||
if (target_os == "android") {
|
||||
_target_type = "shared_library"
|
||||
} else {
|
||||
_target_type = "executable"
|
||||
}
|
||||
target(_target_type, target_name) {
|
||||
forward_variables_from(invoker, "*")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
src, dst = sys.argv[1:]
|
||||
|
||||
if os.path.exists(dst):
|
||||
if os.path.isdir(dst):
|
||||
shutil.rmtree(dst)
|
||||
else:
|
||||
os.remove(dst)
|
||||
|
||||
if os.path.isdir(src):
|
||||
shutil.copytree(src, dst)
|
||||
else:
|
||||
shutil.copy2(src, dst)
|
||||
|
||||
# https://github.com/ninja-build/ninja/issues/1554
|
||||
os.utime(dst, None)
|
|
@ -0,0 +1,130 @@
|
|||
toolchain("gcc") {
|
||||
lib_switch = "-l"
|
||||
lib_dir_switch = "-L"
|
||||
|
||||
tool("asm") {
|
||||
depfile = "{{output}}.d"
|
||||
command = "$cc -MD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
|
||||
depsformat = "gcc"
|
||||
outputs =
|
||||
[ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
|
||||
description = "assemble {{source}}"
|
||||
}
|
||||
|
||||
tool("cc") {
|
||||
depfile = "{{output}}.d"
|
||||
command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
|
||||
depsformat = "gcc"
|
||||
outputs =
|
||||
[ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
|
||||
description = "compile {{output}}"
|
||||
}
|
||||
|
||||
tool("cxx") {
|
||||
depfile = "{{output}}.d"
|
||||
command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
|
||||
depsformat = "gcc"
|
||||
outputs =
|
||||
[ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
|
||||
description = "compile {{output}}"
|
||||
}
|
||||
|
||||
tool("objc") {
|
||||
depfile = "{{output}}.d"
|
||||
command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_c}} {{cflags_objc}} -c {{source}} -o {{output}}"
|
||||
depsformat = "gcc"
|
||||
outputs =
|
||||
[ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
|
||||
description = "compile {{output}}"
|
||||
}
|
||||
|
||||
tool("objcxx") {
|
||||
depfile = "{{output}}.d"
|
||||
command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_cc}} {{cflags_objcc}} -c {{source}} -o {{output}}"
|
||||
depsformat = "gcc"
|
||||
outputs =
|
||||
[ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
|
||||
description = "compile {{output}}"
|
||||
}
|
||||
|
||||
if (is_apple) {
|
||||
not_needed([ "ar" ]) # libtool is used instead.
|
||||
}
|
||||
|
||||
tool("alink") {
|
||||
if (is_apple) {
|
||||
command =
|
||||
"libtool -static -o {{output}} -no_warning_for_no_symbols {{inputs}}"
|
||||
} else {
|
||||
command = "rm -f {{output}} && $ar rcs {{output}} {{inputs}}"
|
||||
}
|
||||
outputs =
|
||||
[ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
|
||||
default_output_extension = ".a"
|
||||
output_prefix = "lib"
|
||||
description = "link {{target_output_name}}{{output_extension}}"
|
||||
}
|
||||
|
||||
tool("solink") {
|
||||
soname = "{{target_output_name}}{{output_extension}}"
|
||||
sofile = "{{output_dir}}/$soname"
|
||||
rspfile = soname + ".rsp"
|
||||
if (is_apple) {
|
||||
os_specific_option = "-install_name @executable_path/$sofile"
|
||||
rspfile_content = "{{inputs}} {{solibs}} {{libs}}"
|
||||
} else {
|
||||
os_specific_option = "-Wl,-soname=$soname"
|
||||
rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
|
||||
}
|
||||
command = "$cxx -shared {{ldflags}} {{frameworks}} -o $sofile $os_specific_option @$rspfile"
|
||||
default_output_extension = ".so"
|
||||
default_output_dir = "{{root_out_dir}}"
|
||||
outputs = [ sofile ]
|
||||
link_output = sofile
|
||||
depend_output = sofile
|
||||
output_prefix = "lib"
|
||||
description = "link $soname"
|
||||
}
|
||||
|
||||
tool("link") {
|
||||
outfile = "{{target_output_name}}{{output_extension}}"
|
||||
rspfile = "$outfile.rsp"
|
||||
rspfile_content = "{{inputs}}"
|
||||
if (is_apple) {
|
||||
command = "$cxx {{ldflags}} {{solibs}} {{libs}} {{frameworks}} -o $outfile @$rspfile"
|
||||
} else {
|
||||
command = "$cxx {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}"
|
||||
}
|
||||
default_output_dir = "{{root_out_dir}}"
|
||||
outputs = [ outfile ]
|
||||
description = "link $outfile"
|
||||
}
|
||||
|
||||
if (host_os == "win") {
|
||||
tool("stamp") {
|
||||
command = "cmd.exe /c echo > {{output}}"
|
||||
description = "stamp {{output}}"
|
||||
}
|
||||
|
||||
tool("copy") {
|
||||
# Note: The build in copy command can't handle forward slashes as path separators.
|
||||
# Use a python script as a work around.
|
||||
# command = "cmd.exe /c copy /Y {{source}} {{output}}"
|
||||
|
||||
copy_cmd = rebase_path("../copy.py")
|
||||
command = "python \"$copy_cmd\" {{source}} {{output}}"
|
||||
|
||||
description = "copy {{source}} {{output}}"
|
||||
}
|
||||
} else {
|
||||
tool("stamp") {
|
||||
command = "touch {{output}}"
|
||||
description = "stamp {{output}}"
|
||||
}
|
||||
|
||||
tool("copy") {
|
||||
command = "cp -af {{source}} {{output}}"
|
||||
description = "copy {{source}} {{output}}"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
toolchain("msvc") {
|
||||
lib_switch = ""
|
||||
lib_dir_switch = "/LIBPATH:"
|
||||
|
||||
tool("asm") {
|
||||
command = "ml.exe {{asmflags}} /nologo /c /Fo {{output}} {{source}}"
|
||||
outputs =
|
||||
[ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ]
|
||||
description = "assemble {{source}}"
|
||||
}
|
||||
|
||||
tool("cc") {
|
||||
pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
|
||||
command = "cl.exe /nologo /showIncludes /FC {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
|
||||
depsformat = "msvc"
|
||||
outputs =
|
||||
[ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ]
|
||||
description = "compile {{source}}"
|
||||
}
|
||||
|
||||
tool("cxx") {
|
||||
pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
|
||||
command = "cl.exe /nologo /showIncludes /FC {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
|
||||
depsformat = "msvc"
|
||||
outputs =
|
||||
[ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ]
|
||||
description = "compile {{source}}"
|
||||
}
|
||||
|
||||
tool("alink") {
|
||||
rspfile = "{{output}}.rsp"
|
||||
command = "lib.exe /nologo {{arflags}} /OUT:{{output}} @$rspfile"
|
||||
outputs = [ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" ]
|
||||
default_output_extension = ".lib"
|
||||
default_output_dir = "{{target_out_dir}}"
|
||||
rspfile_content = "{{inputs_newline}}"
|
||||
description = "link {{output}}"
|
||||
}
|
||||
|
||||
tool("solink") {
|
||||
dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
|
||||
libname = "${dllname}.lib"
|
||||
pdbname = "${dllname}.pdb"
|
||||
rspfile = "${dllname}.rsp"
|
||||
command = "link.exe /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:$pdbname @$rspfile"
|
||||
outputs = [
|
||||
dllname,
|
||||
libname,
|
||||
pdbname,
|
||||
]
|
||||
default_output_extension = ".dll"
|
||||
default_output_dir = "{{root_out_dir}}"
|
||||
link_output = libname
|
||||
depend_output = libname
|
||||
runtime_outputs = [
|
||||
dllname,
|
||||
pdbname,
|
||||
]
|
||||
rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
|
||||
description = "link {{output}}"
|
||||
}
|
||||
|
||||
tool("link") {
|
||||
exename = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
|
||||
pdbname = "$exename.pdb"
|
||||
rspfile = "$exename.rsp"
|
||||
command = "link.exe /nologo /OUT:$exename /PDB:$pdbname @$rspfile"
|
||||
default_output_extension = ".exe"
|
||||
default_output_dir = "{{root_out_dir}}"
|
||||
outputs = [ exename ]
|
||||
rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
|
||||
description = "link {{output}}"
|
||||
}
|
||||
|
||||
tool("stamp") {
|
||||
command = "cmd.exe /c echo > {{output}}"
|
||||
description = "stamp {{output}}"
|
||||
}
|
||||
|
||||
tool("copy") {
|
||||
# Note: The build in copy command can't handle forward slashes as path separators.
|
||||
# Use a python script as a work around.
|
||||
# command = "cmd.exe /c copy /Y {{source}} {{output}}"
|
||||
|
||||
copy_cmd = rebase_path("../copy.py")
|
||||
command = "python \"$copy_cmd\" {{source}} {{output}}"
|
||||
|
||||
description = "copy {{source}} {{output}}"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
source_set("base") {
|
||||
sources = [
|
||||
"closure.h",
|
||||
"collusion_test.cc",
|
||||
"collusion_test.h",
|
||||
"file.h",
|
||||
"hash.h",
|
||||
"interpolation.h",
|
||||
"log.cc",
|
||||
"log.h",
|
||||
"mem.cc",
|
||||
"mem.h",
|
||||
"misc.h",
|
||||
"random.h",
|
||||
"task_runner.cc",
|
||||
"task_runner.h",
|
||||
"thread_pool.cc",
|
||||
"thread_pool.h",
|
||||
"timer.h",
|
||||
"vecmath.h",
|
||||
]
|
||||
|
||||
deps = []
|
||||
}
|
|
@ -10,14 +10,13 @@
|
|||
|
||||
#define HERE std::make_tuple(__func__, __FILE__, __LINE__)
|
||||
|
||||
// Helper for logging location info, e.g. LOG << LOCATION(from)
|
||||
// Helper for logging location info, e.g. LOG(0) << LOCATION(from)
|
||||
#define LOCATION(from) \
|
||||
std::get<0>(from) << "() [" << [](const char* path) -> std::string { \
|
||||
std::string file_name(path); \
|
||||
size_t last_slash_pos = file_name.find_last_of("\\/"); \
|
||||
std::get<0>(from) << "() [" << [](std::string path) -> std::string { \
|
||||
size_t last_slash_pos = path.find_last_of("\\/"); \
|
||||
if (last_slash_pos != std::string::npos) \
|
||||
file_name = file_name.substr(last_slash_pos + 1); \
|
||||
return file_name; \
|
||||
path = path.substr(last_slash_pos + 1); \
|
||||
return path; \
|
||||
}(std::get<1>(from)) << ":" \
|
||||
<< std::get<2>(from) << "]"
|
||||
|
||||
|
@ -36,7 +35,7 @@ using Closure = std::function<void()>;
|
|||
|
||||
// Provides location info (function name, file name and line number) where of a
|
||||
// Closure was constructed.
|
||||
using Location = std::tuple<const char*, const char*, int>;
|
||||
using Location = std::tuple<std::string, std::string, int>;
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
@ -6,17 +6,15 @@
|
|||
|
||||
namespace base {
|
||||
|
||||
// Compile-time string hashing function.
|
||||
template <size_t N>
|
||||
constexpr inline size_t Hash(const char (&str)[N], size_t Len = N - 1) {
|
||||
constexpr inline size_t KR2Hash(const char (&str)[N], size_t Len = N - 1) {
|
||||
size_t hash_value = 0;
|
||||
for (int i = 0; str[i] != '\0'; ++i)
|
||||
hash_value = str[i] + 31 * hash_value;
|
||||
return hash_value;
|
||||
}
|
||||
|
||||
// The same hashing function for run-time.
|
||||
inline size_t Hash(const std::string& str) {
|
||||
inline size_t KR2Hash(const std::string& str) {
|
||||
size_t hash_value = 0;
|
||||
for (std::string::value_type c : str)
|
||||
hash_value = c + 31 * hash_value;
|
||||
|
|
|
@ -2,52 +2,74 @@
|
|||
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/log.h>
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <format>
|
||||
#else
|
||||
#include <cstdio>
|
||||
#endif
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
int g_max_log_verbosity_level = 0;
|
||||
|
||||
} // namespace
|
||||
|
||||
// This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to have
|
||||
// an object of the correct type on the LHS of the unused part of the ternary
|
||||
// operator.
|
||||
std::ostream* LogMessage::swallow_stream;
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line) : file_(file), line_(line) {}
|
||||
int GlobalMaxLogVerbosityLevel() {
|
||||
return g_max_log_verbosity_level;
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, int verbosity_level)
|
||||
: file_(file), line_(line), verbosity_level_(verbosity_level) {}
|
||||
|
||||
LogMessage::~LogMessage() {
|
||||
stream_ << std::endl;
|
||||
std::string text(stream_.str());
|
||||
std::string message(stream_.str());
|
||||
std::string filename(file_);
|
||||
size_t last_slash_pos = filename.find_last_of("\\/");
|
||||
if (last_slash_pos != std::string::npos)
|
||||
filename = filename.substr(last_slash_pos + 1);
|
||||
#if defined(__ANDROID__)
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kaliber", "[%s:%d] %s",
|
||||
filename.c_str(), line_, text.c_str());
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kaliber", "%d [%s:%d] %s",
|
||||
verbosity_level_, filename.c_str(), line_,
|
||||
message.c_str());
|
||||
#elif defined(_WIN32)
|
||||
OutputDebugStringA(
|
||||
std::format("{} [{}:{}] {}", verbosity_level_, filename, line_, message)
|
||||
.c_str());
|
||||
#else
|
||||
printf("[%s:%d] %s", filename.c_str(), line_, text.c_str());
|
||||
printf("%d [%s:%d] %s", verbosity_level_, filename.c_str(), line_,
|
||||
message.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
// static
|
||||
LogAbort LogAbort::Check(const char* file, int line, const char* expr) {
|
||||
LogAbort instance(new LogMessage(file, line));
|
||||
instance.GetLog().stream() << "CHECK: "
|
||||
<< "(" << expr << ") ";
|
||||
LogAbort instance(new LogMessage(file, line, 0));
|
||||
instance.GetLog().stream() << "CHECK(" << expr << ") ";
|
||||
return instance;
|
||||
}
|
||||
|
||||
// static
|
||||
LogAbort LogAbort::DCheck(const char* file, int line, const char* expr) {
|
||||
LogAbort instance(new LogMessage(file, line));
|
||||
instance.GetLog().stream() << "DCHECK: "
|
||||
<< "(" << expr << ") ";
|
||||
LogAbort instance(new LogMessage(file, line, 0));
|
||||
instance.GetLog().stream() << "DCHECK(" << expr << ") ";
|
||||
return instance;
|
||||
}
|
||||
|
||||
// static
|
||||
LogAbort LogAbort::NotReached(const char* file, int line) {
|
||||
LogAbort instance(new LogMessage(file, line));
|
||||
instance.GetLog().stream() << "NOTREACHED ";
|
||||
LogAbort instance(new LogMessage(file, line, 0));
|
||||
instance.GetLog().stream() << "NOTREACHED() ";
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,45 +11,66 @@
|
|||
// CHECK(condition) terminates the process if the condition is false.
|
||||
// NOTREACHED annotates unreachable codepaths and terminates the process if
|
||||
// reached.
|
||||
#define LOG base::LogMessage(__FILE__, __LINE__).stream()
|
||||
#define LOG_IF(condition) \
|
||||
LAZY_STREAM(condition, base::LogMessage(__FILE__, __LINE__).stream())
|
||||
#define CHECK(condition) \
|
||||
LAZY_STREAM( \
|
||||
!(condition), \
|
||||
base::LogAbort::Check(__FILE__, __LINE__, #condition).GetLog().stream())
|
||||
#define LOG(verbosity_level) \
|
||||
LAZY_STREAM( \
|
||||
LOG_IS_ON(verbosity_level), \
|
||||
::base::LogMessage(__FILE__, __LINE__, verbosity_level).stream())
|
||||
#define LOG_IF(verbosity_level, condition) \
|
||||
LAZY_STREAM( \
|
||||
LOG_IS_ON(verbosity_level) && (condition), \
|
||||
::base::LogMessage(__FILE__, __LINE__, verbosity_level).stream())
|
||||
#define CHECK(condition) \
|
||||
LAZY_STREAM(!(condition), \
|
||||
::base::LogAbort::Check(__FILE__, __LINE__, #condition) \
|
||||
.GetLog() \
|
||||
.stream())
|
||||
|
||||
#define NOTREACHED \
|
||||
base::LogAbort::NotReached(__FILE__, __LINE__).GetLog().stream()
|
||||
#define NOTREACHED() \
|
||||
::base::LogAbort::NotReached(__FILE__, __LINE__).GetLog().stream()
|
||||
|
||||
// Macros for logging which are active only in debug builds.
|
||||
#ifdef _DEBUG
|
||||
#define DLOG base::LogMessage(__FILE__, __LINE__).stream()
|
||||
#define DLOG_IF(condition) \
|
||||
LAZY_STREAM(condition, base::LogMessage(__FILE__, __LINE__).stream())
|
||||
#define DCHECK(condition) \
|
||||
LAZY_STREAM(!(condition), \
|
||||
base::LogAbort::DCheck(__FILE__, __LINE__, #condition) \
|
||||
.GetLog() \
|
||||
#define DLOG(verbosity_level) \
|
||||
LAZY_STREAM( \
|
||||
LOG_IS_ON(verbosity_level), \
|
||||
::base::LogMessage(__FILE__, __LINE__, verbosity_level).stream())
|
||||
#define DLOG_IF(verbosity_level, condition) \
|
||||
LAZY_STREAM( \
|
||||
LOG_IS_ON(verbosity_level) && (condition), \
|
||||
::base::LogMessage(__FILE__, __LINE__, verbosity_level).stream())
|
||||
#define DCHECK(condition) \
|
||||
LAZY_STREAM(!(condition), \
|
||||
::base::LogAbort::DCheck(__FILE__, __LINE__, #condition) \
|
||||
.GetLog() \
|
||||
.stream())
|
||||
#else
|
||||
// "debug mode" logging is compiled away to nothing for release builds.
|
||||
#define DLOG EAT_STREAM_PARAMETERS
|
||||
#define DLOG_IF(condition) EAT_STREAM_PARAMETERS
|
||||
#define DLOG(verbosity_level) EAT_STREAM_PARAMETERS
|
||||
#define DLOG_IF(verbosity_level, condition) EAT_STREAM_PARAMETERS
|
||||
#define DCHECK(condition) EAT_STREAM_PARAMETERS
|
||||
#endif
|
||||
|
||||
// Helper macro which avoids evaluating the arguments to a stream if
|
||||
// the condition doesn't hold.
|
||||
#define LAZY_STREAM(condition, stream) \
|
||||
!(condition) ? (void)0 : base::LogMessage::Voidify() & (stream)
|
||||
!(condition) ? (void)0 : ::base::LogMessage::Voidify() & (stream)
|
||||
|
||||
// Avoid any pointless instructions to be emitted by the compiler.
|
||||
#define EAT_STREAM_PARAMETERS \
|
||||
LAZY_STREAM(false, *base::LogMessage::swallow_stream)
|
||||
LAZY_STREAM(false, *::base::LogMessage::swallow_stream)
|
||||
|
||||
#if defined(MAX_LOG_VERBOSITY_LEVEL)
|
||||
#define LOG_IS_ON(verbosity_level) \
|
||||
((verbosity_level) <= MAX_LOG_VERBOSITY_LEVEL)
|
||||
#else
|
||||
#define LOG_IS_ON(verbosity_level) \
|
||||
((verbosity_level) <= ::base::GlobalMaxLogVerbosityLevel())
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
int GlobalMaxLogVerbosityLevel();
|
||||
|
||||
class LogMessage {
|
||||
public:
|
||||
class Voidify {
|
||||
|
@ -61,18 +82,17 @@ class LogMessage {
|
|||
void operator&(std::ostream&) {}
|
||||
};
|
||||
|
||||
LogMessage(const char* file, int line);
|
||||
LogMessage(const char* file, int line, int verbosity_level);
|
||||
~LogMessage();
|
||||
|
||||
LogMessage& base() { return *this; }
|
||||
|
||||
std::ostream& stream() { return stream_; }
|
||||
|
||||
static std::ostream* swallow_stream;
|
||||
|
||||
protected:
|
||||
const char* file_;
|
||||
const int line_;
|
||||
int line_;
|
||||
int verbosity_level_;
|
||||
std::ostringstream stream_;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#include "base/mem.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
void* AlignedAlloc(size_t size, size_t alignment) {
|
||||
DCHECK(size > 0U);
|
||||
DCHECK(IsPow2(alignment));
|
||||
DCHECK((alignment % sizeof(void*)) == 0U);
|
||||
|
||||
void* ptr = nullptr;
|
||||
#if defined(_WIN32)
|
||||
ptr = _aligned_malloc(size, alignment);
|
||||
#elif defined(__ANDROID__)
|
||||
ptr = memalign(alignment, size);
|
||||
#else
|
||||
int ret = posix_memalign(&ptr, alignment, size);
|
||||
if (ret != 0) {
|
||||
DLOG(0) << "posix_memalign() returned with error " << ret;
|
||||
ptr = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Aligned allocations may fail for non-memory related reasons.
|
||||
CHECK(ptr) << "Aligned allocation failed. "
|
||||
<< "size=" << size << ", alignment=" << alignment;
|
||||
DCHECK(IsAligned(ptr, alignment));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* AlignedRealloc(void* ptr,
|
||||
size_t old_size,
|
||||
size_t new_size,
|
||||
size_t alignment) {
|
||||
auto* new_ptr = AlignedAlloc(new_size, alignment);
|
||||
memmove(new_ptr, ptr, old_size);
|
||||
AlignedFree(ptr);
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -1,26 +1,33 @@
|
|||
#ifndef BASE_MEM_H
|
||||
#define BASE_MEM_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(_WIN32)
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "base/log.h"
|
||||
|
||||
#define ALIGN_MEM(alignment) __attribute__((aligned(alignment)))
|
||||
#include "base/misc.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
inline void AlignedFree(void* mem) {
|
||||
#if defined(_WIN32)
|
||||
_aligned_free(mem);
|
||||
#else
|
||||
free(mem);
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct ScopedAlignedFree {
|
||||
inline void operator()(void* x) const {
|
||||
if (x)
|
||||
free(x);
|
||||
}
|
||||
inline void operator()(void* x) const { AlignedFree(x); }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -28,27 +35,16 @@ struct ScopedAlignedFree {
|
|||
template <typename T>
|
||||
using AlignedMemPtr = std::unique_ptr<T, internal::ScopedAlignedFree>;
|
||||
|
||||
template <int kAlignment>
|
||||
inline void* AlignedAlloc(size_t size) {
|
||||
void* ptr = NULL;
|
||||
#if defined(__ANDROID__)
|
||||
ptr = memalign(kAlignment, size);
|
||||
#else
|
||||
if (posix_memalign(&ptr, kAlignment, size))
|
||||
ptr = NULL;
|
||||
#endif
|
||||
DCHECK(ptr);
|
||||
// DCHECK(((unsigned)ptr & (kAlignment - 1)) == 0);
|
||||
return ptr;
|
||||
}
|
||||
void* AlignedAlloc(size_t size, size_t alignment);
|
||||
|
||||
inline void AlignedFree(void* mem) {
|
||||
free(mem);
|
||||
}
|
||||
void* AlignedRealloc(void* ptr,
|
||||
size_t old_size,
|
||||
size_t new_size,
|
||||
size_t alignment);
|
||||
|
||||
template <int kAlignment>
|
||||
inline bool IsAligned(void* ptr) {
|
||||
return (reinterpret_cast<uintptr_t>(ptr) & (kAlignment - 1)) == 0U;
|
||||
inline bool IsAligned(const void* val, size_t alignment) {
|
||||
DCHECK(IsPow2(alignment)) << alignment << " is not a power of 2";
|
||||
return (reinterpret_cast<uintptr_t>(val) & (alignment - 1)) == 0;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
|
|
@ -1,31 +1,42 @@
|
|||
#ifndef BASE_MISC_H
|
||||
#define BASE_MISC_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define CRASH *((int*)nullptr) = 0;
|
||||
|
||||
namespace base {
|
||||
|
||||
// ToDo: x86 has the bsr instruction.
|
||||
inline int GetHighestBitPos(int value) {
|
||||
return (0xFFFF0000 & value ? value &= 0xFFFF0000, 1 : 0) * 0x10 +
|
||||
(0xFF00FF00 & value ? value &= 0xFF00FF00, 1 : 0) * 0x08 +
|
||||
(0xF0F0F0F0 & value ? value &= 0xF0F0F0F0, 1 : 0) * 0x04 +
|
||||
(0xCCCCCCCC & value ? value &= 0xCCCCCCCC, 1 : 0) * 0x02 +
|
||||
(0xAAAAAAAA & value ? 1 : 0) * 0x01;
|
||||
inline uint32_t GetHighestBitPos(uint32_t value) {
|
||||
uint32_t result = 0;
|
||||
if (0xFFFF0000 & value) {
|
||||
value &= 0xFFFF0000;
|
||||
result += 0x10;
|
||||
}
|
||||
if (0xFF00FF00 & value) {
|
||||
value &= 0xFF00FF00;
|
||||
result += 0x8;
|
||||
}
|
||||
if (0xF0F0F0F0 & value) {
|
||||
value &= 0xF0F0F0F0;
|
||||
result += 0x04;
|
||||
}
|
||||
if (0xCCCCCCCC & value) {
|
||||
value &= 0xCCCCCCCC;
|
||||
result += 0x02;
|
||||
}
|
||||
if (0xAAAAAAAA & value) {
|
||||
result += 0x01;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get the highest set bit in an integer number
|
||||
inline int GetHighestBit(int value) {
|
||||
return 0x1 << GetHighestBitPos(value);
|
||||
}
|
||||
|
||||
// Check if the given integer is a power of two, ie if only one bit is set.
|
||||
inline bool IsPow2(int value) {
|
||||
return GetHighestBit(value) == value;
|
||||
return ((value & (value - 1)) == 0);
|
||||
}
|
||||
|
||||
inline int RoundUpToPow2(int val) {
|
||||
int i = GetHighestBit(val);
|
||||
inline uint32_t RoundUpToPow2(uint32_t val) {
|
||||
uint32_t i = 1 << GetHighestBitPos(val);
|
||||
return val == i ? val : i << 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,55 +4,75 @@
|
|||
|
||||
#include "base/log.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
void PostTaskAndReplyRelay(base::Location from,
|
||||
base::Closure task_cb,
|
||||
base::Closure reply_cb,
|
||||
base::TaskRunner* destination) {
|
||||
void PostTaskAndReplyRelay(Location from,
|
||||
Closure task_cb,
|
||||
Closure reply_cb,
|
||||
std::shared_ptr<TaskRunner> destination,
|
||||
bool front) {
|
||||
task_cb();
|
||||
|
||||
if (reply_cb)
|
||||
destination->PostTask(from, std::move(reply_cb));
|
||||
destination->PostTask(from, std::move(reply_cb), front);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace base {
|
||||
|
||||
thread_local std::unique_ptr<TaskRunner> TaskRunner::thread_local_task_runner;
|
||||
// The task runner that belongs to the thread it's created in. Tasks to be run
|
||||
// on a specific thread can be posted to this task runner.
|
||||
// TaskRunner::GetThreadLocalTaskRunner()->RunTasks() is expected to be
|
||||
// periodically called.
|
||||
thread_local std::shared_ptr<TaskRunner> TaskRunner::thread_local_task_runner;
|
||||
|
||||
void TaskRunner::CreateThreadLocalTaskRunner() {
|
||||
DCHECK(!thread_local_task_runner);
|
||||
|
||||
thread_local_task_runner = std::make_unique<TaskRunner>();
|
||||
thread_local_task_runner = std::make_shared<TaskRunner>();
|
||||
}
|
||||
|
||||
TaskRunner* TaskRunner::GetThreadLocalTaskRunner() {
|
||||
return thread_local_task_runner.get();
|
||||
std::shared_ptr<TaskRunner> TaskRunner::GetThreadLocalTaskRunner() {
|
||||
return thread_local_task_runner;
|
||||
}
|
||||
|
||||
void TaskRunner::PostTask(const Location& from, Closure task) {
|
||||
void TaskRunner::PostTask(Location from, Closure task, bool front) {
|
||||
DCHECK(task) << LOCATION(from);
|
||||
|
||||
task_count_.fetch_add(1, std::memory_order_release);
|
||||
task_count_.fetch_add(1, std::memory_order_relaxed);
|
||||
std::lock_guard<std::mutex> scoped_lock(lock_);
|
||||
queue_.emplace_back(from, std::move(task));
|
||||
if (front)
|
||||
queue_.emplace_front(from, std::move(task));
|
||||
else
|
||||
queue_.emplace_back(from, std::move(task));
|
||||
}
|
||||
|
||||
void TaskRunner::PostTaskAndReply(const Location& from,
|
||||
void TaskRunner::PostTaskAndReply(Location from,
|
||||
Closure task,
|
||||
Closure reply) {
|
||||
Closure reply,
|
||||
bool front) {
|
||||
DCHECK(task) << LOCATION(from);
|
||||
DCHECK(reply) << LOCATION(from);
|
||||
DCHECK(thread_local_task_runner) << LOCATION(from);
|
||||
|
||||
auto relay = std::bind(::PostTaskAndReplyRelay, from, std::move(task),
|
||||
std::move(reply), thread_local_task_runner.get());
|
||||
PostTask(from, std::move(relay));
|
||||
auto relay = std::bind(PostTaskAndReplyRelay, from, std::move(task),
|
||||
std::move(reply), thread_local_task_runner, front);
|
||||
PostTask(from, std::move(relay), front);
|
||||
}
|
||||
|
||||
void TaskRunner::MultiConsumerRun() {
|
||||
void TaskRunner::CancelTasks() {
|
||||
std::lock_guard<std::mutex> scoped_lock(lock_);
|
||||
task_count_.fetch_sub(queue_.size(), std::memory_order_release);
|
||||
queue_.clear();
|
||||
}
|
||||
|
||||
void TaskRunner::WaitForCompletion() {
|
||||
while (task_count_.load(std::memory_order_acquire) > 0)
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
void TaskRunner::RunTasks() {
|
||||
for (;;) {
|
||||
Task task;
|
||||
{
|
||||
|
@ -66,7 +86,7 @@ void TaskRunner::MultiConsumerRun() {
|
|||
auto [from, task_cb] = task;
|
||||
|
||||
#if 0
|
||||
LOG << __func__ << " from: " << LOCATION(from);
|
||||
LOG(0) << __func__ << " from: " << LOCATION(from);
|
||||
#endif
|
||||
|
||||
task_cb();
|
||||
|
@ -74,31 +94,4 @@ void TaskRunner::MultiConsumerRun() {
|
|||
}
|
||||
}
|
||||
|
||||
void TaskRunner::SingleConsumerRun() {
|
||||
std::deque<Task> queue;
|
||||
{
|
||||
std::lock_guard<std::mutex> scoped_lock(lock_);
|
||||
if (queue_.empty())
|
||||
return;
|
||||
queue.swap(queue_);
|
||||
}
|
||||
|
||||
while (!queue.empty()) {
|
||||
auto [from, task_cb] = queue.front();
|
||||
queue.pop_front();
|
||||
|
||||
#if 0
|
||||
LOG << __func__ << " from: " << LOCATION(from);
|
||||
#endif
|
||||
|
||||
task_cb();
|
||||
task_count_.fetch_sub(1, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskRunner::WaitForCompletion() {
|
||||
while (task_count_.load(std::memory_order_acquire) > 0)
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
|
|
@ -18,55 +18,66 @@ namespace internal {
|
|||
// one that returns via an output parameter.
|
||||
template <typename ReturnType>
|
||||
void ReturnAsParamAdapter(std::function<ReturnType()> func,
|
||||
ReturnType* result) {
|
||||
std::shared_ptr<ReturnType> result) {
|
||||
*result = func();
|
||||
}
|
||||
|
||||
// Adapts a ReturnType* result to a callblack that expects a ReturnType.
|
||||
// Adapts a ReturnType* result to a callback that expects a ReturnType.
|
||||
template <typename ReturnType>
|
||||
void ReplyAdapter(std::function<void(ReturnType)> callback,
|
||||
ReturnType* result) {
|
||||
callback(*result);
|
||||
delete result;
|
||||
std::shared_ptr<ReturnType> result) {
|
||||
callback(std::move(*result));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Runs queued tasks (in the form of Closure objects). All methods are
|
||||
// thread-safe and can be called on any thread.
|
||||
// Tasks run in FIFO order. When consumed concurrently by multiple threads, it
|
||||
// doesn't guarantee whether tasks overlap, or whether they run on a particular
|
||||
// thread.
|
||||
// Tasks run in FIFO order when consumed by a single thread. When consumed
|
||||
// concurrently by multiple threads, it doesn't guarantee whether tasks overlap,
|
||||
// or whether they run on a particular thread.
|
||||
class TaskRunner {
|
||||
public:
|
||||
TaskRunner() = default;
|
||||
~TaskRunner() = default;
|
||||
|
||||
void PostTask(const Location& from, Closure task);
|
||||
static void CreateThreadLocalTaskRunner();
|
||||
static std::shared_ptr<TaskRunner> GetThreadLocalTaskRunner();
|
||||
|
||||
void PostTaskAndReply(const Location& from, Closure task, Closure reply);
|
||||
void PostTask(Location from, Closure task, bool front = false);
|
||||
|
||||
void PostTaskAndReply(Location from,
|
||||
Closure task,
|
||||
Closure reply,
|
||||
bool front = false);
|
||||
|
||||
template <typename ReturnType>
|
||||
void PostTaskAndReplyWithResult(const Location& from,
|
||||
void PostTaskAndReplyWithResult(Location from,
|
||||
std::function<ReturnType()> task,
|
||||
std::function<void(ReturnType)> reply) {
|
||||
auto* result = new ReturnType;
|
||||
std::function<void(ReturnType)> reply,
|
||||
bool front = false) {
|
||||
auto result = std::make_shared<ReturnType>();
|
||||
return PostTaskAndReply(
|
||||
from,
|
||||
std::bind(internal::ReturnAsParamAdapter<ReturnType>, std::move(task),
|
||||
result),
|
||||
std::bind(internal::ReplyAdapter<ReturnType>, std::move(reply),
|
||||
result));
|
||||
std::bind(internal::ReplyAdapter<ReturnType>, std::move(reply), result),
|
||||
front);
|
||||
}
|
||||
|
||||
void MultiConsumerRun();
|
||||
// Posts a task that deletes the given object.
|
||||
template <class T>
|
||||
void Delete(Location from, std::unique_ptr<T> object) {
|
||||
// std::function target must be copy-constructible
|
||||
std::shared_ptr<T> owned = std::move(object);
|
||||
PostTask(HERE, [owned]() {});
|
||||
}
|
||||
|
||||
void SingleConsumerRun();
|
||||
void CancelTasks();
|
||||
|
||||
void WaitForCompletion();
|
||||
|
||||
static void CreateThreadLocalTaskRunner();
|
||||
static TaskRunner* GetThreadLocalTaskRunner();
|
||||
void RunTasks();
|
||||
|
||||
private:
|
||||
using Task = std::tuple<Location, Closure>;
|
||||
|
@ -75,7 +86,7 @@ class TaskRunner {
|
|||
mutable std::mutex lock_;
|
||||
std::atomic<size_t> task_count_{0};
|
||||
|
||||
static thread_local std::unique_ptr<TaskRunner> thread_local_task_runner;
|
||||
static thread_local std::shared_ptr<TaskRunner> thread_local_task_runner;
|
||||
|
||||
TaskRunner(TaskRunner const&) = delete;
|
||||
TaskRunner& operator=(TaskRunner const&) = delete;
|
||||
|
|
|
@ -40,30 +40,30 @@ void ThreadPool::Shutdown() {
|
|||
threads_.clear();
|
||||
}
|
||||
|
||||
void ThreadPool::PostTask(const Location& from, Closure task) {
|
||||
DCHECK((!threads_.empty()));
|
||||
|
||||
task_runner_.PostTask(from, std::move(task));
|
||||
void ThreadPool::PostTask(Location from, Closure task, bool front) {
|
||||
task_runner_.PostTask(from, std::move(task), front);
|
||||
semaphore_.release();
|
||||
}
|
||||
|
||||
void ThreadPool::PostTaskAndReply(const Location& from,
|
||||
void ThreadPool::PostTaskAndReply(Location from,
|
||||
Closure task,
|
||||
Closure reply) {
|
||||
DCHECK((!threads_.empty()));
|
||||
|
||||
task_runner_.PostTaskAndReply(from, std::move(task), std::move(reply));
|
||||
Closure reply,
|
||||
bool front) {
|
||||
task_runner_.PostTaskAndReply(from, std::move(task), std::move(reply), front);
|
||||
semaphore_.release();
|
||||
}
|
||||
|
||||
void ThreadPool::CancelTasks() {
|
||||
task_runner_.CancelTasks();
|
||||
}
|
||||
|
||||
void ThreadPool::WorkerMain() {
|
||||
for (;;) {
|
||||
semaphore_.acquire();
|
||||
|
||||
if (quit_.load(std::memory_order_relaxed))
|
||||
return;
|
||||
|
||||
task_runner_.MultiConsumerRun();
|
||||
task_runner_.RunTasks();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
namespace base {
|
||||
|
||||
class TaskRunner;
|
||||
|
||||
// Feed the ThreadPool tasks (in the form of Closure objects) and they will be
|
||||
// called on any thread from the pool.
|
||||
class ThreadPool {
|
||||
|
@ -26,19 +24,25 @@ class ThreadPool {
|
|||
|
||||
void Shutdown();
|
||||
|
||||
void PostTask(const Location& from, Closure task);
|
||||
void PostTask(Location from, Closure task, bool front = false);
|
||||
|
||||
void PostTaskAndReply(const Location& from, Closure task, Closure reply);
|
||||
void PostTaskAndReply(Location from,
|
||||
Closure task,
|
||||
Closure reply,
|
||||
bool front = false);
|
||||
|
||||
template <typename ReturnType>
|
||||
void PostTaskAndReplyWithResult(const Location& from,
|
||||
void PostTaskAndReplyWithResult(Location from,
|
||||
std::function<ReturnType()> task,
|
||||
std::function<void(ReturnType)> reply) {
|
||||
std::function<void(ReturnType)> reply,
|
||||
bool front = false) {
|
||||
task_runner_.PostTaskAndReplyWithResult(from, std::move(task),
|
||||
std::move(reply));
|
||||
std::move(reply), front);
|
||||
semaphore_.release();
|
||||
}
|
||||
|
||||
void CancelTasks();
|
||||
|
||||
private:
|
||||
std::vector<std::thread> threads_;
|
||||
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
#include "base/timer.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace base {
|
||||
|
||||
Timer::Timer() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Timer::Reset() {
|
||||
gettimeofday(&last_time_, nullptr);
|
||||
|
||||
seconds_passed_ = 0.0f;
|
||||
seconds_accumulated_ = 0.0f;
|
||||
}
|
||||
|
||||
void Timer::Update() {
|
||||
timeval currentTime;
|
||||
gettimeofday(¤tTime, nullptr);
|
||||
seconds_passed_ =
|
||||
(float)(currentTime.tv_sec - last_time_.tv_sec) +
|
||||
0.000001f * (float)(currentTime.tv_usec - last_time_.tv_usec);
|
||||
|
||||
last_time_ = currentTime;
|
||||
|
||||
seconds_accumulated_ += seconds_passed_;
|
||||
}
|
||||
|
||||
void Timer::Sleep(float duration) {
|
||||
Timer timer;
|
||||
float accumulator = 0.0;
|
||||
constexpr float epsilon = 0.0001f;
|
||||
|
||||
while (accumulator < duration) {
|
||||
timer.Update();
|
||||
accumulator += timer.GetSecondsPassed();
|
||||
if (duration - accumulator > epsilon) {
|
||||
float sleep_time = duration - accumulator - epsilon;
|
||||
std::this_thread::sleep_for(
|
||||
std::chrono::microseconds((int)(sleep_time * 1000000.0f)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -1,31 +1,47 @@
|
|||
#ifndef BASE_TIMER_H
|
||||
#define BASE_TIMER_H
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
namespace base {
|
||||
|
||||
class Timer {
|
||||
class ElapsedTimer {
|
||||
public:
|
||||
Timer();
|
||||
~Timer() = default;
|
||||
ElapsedTimer() { time_ = std::chrono::high_resolution_clock::now(); }
|
||||
|
||||
void Reset();
|
||||
|
||||
void Update();
|
||||
|
||||
static void Sleep(float duration);
|
||||
|
||||
float GetSecondsPassed() const { return seconds_passed_; }
|
||||
float GetSecondsAccumulated() const { return seconds_accumulated_; }
|
||||
// Return seconds passed since creating the object.
|
||||
double Elapsed() const {
|
||||
auto current_time = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> diff = current_time - time_;
|
||||
return diff.count();
|
||||
}
|
||||
|
||||
private:
|
||||
float seconds_passed_ = 0.0f;
|
||||
float seconds_accumulated_ = 0.0f;
|
||||
|
||||
timeval last_time_;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> time_;
|
||||
};
|
||||
|
||||
class DeltaTimer {
|
||||
public:
|
||||
DeltaTimer() { time_ = std::chrono::high_resolution_clock::now(); }
|
||||
|
||||
// Return seconds passed since the last call to this function.
|
||||
double Delta() {
|
||||
auto current_time = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> diff = current_time - time_;
|
||||
time_ = current_time;
|
||||
return diff.count();
|
||||
}
|
||||
|
||||
private:
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> time_;
|
||||
};
|
||||
|
||||
inline void Sleep(double seconds) {
|
||||
std::this_thread::sleep_for(
|
||||
std::chrono::duration<double, std::milli>(seconds * 1000));
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_TIMER_H
|
||||
|
|
|
@ -1247,8 +1247,8 @@ class Matrix4 {
|
|||
T fov_aspect,
|
||||
T width,
|
||||
T height,
|
||||
T near,
|
||||
T far) {
|
||||
T near_plane,
|
||||
T far_plane) {
|
||||
// Calc x and y scale from FOV.
|
||||
T scale =
|
||||
T(2.0) /
|
||||
|
@ -1257,8 +1257,8 @@ class Matrix4 {
|
|||
T x_scale = y_scale / (width / height);
|
||||
_M_SET_ROW(0, x_scale / T(2.0), 0, 0, 0);
|
||||
_M_SET_ROW(1, 0, (-y_scale) / T(2.0), 0, 0);
|
||||
_M_SET_ROW(2, 0, 0, far / (far - near), 1);
|
||||
_M_SET_ROW(3, 0, 0, -near * far / (far - near), 0);
|
||||
_M_SET_ROW(2, 0, 0, far_plane / (far_plane - near_plane), 1);
|
||||
_M_SET_ROW(3, 0, 0, -near_plane * far_plane / (far_plane - near_plane), 0);
|
||||
}
|
||||
|
||||
void CreateTranslation(const Vector3<T>& t) {
|
||||
|
@ -1343,7 +1343,7 @@ class Matrix4 {
|
|||
M_x_RotZ(angles[2]);
|
||||
break;
|
||||
default:
|
||||
NOTREACHED;
|
||||
NOTREACHED();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1534,7 +1534,7 @@ class Matrix4 {
|
|||
break;
|
||||
}
|
||||
default:
|
||||
NOTREACHED;
|
||||
NOTREACHED();
|
||||
}
|
||||
return -angles;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import("//build/rules.gni")
|
||||
|
||||
game("demo") {
|
||||
sources = [
|
||||
"credits.cc",
|
||||
"credits.h",
|
||||
"damage_type.h",
|
||||
"demo.cc",
|
||||
"demo.h",
|
||||
"enemy.cc",
|
||||
"enemy.h",
|
||||
"hud.cc",
|
||||
"hud.h",
|
||||
"menu.cc",
|
||||
"menu.h",
|
||||
"player.cc",
|
||||
"player.h",
|
||||
"sky_quad.cc",
|
||||
"sky_quad.h",
|
||||
]
|
||||
deps = [
|
||||
"//assets/demo",
|
||||
"//src/base",
|
||||
"//src/engine",
|
||||
]
|
||||
}
|
|
@ -3,9 +3,9 @@
|
|||
#include "base/log.h"
|
||||
#include "base/vecmath.h"
|
||||
#include "demo/demo.h"
|
||||
#include "engine/asset/font.h"
|
||||
#include "engine/asset/image.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/font.h"
|
||||
#include "engine/image.h"
|
||||
#include "engine/input_event.h"
|
||||
|
||||
using namespace base;
|
||||
|
|
135
src/demo/demo.cc
|
@ -13,11 +13,8 @@
|
|||
#include "engine/engine.h"
|
||||
#include "engine/game_factory.h"
|
||||
#include "engine/input_event.h"
|
||||
#include "engine/sound.h"
|
||||
|
||||
DECLARE_GAME_BEGIN
|
||||
DECLARE_GAME(Demo)
|
||||
DECLARE_GAME_END
|
||||
GAME_FACTORIES{GAME_CLASS(Demo)};
|
||||
|
||||
// #define RECORD 15
|
||||
// #define REPLAY
|
||||
|
@ -47,59 +44,73 @@ Demo::~Demo() {
|
|||
saved_data_.Save();
|
||||
}
|
||||
|
||||
bool Demo::PreInitialize() {
|
||||
if (!font_.Load("demo/PixelCaps!.ttf"))
|
||||
return false;
|
||||
|
||||
Engine::Get().SetShaderSource("sky_without_nebula",
|
||||
"demo/sky_without_nebula.glsl");
|
||||
Engine::Get().SetShaderSource("sky", "demo/sky.glsl");
|
||||
|
||||
Engine::Get().AsyncLoadSound("music", "demo/Game_2_Main.mp3", true);
|
||||
Engine::Get().AsyncLoadSound("boss_music", "demo/Game_2_Boss.mp3", true);
|
||||
|
||||
if (!enemy_.PreInitialize()) {
|
||||
LOG(0) << "Failed to create the enemy.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!player_.PreInitialize()) {
|
||||
LOG(0) << "Failed to create the enemy.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!menu_.PreInitialize()) {
|
||||
LOG(0) << "Failed to create the menu.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Demo::Initialize() {
|
||||
saved_data_.Load(kSaveFileName);
|
||||
|
||||
Engine::Get().LoadCustomShader("sky_without_nebula",
|
||||
"sky_without_nebula.glsl");
|
||||
Engine::Get().LoadCustomShader("sky", "sky.glsl");
|
||||
|
||||
if (!font_.Load("PixelCaps!.ttf"))
|
||||
return false;
|
||||
|
||||
if (!sky_.Create(false)) {
|
||||
LOG << "Could not create the sky.";
|
||||
LOG(0) << "Could not create the sky.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!enemy_.Initialize()) {
|
||||
LOG << "Failed to create the enemy.";
|
||||
LOG(0) << "Failed to create the enemy.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!player_.Initialize()) {
|
||||
LOG << "Failed to create the enemy.";
|
||||
LOG(0) << "Failed to create the enemy.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hud_.Initialize()) {
|
||||
LOG << "Failed to create the hud.";
|
||||
LOG(0) << "Failed to create the hud.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!menu_.Initialize()) {
|
||||
LOG << "Failed to create the menu.";
|
||||
LOG(0) << "Failed to create the menu.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!credits_.Initialize()) {
|
||||
LOG << "Failed to create the credits.";
|
||||
LOG(0) << "Failed to create the credits.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto sound = std::make_unique<Sound>();
|
||||
if (!sound->Load("Game_2_Main.mp3", true))
|
||||
return false;
|
||||
music_.SetSound("music");
|
||||
music_.SetMaxAmplitude(0.5f);
|
||||
|
||||
auto boss_sound = std::make_unique<Sound>();
|
||||
if (!boss_sound->Load("Game_2_Boss.mp3", true))
|
||||
return false;
|
||||
|
||||
music_.SetSound(std::move(sound));
|
||||
music_.SetMaxAplitude(0.5f);
|
||||
|
||||
boss_music_.SetSound(std::move(boss_sound));
|
||||
boss_music_.SetMaxAplitude(0.5f);
|
||||
boss_music_.SetSound("boss_music");
|
||||
boss_music_.SetMaxAmplitude(0.5f);
|
||||
|
||||
if (!saved_data_.root().get("audio", Json::Value(true)).asBool())
|
||||
Engine::Get().SetEnableAudio(false);
|
||||
|
@ -130,11 +141,11 @@ void Demo::Update(float delta_time) {
|
|||
|
||||
if (do_benchmark_) {
|
||||
benchmark_time_ += delta_time;
|
||||
if (benchmark_time_ > 1) {
|
||||
if (benchmark_time_ > 3) {
|
||||
avarage_fps_ += Engine::Get().fps();
|
||||
++num_benchmark_samples_;
|
||||
}
|
||||
if (benchmark_time_ > 6) {
|
||||
if (benchmark_time_ > 5) {
|
||||
avarage_fps_ /= num_benchmark_samples_;
|
||||
do_benchmark_ = false;
|
||||
BenchmarkResult(avarage_fps_);
|
||||
|
@ -166,14 +177,23 @@ void Demo::Update(float delta_time) {
|
|||
UpdateGameState(delta_time);
|
||||
}
|
||||
|
||||
void Demo::ContextLost() {
|
||||
if (do_benchmark_) {
|
||||
benchmark_time_ = 0;
|
||||
num_benchmark_samples_ = 0;
|
||||
avarage_fps_ = 0;
|
||||
}
|
||||
menu_.SetRendererType();
|
||||
}
|
||||
|
||||
void Demo::LostFocus() {}
|
||||
|
||||
void Demo::GainedFocus(bool from_interstitial_ad) {
|
||||
DLOG << __func__ << " from_interstitial_ad: " << from_interstitial_ad;
|
||||
DLOG(0) << __func__ << " from_interstitial_ad: " << from_interstitial_ad;
|
||||
if (!from_interstitial_ad) {
|
||||
if (saved_data_.root().get(kLaunchCount, Json::Value(0)).asInt() >
|
||||
kLaunchCountBeforeAd)
|
||||
Engine::Get().ShowInterstitialAd();
|
||||
// if (saved_data_.root().get(kLaunchCount, Json::Value(0)).asInt() >
|
||||
// kLaunchCountBeforeAd)
|
||||
// Engine::Get().ShowInterstitialAd();
|
||||
if (state_ == kGame)
|
||||
EnterMenuState();
|
||||
}
|
||||
|
@ -261,15 +281,15 @@ void Demo::EnterGameOverState() {
|
|||
hud_.ShowMessage("Game Over", 3);
|
||||
state_ = kGameOver;
|
||||
|
||||
if (boss_fight_) {
|
||||
music_.Resume(10);
|
||||
boss_music_.Stop(10);
|
||||
}
|
||||
|
||||
SetDelayedWork(1, [&]() -> void {
|
||||
enemy_.RemoveAll();
|
||||
// hud_.Hide();
|
||||
SetDelayedWork(3, [&]() -> void {
|
||||
if (saved_data_.root().get("music", Json::Value(true)).asBool()) {
|
||||
if (boss_fight_) {
|
||||
music_.Resume(10);
|
||||
boss_music_.Stop(10);
|
||||
}
|
||||
}
|
||||
wave_ = 0;
|
||||
boss_fight_ = false;
|
||||
EnterMenuState();
|
||||
|
@ -305,7 +325,7 @@ void Demo::UpdateMenuState(float delta_time) {
|
|||
Engine::Get().Exit();
|
||||
break;
|
||||
default:
|
||||
NOTREACHED << "- Unknown menu option: " << menu_.selected_option();
|
||||
NOTREACHED() << "- Unknown menu option: " << menu_.selected_option();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,21 +409,13 @@ void Demo::StartNextStage(bool boss) {
|
|||
waiting_for_next_wave_ = true;
|
||||
hud_.SetProgress(wave_ > 0 ? 0 : 1);
|
||||
|
||||
DLOG_IF(wave_ > 0 && stage_time_ > 0)
|
||||
DLOG_IF(0, wave_ > 0 && stage_time_ > 0)
|
||||
<< "wave: " << wave_ << " time: " << stage_time_ / 60.0f;
|
||||
stage_time_ = 0;
|
||||
|
||||
enemy_.PauseProgress();
|
||||
enemy_.StopAllEnemyUnits();
|
||||
|
||||
if (boss) {
|
||||
boss_music_.Play(true, 10);
|
||||
music_.Stop(10);
|
||||
} else if (boss_fight_) {
|
||||
music_.Resume(10);
|
||||
boss_music_.Stop(10);
|
||||
}
|
||||
|
||||
SetDelayedWork(1.25f, [&, boss]() -> void {
|
||||
enemy_.KillAllEnemyUnits();
|
||||
|
||||
|
@ -413,8 +425,12 @@ void Demo::StartNextStage(bool boss) {
|
|||
|
||||
hud_.HideProgress();
|
||||
|
||||
if (saved_data_.root().get("music", Json::Value(true)).asBool()) {
|
||||
boss_music_.Play(true, 10);
|
||||
music_.Stop(10);
|
||||
}
|
||||
boss_fight_ = true;
|
||||
DLOG << "Boss fight.";
|
||||
DLOG(0) << "Boss fight.";
|
||||
} else {
|
||||
size_t bonus_factor = [&]() -> size_t {
|
||||
if (wave_ <= 3)
|
||||
|
@ -426,8 +442,8 @@ void Demo::StartNextStage(bool boss) {
|
|||
return 100;
|
||||
}();
|
||||
size_t bonus_score = wave_score_ * (bonus_factor - 1);
|
||||
DLOG << "total_score_" << total_score_ << " wave " << wave_
|
||||
<< " score: " << wave_score_ << " bonus: " << bonus_score;
|
||||
DLOG(0) << "total_score_" << total_score_ << " wave " << wave_
|
||||
<< " score: " << wave_score_ << " bonus: " << bonus_score;
|
||||
|
||||
if (bonus_score > 0) {
|
||||
delta_score_ += bonus_score;
|
||||
|
@ -455,13 +471,18 @@ void Demo::StartNextStage(bool boss) {
|
|||
hud_.Show();
|
||||
hud_.SetProgress(1);
|
||||
|
||||
if (boss_fight_)
|
||||
if (boss_fight_) {
|
||||
player_.TakeDamage(-1);
|
||||
if (saved_data_.root().get("music", Json::Value(true)).asBool()) {
|
||||
music_.Resume(10);
|
||||
boss_music_.Stop(10);
|
||||
}
|
||||
}
|
||||
|
||||
total_enemies_ = 23.0897f * log((float)wave_ + 1.0f) - 10.0f;
|
||||
last_num_enemies_killed_ = 0;
|
||||
boss_fight_ = false;
|
||||
DLOG << "wave: " << wave_ << " total_enemies_: " << total_enemies_;
|
||||
DLOG(0) << "wave: " << wave_ << " total_enemies_: " << total_enemies_;
|
||||
}
|
||||
|
||||
hud_.SetScore(total_score_, true);
|
||||
|
@ -512,7 +533,7 @@ void Demo::SetDelayedWork(float seconds, base::Closure cb) {
|
|||
}
|
||||
|
||||
void Demo::BenchmarkResult(int avarage_fps) {
|
||||
LOG << __func__ << " avarage_fps: " << avarage_fps;
|
||||
LOG(0) << __func__ << " avarage_fps: " << avarage_fps;
|
||||
if (avarage_fps < 30)
|
||||
sky_.Create(true);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "base/closure.h"
|
||||
#include "engine/animator.h"
|
||||
#include "engine/font.h"
|
||||
#include "engine/asset/font.h"
|
||||
#include "engine/game.h"
|
||||
#include "engine/persistent_data.h"
|
||||
#include "engine/solid_quad.h"
|
||||
|
@ -23,14 +23,12 @@ class Demo final : public eng::Game {
|
|||
Demo();
|
||||
~Demo() final;
|
||||
|
||||
// Game interface
|
||||
bool PreInitialize() final;
|
||||
bool Initialize() final;
|
||||
|
||||
void Update(float delta_time) final;
|
||||
|
||||
void ContextLost() final {}
|
||||
|
||||
void ContextLost() final;
|
||||
void LostFocus() final;
|
||||
|
||||
void GainedFocus(bool from_interstitial_ad) final;
|
||||
|
||||
void AddScore(size_t score);
|
||||
|
|
|
@ -9,11 +9,10 @@
|
|||
#include "base/collusion_test.h"
|
||||
#include "base/interpolation.h"
|
||||
#include "base/log.h"
|
||||
#include "engine/asset/font.h"
|
||||
#include "engine/asset/image.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/font.h"
|
||||
#include "engine/image.h"
|
||||
#include "engine/renderer/geometry.h"
|
||||
#include "engine/sound.h"
|
||||
|
||||
#include "demo/demo.h"
|
||||
|
||||
|
@ -78,46 +77,50 @@ Enemy::Enemy() = default;
|
|||
|
||||
Enemy::~Enemy() = default;
|
||||
|
||||
bool Enemy::PreInitialize() {
|
||||
Engine::Get().SetImageSource("skull_tex", "demo/enemy_anims_01_frames_ok.png",
|
||||
true);
|
||||
Engine::Get().SetImageSource("bug_tex", "demo/enemy_anims_02_frames_ok.png",
|
||||
true);
|
||||
Engine::Get().SetImageSource("boss_tex1", "demo/Boss_ok.png", true);
|
||||
Engine::Get().SetImageSource("boss_tex2", "demo/Boss_ok_lvl2.png", true);
|
||||
Engine::Get().SetImageSource("boss_tex3", "demo/Boss_ok_lvl3.png", true);
|
||||
Engine::Get().SetImageSource("target_tex", "demo/enemy_target_single_ok.png",
|
||||
true);
|
||||
Engine::Get().SetImageSource("blast_tex", "demo/enemy_anims_blast_ok.png",
|
||||
true);
|
||||
Engine::Get().SetImageSource("shield_tex", "demo/woom_enemy_shield.png",
|
||||
true);
|
||||
Engine::Get().SetImageSource("crate_tex", "demo/nuke_pack_OK.png", true);
|
||||
|
||||
for (int i = 0; i < kEnemyType_Max; ++i) {
|
||||
if (i == kEnemyType_PowerUp)
|
||||
continue;
|
||||
Engine::Get().SetImageSource(
|
||||
"score_tex"s + std::to_string(i),
|
||||
std::bind(&Enemy::GetScoreImage, this, (EnemyType)i), true);
|
||||
}
|
||||
|
||||
Engine::Get().SetShaderSource("chromatic_aberration",
|
||||
"demo/chromatic_aberration.glsl");
|
||||
|
||||
Engine::Get().AsyncLoadSound("boss_intro", "demo/boss_intro.mp3");
|
||||
Engine::Get().AsyncLoadSound("boss_explosion", "demo/boss_explosion.mp3");
|
||||
Engine::Get().AsyncLoadSound("explosion", "demo/explosion.mp3");
|
||||
Engine::Get().AsyncLoadSound("stealth", "demo/stealth.mp3");
|
||||
Engine::Get().AsyncLoadSound("shield", "demo/shield.mp3");
|
||||
Engine::Get().AsyncLoadSound("hit", "demo/hit.mp3");
|
||||
Engine::Get().AsyncLoadSound("powerup-spawn", "demo/powerup-spawn.mp3");
|
||||
Engine::Get().AsyncLoadSound("powerup-pick", "demo/powerup-pick.mp3");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Enemy::Initialize() {
|
||||
boss_intro_sound_ = std::make_shared<Sound>();
|
||||
if (!boss_intro_sound_->Load("boss_intro.mp3", false))
|
||||
return false;
|
||||
|
||||
boss_explosion_sound_ = std::make_shared<Sound>();
|
||||
if (!boss_explosion_sound_->Load("boss_explosion.mp3", false))
|
||||
return false;
|
||||
|
||||
explosion_sound_ = std::make_shared<Sound>();
|
||||
if (!explosion_sound_->Load("explosion.mp3", false))
|
||||
return false;
|
||||
|
||||
stealth_sound_ = std::make_shared<Sound>();
|
||||
if (!stealth_sound_->Load("stealth.mp3", false))
|
||||
return false;
|
||||
|
||||
shield_on_sound_ = std::make_shared<Sound>();
|
||||
if (!shield_on_sound_->Load("shield.mp3", false))
|
||||
return false;
|
||||
|
||||
hit_sound_ = std::make_shared<Sound>();
|
||||
if (!hit_sound_->Load("hit.mp3", false))
|
||||
return false;
|
||||
|
||||
power_up_spawn_sound_ = std::make_shared<Sound>();
|
||||
if (!power_up_spawn_sound_->Load("powerup-spawn.mp3", false))
|
||||
return false;
|
||||
|
||||
power_up_pick_sound_ = std::make_shared<Sound>();
|
||||
if (!power_up_pick_sound_->Load("powerup-pick.mp3", false))
|
||||
return false;
|
||||
|
||||
if (!CreateRenderResources())
|
||||
return false;
|
||||
|
||||
boss_.SetZOrder(10);
|
||||
boss_animator_.Attach(&boss_);
|
||||
|
||||
boss_intro_.SetSound(boss_intro_sound_);
|
||||
boss_intro_.SetSound("boss_intro");
|
||||
boss_intro_.SetVariate(false);
|
||||
boss_intro_.SetSimulateStereo(false);
|
||||
|
||||
|
@ -350,8 +353,8 @@ void Enemy::HitTarget(DamageType damage_type) {
|
|||
|
||||
if (target->damage_type != kDamageType_Any &&
|
||||
target->damage_type != damage_type) {
|
||||
// No shield until wave 4.
|
||||
if (wave_ <= 3)
|
||||
// No shield until wave 8.
|
||||
if (wave_ <= 8)
|
||||
return;
|
||||
|
||||
if (!target->shield_active) {
|
||||
|
@ -513,7 +516,7 @@ void Enemy::OnWaveStarted(int wave, bool boss_fight) {
|
|||
return 1.0f;
|
||||
return 1.6f;
|
||||
}();
|
||||
DLOG << "boss_spawn_time_factor_: " << boss_spawn_time_factor_;
|
||||
DLOG(0) << "boss_spawn_time_factor_: " << boss_spawn_time_factor_;
|
||||
SpawnBoss();
|
||||
}
|
||||
}
|
||||
|
@ -604,7 +607,7 @@ void Enemy::SpawnUnit(EnemyType enemy_type,
|
|||
e.sprite.Create("crate_tex", {8, 3});
|
||||
break;
|
||||
default:
|
||||
NOTREACHED << "- Unkown enemy type: " << enemy_type;
|
||||
NOTREACHED() << "- Unkown enemy type: " << enemy_type;
|
||||
}
|
||||
|
||||
e.sprite.SetZOrder(11);
|
||||
|
@ -650,11 +653,13 @@ void Enemy::SpawnUnit(EnemyType enemy_type,
|
|||
e.health_bar.PlaceToBottomOf(e.sprite);
|
||||
e.health_bar.SetColor({0.161f, 0.89f, 0.322f, 1});
|
||||
|
||||
e.score.Create("score_tex"s + std::to_string(e.enemy_type));
|
||||
e.score.SetZOrder(12);
|
||||
e.score.Scale(1.1f);
|
||||
e.score.SetColor({1, 1, 1, 1});
|
||||
e.score.SetPosition(spawn_pos);
|
||||
if (enemy_type != kEnemyType_PowerUp) {
|
||||
e.score.Create("score_tex"s + std::to_string(e.enemy_type));
|
||||
e.score.SetZOrder(12);
|
||||
e.score.Scale(1.1f);
|
||||
e.score.SetColor({1, 1, 1, 1});
|
||||
e.score.SetPosition(spawn_pos);
|
||||
}
|
||||
|
||||
e.target_animator.Attach(&e.target);
|
||||
|
||||
|
@ -729,32 +734,32 @@ void Enemy::SpawnUnit(EnemyType enemy_type,
|
|||
e.movement_animator.Play(Animator::kMovement, false);
|
||||
|
||||
if (e.enemy_type == kEnemyType_PowerUp) {
|
||||
e.explosion.SetSound(power_up_pick_sound_);
|
||||
e.explosion.SetSound("powerup-pick");
|
||||
|
||||
e.spawn.SetSound(power_up_spawn_sound_);
|
||||
e.spawn.SetMaxAplitude(2.0f);
|
||||
e.spawn.SetSound("powerup-spawn");
|
||||
e.spawn.SetMaxAmplitude(2.0f);
|
||||
e.spawn.Play(false);
|
||||
} else {
|
||||
e.explosion.SetSound(explosion_sound_);
|
||||
e.explosion.SetSound("explosion");
|
||||
e.explosion.SetVariate(true);
|
||||
e.explosion.SetSimulateStereo(true);
|
||||
e.explosion.SetMaxAplitude(0.9f);
|
||||
e.explosion.SetMaxAmplitude(0.9f);
|
||||
}
|
||||
|
||||
e.stealth.SetSound(stealth_sound_);
|
||||
e.stealth.SetSound("stealth");
|
||||
e.stealth.SetVariate(false);
|
||||
e.stealth.SetSimulateStereo(false);
|
||||
e.stealth.SetMaxAplitude(0.7f);
|
||||
e.stealth.SetMaxAmplitude(0.7f);
|
||||
|
||||
e.shield_on.SetSound(shield_on_sound_);
|
||||
e.shield_on.SetSound("shield");
|
||||
e.shield_on.SetVariate(false);
|
||||
e.shield_on.SetSimulateStereo(false);
|
||||
e.shield_on.SetMaxAplitude(0.5f);
|
||||
e.shield_on.SetMaxAmplitude(0.5f);
|
||||
|
||||
e.hit.SetSound(hit_sound_);
|
||||
e.hit.SetSound("hit");
|
||||
e.hit.SetVariate(true);
|
||||
e.hit.SetSimulateStereo(false);
|
||||
e.hit.SetMaxAplitude(0.5f);
|
||||
e.hit.SetMaxAmplitude(0.5f);
|
||||
}
|
||||
|
||||
void Enemy::SpawnBoss() {
|
||||
|
@ -781,7 +786,7 @@ void Enemy::SpawnBoss() {
|
|||
e.enemy_type = kEnemyType_Boss;
|
||||
e.damage_type = kDamageType_Any;
|
||||
e.total_health = e.hit_points = 41.1283f * log((float)game->wave()) - 20.0f;
|
||||
DLOG << " Boss health: " << e.total_health;
|
||||
DLOG(0) << " Boss health: " << e.total_health;
|
||||
|
||||
Vector2f hit_box_pos =
|
||||
boss_.GetPosition() - boss_.GetSize() * Vector2f(0, 0.2f);
|
||||
|
@ -825,14 +830,14 @@ void Enemy::SpawnBoss() {
|
|||
Animator::kMovement, [&]() -> void { e.marked_for_removal = true; });
|
||||
e.score_animator.Attach(&e.score);
|
||||
|
||||
e.explosion.SetSound(boss_explosion_sound_);
|
||||
e.explosion.SetSound("boss_explosion");
|
||||
e.explosion.SetVariate(false);
|
||||
e.explosion.SetSimulateStereo(false);
|
||||
|
||||
e.hit.SetSound(hit_sound_);
|
||||
e.hit.SetSound("hit");
|
||||
e.hit.SetVariate(true);
|
||||
e.hit.SetSimulateStereo(false);
|
||||
e.hit.SetMaxAplitude(0.5f);
|
||||
e.hit.SetMaxAmplitude(0.5f);
|
||||
});
|
||||
boss_animator_.Play(Animator::kFrames, true);
|
||||
boss_animator_.Play(Animator::kMovement, false);
|
||||
|
@ -1167,11 +1172,7 @@ int Enemy::GetScore(EnemyType enemy_type) {
|
|||
std::unique_ptr<Image> Enemy::GetScoreImage(EnemyType enemy_type) {
|
||||
const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont();
|
||||
|
||||
int score = GetScore(enemy_type);
|
||||
if (!score)
|
||||
return nullptr;
|
||||
|
||||
std::string text = std::to_string(score);
|
||||
std::string text = std::to_string(GetScore(enemy_type));
|
||||
int width, height;
|
||||
font.CalculateBoundingBox(text.c_str(), width, height);
|
||||
|
||||
|
@ -1185,30 +1186,6 @@ std::unique_ptr<Image> Enemy::GetScoreImage(EnemyType enemy_type) {
|
|||
return image;
|
||||
}
|
||||
|
||||
bool Enemy::CreateRenderResources() {
|
||||
Engine::Get().SetImageSource("skull_tex", "enemy_anims_01_frames_ok.png",
|
||||
true);
|
||||
Engine::Get().SetImageSource("bug_tex", "enemy_anims_02_frames_ok.png", true);
|
||||
Engine::Get().SetImageSource("boss_tex1", "Boss_ok.png", true);
|
||||
Engine::Get().SetImageSource("boss_tex2", "Boss_ok_lvl2.png", true);
|
||||
Engine::Get().SetImageSource("boss_tex3", "Boss_ok_lvl3.png", true);
|
||||
Engine::Get().SetImageSource("target_tex", "enemy_target_single_ok.png",
|
||||
true);
|
||||
Engine::Get().SetImageSource("blast_tex", "enemy_anims_blast_ok.png", true);
|
||||
Engine::Get().SetImageSource("shield_tex", "woom_enemy_shield.png", true);
|
||||
Engine::Get().SetImageSource("crate_tex", "nuke_pack_OK.png", true);
|
||||
|
||||
for (int i = 0; i < kEnemyType_Max; ++i)
|
||||
Engine::Get().SetImageSource(
|
||||
"score_tex"s + std::to_string(i),
|
||||
std::bind(&Enemy::GetScoreImage, this, (EnemyType)i), true);
|
||||
|
||||
Engine::Get().LoadCustomShader("chromatic_aberration",
|
||||
"chromatic_aberration.glsl");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Enemy::TranslateEnemyUnit(EnemyUnit& e, const Vector2f& delta) {
|
||||
e.sprite.Translate(delta);
|
||||
e.target.Translate(delta);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
namespace eng {
|
||||
class Image;
|
||||
class Sound;
|
||||
} // namespace eng
|
||||
|
||||
class Enemy {
|
||||
|
@ -23,6 +22,7 @@ class Enemy {
|
|||
Enemy();
|
||||
~Enemy();
|
||||
|
||||
bool PreInitialize();
|
||||
bool Initialize();
|
||||
|
||||
void Update(float delta_time);
|
||||
|
@ -109,15 +109,6 @@ class Enemy {
|
|||
eng::Animator boss_animator_;
|
||||
eng::SoundPlayer boss_intro_;
|
||||
|
||||
std::shared_ptr<eng::Sound> boss_intro_sound_;
|
||||
std::shared_ptr<eng::Sound> boss_explosion_sound_;
|
||||
std::shared_ptr<eng::Sound> explosion_sound_;
|
||||
std::shared_ptr<eng::Sound> stealth_sound_;
|
||||
std::shared_ptr<eng::Sound> shield_on_sound_;
|
||||
std::shared_ptr<eng::Sound> hit_sound_;
|
||||
std::shared_ptr<eng::Sound> power_up_spawn_sound_;
|
||||
std::shared_ptr<eng::Sound> power_up_pick_sound_;
|
||||
|
||||
std::list<EnemyUnit> enemies_;
|
||||
|
||||
int num_enemies_killed_in_current_wave_ = 0;
|
||||
|
@ -164,8 +155,6 @@ class Enemy {
|
|||
|
||||
std::unique_ptr<eng::Image> GetScoreImage(EnemyType enemy_type);
|
||||
|
||||
bool CreateRenderResources();
|
||||
|
||||
void TranslateEnemyUnit(EnemyUnit& e, const base::Vector2f& delta);
|
||||
};
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#include "base/interpolation.h"
|
||||
#include "base/log.h"
|
||||
#include "base/vecmath.h"
|
||||
#include "engine/asset/font.h"
|
||||
#include "engine/asset/image.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/font.h"
|
||||
#include "engine/image.h"
|
||||
|
||||
#include "demo/demo.h"
|
||||
|
||||
|
@ -198,7 +198,6 @@ void Hud::ShowMessage(const std::string& text, float duration) {
|
|||
message_text_ = text;
|
||||
Engine::Get().RefreshImage("message");
|
||||
|
||||
message_.AutoScale();
|
||||
message_.Scale(1.5f);
|
||||
message_.SetColor({1, 1, 1, 0});
|
||||
message_.SetVisible(true);
|
||||
|
@ -215,7 +214,6 @@ void Hud::ShowMessage(const std::string& text, float duration) {
|
|||
void Hud::ShowBonus(size_t bonus) {
|
||||
bonus_score_ = bonus;
|
||||
Engine::Get().RefreshImage("bonus_tex");
|
||||
bonus_.AutoScale();
|
||||
bonus_.Scale(1.3f);
|
||||
bonus_.SetColor({1, 1, 1, 1});
|
||||
bonus_.SetVisible(true);
|
||||
|
@ -245,26 +243,20 @@ std::unique_ptr<Image> Hud::CreateMessageImage() {
|
|||
font.Print(x, 0, message_text_.c_str(), image->GetBuffer(),
|
||||
image->GetWidth());
|
||||
image->Compress();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
std::unique_ptr<Image> Hud::CreateBonusImage() {
|
||||
const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont();
|
||||
|
||||
if (bonus_score_ == 0)
|
||||
return nullptr;
|
||||
auto image = CreateImage();
|
||||
|
||||
std::string text = std::to_string(bonus_score_);
|
||||
int width, height;
|
||||
font.CalculateBoundingBox(text.c_str(), width, height);
|
||||
|
||||
auto image = std::make_unique<Image>();
|
||||
image->Create(width, height);
|
||||
image->Clear({1, 1, 1, 0});
|
||||
|
||||
font.Print(0, 0, text.c_str(), image->GetBuffer(), image->GetWidth());
|
||||
int w, h;
|
||||
font.CalculateBoundingBox(text.c_str(), w, h);
|
||||
float x = (image->GetWidth() - w) / 2;
|
||||
|
||||
font.Print(x, 0, text.c_str(), image->GetBuffer(), image->GetWidth());
|
||||
image->Compress();
|
||||
return image;
|
||||
}
|
||||
|
@ -282,7 +274,7 @@ std::unique_ptr<Image> Hud::Print(int i, const std::string& text) {
|
|||
}
|
||||
|
||||
font.Print(x, 0, text.c_str(), image->GetBuffer(), image->GetWidth());
|
||||
|
||||
image->Compress();
|
||||
return image;
|
||||
}
|
||||
|
||||
|
|
167
src/demo/menu.cc
|
@ -7,11 +7,12 @@
|
|||
#include "base/collusion_test.h"
|
||||
#include "base/interpolation.h"
|
||||
#include "base/log.h"
|
||||
#include "engine/asset/font.h"
|
||||
#include "engine/asset/image.h"
|
||||
#include "engine/asset/sound.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/font.h"
|
||||
#include "engine/image.h"
|
||||
#include "engine/input_event.h"
|
||||
#include "engine/sound.h"
|
||||
#include "engine/renderer/renderer.h"
|
||||
|
||||
#include "demo/demo.h"
|
||||
|
||||
|
@ -22,7 +23,7 @@ using namespace eng;
|
|||
|
||||
namespace {
|
||||
|
||||
constexpr char kVersionStr[] = "Version 1.0.2";
|
||||
constexpr char kVersionStr[] = "Version 1.0.4";
|
||||
|
||||
constexpr char kMenuOption[Menu::kOption_Max][10] = {"continue", "start",
|
||||
"credits", "exit"};
|
||||
|
@ -33,9 +34,10 @@ const Vector4f kColorNormal = {1, 1, 1, 1};
|
|||
const Vector4f kColorHighlight = {20, 20, 20, 1};
|
||||
constexpr float kBlendingSpeed = 0.12f;
|
||||
|
||||
const Vector4f kColorSwitch[2] = {{0.003f, 0.91f, 0.99f, 1},
|
||||
{0.33f, 0.47, 0.51f, 1}};
|
||||
const std::array<Vector4f, 2> kColorSwitch = {Vector4f{0.003f, 0.91f, 0.99f, 1},
|
||||
Vector4f{0.33f, 0.47, 0.51f, 1}};
|
||||
|
||||
const Vector4f kColorFadeIn = {1, 1, 1, 1};
|
||||
const Vector4f kColorFadeOut = {1, 1, 1, 0};
|
||||
constexpr float kFadeSpeed = 0.2f;
|
||||
|
||||
|
@ -51,9 +53,9 @@ Menu::Menu() = default;
|
|||
|
||||
Menu::~Menu() = default;
|
||||
|
||||
bool Menu::Initialize() {
|
||||
bool Menu::PreInitialize() {
|
||||
click_sound_ = std::make_shared<Sound>();
|
||||
if (!click_sound_->Load("menu_click.mp3", false))
|
||||
if (!click_sound_->Load("demo/menu_click.mp3", false))
|
||||
return false;
|
||||
|
||||
Demo* game = static_cast<Demo*>(Engine::Get().GetGame());
|
||||
|
@ -68,8 +70,59 @@ bool Menu::Initialize() {
|
|||
max_text_width_ = width;
|
||||
}
|
||||
|
||||
if (!CreateRenderResources())
|
||||
return false;
|
||||
Engine::Get().SetImageSource("menu_tex",
|
||||
std::bind(&Menu::CreateMenuImage, this), true);
|
||||
Engine::Get().SetImageSource("logo_tex0",
|
||||
"demo/woom_logo_start_frames_01.png", true);
|
||||
Engine::Get().SetImageSource("logo_tex1",
|
||||
"demo/woom_logo_start_frames_02-03.png", true);
|
||||
Engine::Get().SetImageSource("buttons_tex", "demo/menu_icons.png", true);
|
||||
Engine::Get().SetImageSource("renderer_logo", "demo/renderer_logo.png", true);
|
||||
|
||||
Engine::Get().SetImageSource(
|
||||
"version_tex",
|
||||
[]() -> std::unique_ptr<Image> {
|
||||
const Font* font = Engine::Get().GetSystemFont();
|
||||
|
||||
int w, h;
|
||||
font->CalculateBoundingBox(kVersionStr, w, h);
|
||||
|
||||
auto image = std::make_unique<Image>();
|
||||
image->Create(w, font->GetLineHeight());
|
||||
image->Clear({1, 1, 1, 0});
|
||||
|
||||
font->Print(0, 0, kVersionStr, image->GetBuffer(), image->GetWidth());
|
||||
|
||||
image->Compress();
|
||||
return image;
|
||||
},
|
||||
true);
|
||||
|
||||
Engine::Get().SetImageSource("high_score_tex",
|
||||
std::bind(&Menu::CreateHighScoreImage, this));
|
||||
Engine::Get().SetImageSource("wave_up_tex", []() -> std::unique_ptr<Image> {
|
||||
const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont();
|
||||
|
||||
constexpr char btn_text[] = "[ ]";
|
||||
|
||||
int w, h;
|
||||
font.CalculateBoundingBox(btn_text, w, h);
|
||||
|
||||
auto image = std::make_unique<Image>();
|
||||
image->Create(w, h);
|
||||
image->Clear({1, 1, 1, 0});
|
||||
|
||||
font.Print(0, 0, btn_text, image->GetBuffer(), image->GetWidth());
|
||||
|
||||
image->Compress();
|
||||
return image;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Menu::Initialize() {
|
||||
Demo* game = static_cast<Demo*>(Engine::Get().GetGame());
|
||||
|
||||
for (int i = 0; i < kOption_Max; ++i) {
|
||||
items_[i].text.Create("menu_tex", {1, 4});
|
||||
|
@ -96,7 +149,7 @@ bool Menu::Initialize() {
|
|||
click_.SetSound(click_sound_);
|
||||
click_.SetVariate(false);
|
||||
click_.SetSimulateStereo(false);
|
||||
click_.SetMaxAplitude(1.5f);
|
||||
click_.SetMaxAmplitude(1.5f);
|
||||
|
||||
logo_[0].Create("logo_tex0", {3, 8});
|
||||
logo_[0].SetZOrder(41);
|
||||
|
@ -150,7 +203,8 @@ bool Menu::Initialize() {
|
|||
}
|
||||
game->saved_data().root()["audio"] = toggle_audio_.enabled();
|
||||
},
|
||||
true, game->saved_data().root().get("audio", Json::Value(true)).asBool());
|
||||
true, game->saved_data().root().get("audio", Json::Value(true)).asBool(),
|
||||
kColorFadeOut, kColorSwitch);
|
||||
toggle_audio_.image().SetPosition(Engine::Get().GetScreenSize() *
|
||||
Vector2f(0, -0.25f));
|
||||
toggle_audio_.image().Scale(0.7f);
|
||||
|
@ -162,7 +216,8 @@ bool Menu::Initialize() {
|
|||
game->SetEnableMusic(toggle_music_.enabled());
|
||||
game->saved_data().root()["music"] = toggle_music_.enabled();
|
||||
},
|
||||
true, game->saved_data().root().get("music", Json::Value(true)).asBool());
|
||||
true, game->saved_data().root().get("music", Json::Value(true)).asBool(),
|
||||
kColorFadeOut, kColorSwitch);
|
||||
toggle_music_.image().SetPosition(Engine::Get().GetScreenSize() *
|
||||
Vector2f(0, -0.25f));
|
||||
toggle_music_.image().Scale(0.7f);
|
||||
|
@ -177,7 +232,8 @@ bool Menu::Initialize() {
|
|||
game->saved_data().root()["vibration"] = toggle_vibration_.enabled();
|
||||
},
|
||||
true,
|
||||
game->saved_data().root().get("vibration", Json::Value(true)).asBool());
|
||||
game->saved_data().root().get("vibration", Json::Value(true)).asBool(),
|
||||
kColorFadeOut, kColorSwitch);
|
||||
toggle_vibration_.image().SetPosition(Engine::Get().GetScreenSize() *
|
||||
Vector2f(0, -0.25f));
|
||||
toggle_vibration_.image().Scale(0.7f);
|
||||
|
@ -188,6 +244,19 @@ bool Menu::Initialize() {
|
|||
toggle_vibration_.image().Translate(
|
||||
{toggle_music_.image().GetSize().x / 2, 0});
|
||||
|
||||
renderer_type_.Create(
|
||||
"renderer_logo", {2, 1}, 0, 1,
|
||||
[&] {
|
||||
Engine::Get().CreateRenderer(renderer_type_.enabled()
|
||||
? RendererType::kVulkan
|
||||
: RendererType::kOpenGL);
|
||||
},
|
||||
true, Engine::Get().GetRendererType() == RendererType::kVulkan,
|
||||
kColorFadeOut, {Vector4f{1, 1, 1, 1}, Vector4f{1, 1, 1, 1}});
|
||||
renderer_type_.image().PlaceToBottomOf(toggle_music_.image());
|
||||
renderer_type_.image().Translate(toggle_music_.image().GetPosition() *
|
||||
Vector2f(0, 1.1f));
|
||||
|
||||
high_score_value_ = game->GetHighScore();
|
||||
|
||||
high_score_.Create("high_score_tex");
|
||||
|
@ -226,7 +295,7 @@ bool Menu::Initialize() {
|
|||
starting_wave_.image().SetFrame(start_from_wave_ / 3);
|
||||
click_.Play(false);
|
||||
},
|
||||
false, true);
|
||||
false, true, kColorFadeOut, kColorSwitch);
|
||||
wave_up_.image().Scale(1.5f);
|
||||
|
||||
return true;
|
||||
|
@ -236,6 +305,7 @@ void Menu::OnInputEvent(std::unique_ptr<InputEvent> event) {
|
|||
if (toggle_audio_.OnInputEvent(event.get()) ||
|
||||
toggle_music_.OnInputEvent(event.get()) ||
|
||||
toggle_vibration_.OnInputEvent(event.get()) ||
|
||||
renderer_type_.OnInputEvent(event.get()) ||
|
||||
(wave_up_.image().IsVisible() && wave_up_.OnInputEvent(event.get())))
|
||||
return;
|
||||
|
||||
|
@ -299,6 +369,11 @@ void Menu::SetOptionEnabled(Option o, bool enable) {
|
|||
}
|
||||
}
|
||||
|
||||
void Menu::SetRendererType() {
|
||||
renderer_type_.SetEnabled(
|
||||
(Engine::Get().GetRendererType() == RendererType::kVulkan));
|
||||
}
|
||||
|
||||
void Menu::Show() {
|
||||
logo_[1].SetColor(kColorNormal);
|
||||
logo_animator_[0].SetVisible(true);
|
||||
|
@ -350,6 +425,7 @@ void Menu::Show() {
|
|||
toggle_audio_.Show();
|
||||
toggle_music_.Show();
|
||||
toggle_vibration_.Show();
|
||||
renderer_type_.Show();
|
||||
|
||||
Demo* game = static_cast<Demo*>(Engine::Get().GetGame());
|
||||
|
||||
|
@ -410,6 +486,7 @@ void Menu::Hide(Closure cb) {
|
|||
toggle_audio_.Hide();
|
||||
toggle_music_.Hide();
|
||||
toggle_vibration_.Hide();
|
||||
renderer_type_.Hide();
|
||||
|
||||
if (starting_wave_.image().IsVisible()) {
|
||||
starting_wave_.Hide();
|
||||
|
@ -417,52 +494,6 @@ void Menu::Hide(Closure cb) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Menu::CreateRenderResources() {
|
||||
Engine::Get().SetImageSource("menu_tex",
|
||||
std::bind(&Menu::CreateMenuImage, this));
|
||||
Engine::Get().SetImageSource("logo_tex0", "woom_logo_start_frames_01.png");
|
||||
Engine::Get().SetImageSource("logo_tex1", "woom_logo_start_frames_02-03.png");
|
||||
Engine::Get().SetImageSource("buttons_tex", "menu_icons.png");
|
||||
Engine::Get().SetImageSource("high_score_tex",
|
||||
std::bind(&Menu::CreateHighScoreImage, this));
|
||||
|
||||
Engine::Get().SetImageSource("wave_up_tex", []() -> std::unique_ptr<Image> {
|
||||
const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont();
|
||||
|
||||
constexpr char btn_text[] = "[ ]";
|
||||
|
||||
int w, h;
|
||||
font.CalculateBoundingBox(btn_text, w, h);
|
||||
|
||||
auto image = std::make_unique<Image>();
|
||||
image->Create(w, h);
|
||||
image->Clear({1, 1, 1, 0});
|
||||
|
||||
font.Print(0, 0, btn_text, image->GetBuffer(), image->GetWidth());
|
||||
|
||||
image->Compress();
|
||||
return image;
|
||||
});
|
||||
|
||||
Engine::Get().SetImageSource("version_tex", []() -> std::unique_ptr<Image> {
|
||||
const Font* font = Engine::Get().GetSystemFont();
|
||||
|
||||
int w, h;
|
||||
font->CalculateBoundingBox(kVersionStr, w, h);
|
||||
|
||||
auto image = std::make_unique<Image>();
|
||||
image->Create(w, font->GetLineHeight());
|
||||
image->Clear({1, 1, 1, 0});
|
||||
|
||||
font->Print(0, 0, kVersionStr, image->GetBuffer(), image->GetWidth());
|
||||
|
||||
image->Compress();
|
||||
return image;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Image> Menu::CreateMenuImage() {
|
||||
const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont();
|
||||
|
||||
|
@ -520,16 +551,20 @@ void Menu::Button::Create(const std::string& asset_name,
|
|||
int frame2,
|
||||
Closure pressed_cb,
|
||||
bool switch_control,
|
||||
bool enabled) {
|
||||
bool enabled,
|
||||
const Vector4f& fade_out_color,
|
||||
const std::array<Vector4f, 2>& switch_color) {
|
||||
frame1_ = frame1;
|
||||
frame2_ = frame2;
|
||||
pressed_cb_ = std::move(pressed_cb);
|
||||
switch_control_ = switch_control;
|
||||
enabled_ = enabled;
|
||||
fade_out_color_ = fade_out_color;
|
||||
switch_color_ = switch_color;
|
||||
|
||||
image_.Create(asset_name, num_frames);
|
||||
image_.SetFrame(enabled ? frame1 : frame2);
|
||||
image_.SetColor(kColorFadeOut);
|
||||
image_.SetColor(fade_out_color_);
|
||||
image_.SetZOrder(41);
|
||||
image_.SetVisible(false);
|
||||
|
||||
|
@ -562,14 +597,14 @@ bool Menu::Button::OnInputEvent(eng::InputEvent* event) {
|
|||
|
||||
void Menu::Button::Show() {
|
||||
animator_.SetVisible(true);
|
||||
animator_.SetBlending(enabled_ ? kColorSwitch[0] : kColorSwitch[1],
|
||||
animator_.SetBlending(enabled_ ? switch_color_[0] : switch_color_[1],
|
||||
kBlendingSpeed);
|
||||
animator_.Play(Animator::kBlending, false);
|
||||
animator_.SetEndCallback(Animator::kBlending, nullptr);
|
||||
}
|
||||
|
||||
void Menu::Button::Hide() {
|
||||
animator_.SetBlending(kColorFadeOut, kBlendingSpeed);
|
||||
animator_.SetBlending(fade_out_color_, kBlendingSpeed);
|
||||
animator_.Play(Animator::kBlending, false);
|
||||
animator_.SetEndCallback(Animator::kBlending,
|
||||
[&]() -> void { animator_.SetVisible(false); });
|
||||
|
@ -579,7 +614,7 @@ void Menu::Button::SetEnabled(bool enable) {
|
|||
if (switch_control_) {
|
||||
enabled_ = enable;
|
||||
image_.SetFrame(enabled_ ? frame1_ : frame2_);
|
||||
image_.SetColor(enabled_ ? kColorSwitch[0] : kColorSwitch[1]);
|
||||
image_.SetColor(enabled_ ? switch_color_[0] : switch_color_[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,11 +30,13 @@ class Menu {
|
|||
Menu();
|
||||
~Menu();
|
||||
|
||||
bool PreInitialize();
|
||||
bool Initialize();
|
||||
|
||||
void OnInputEvent(std::unique_ptr<eng::InputEvent> event);
|
||||
|
||||
void SetOptionEnabled(Option o, bool enable);
|
||||
void SetRendererType();
|
||||
|
||||
void Show();
|
||||
void Hide(base::Closure cb = nullptr);
|
||||
|
@ -55,13 +57,17 @@ class Menu {
|
|||
int frame2,
|
||||
base::Closure pressed_cb,
|
||||
bool switch_control,
|
||||
bool enabled);
|
||||
bool enabled,
|
||||
const base::Vector4f& fade_out_color,
|
||||
const std::array<base::Vector4f, 2>& switch_color);
|
||||
|
||||
bool OnInputEvent(eng::InputEvent* event);
|
||||
|
||||
void Show();
|
||||
void Hide();
|
||||
|
||||
void SetEnabled(bool enable);
|
||||
|
||||
eng::ImageQuad& image() { return image_; };
|
||||
|
||||
bool enabled() const { return enabled_; }
|
||||
|
@ -77,7 +83,8 @@ class Menu {
|
|||
bool enabled_ = false;
|
||||
base::Vector2f tap_pos_[2] = {{0, 0}, {0, 0}};
|
||||
|
||||
void SetEnabled(bool enable);
|
||||
base::Vector4f fade_out_color_;
|
||||
std::array<base::Vector4f, 2> switch_color_;
|
||||
};
|
||||
|
||||
class Radio {
|
||||
|
@ -126,6 +133,7 @@ class Menu {
|
|||
Button toggle_audio_;
|
||||
Button toggle_music_;
|
||||
Button toggle_vibration_;
|
||||
Button renderer_type_;
|
||||
|
||||
size_t high_score_value_ = 0;
|
||||
|
||||
|
@ -139,9 +147,6 @@ class Menu {
|
|||
|
||||
Radio starting_wave_;
|
||||
Button wave_up_;
|
||||
Button wave_down_;
|
||||
|
||||
bool CreateRenderResources();
|
||||
|
||||
std::unique_ptr<eng::Image> CreateMenuImage();
|
||||
std::unique_ptr<eng::Image> CreateHighScoreImage();
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
#include "base/interpolation.h"
|
||||
#include "base/log.h"
|
||||
#include "base/vecmath.h"
|
||||
#include "engine/asset/font.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/font.h"
|
||||
#include "engine/input_event.h"
|
||||
#include "engine/sound.h"
|
||||
|
||||
#include "demo/demo.h"
|
||||
|
||||
|
@ -29,22 +29,21 @@ Player::Player() = default;
|
|||
|
||||
Player::~Player() = default;
|
||||
|
||||
bool Player::PreInitialize() {
|
||||
Engine::Get().SetImageSource("weapon_tex", "demo/enemy_anims_flare_ok.png",
|
||||
true);
|
||||
Engine::Get().SetImageSource("beam_tex", "demo/enemy_ray_ok.png", true);
|
||||
Engine::Get().SetImageSource("nuke_symbol_tex", "demo/nuke_frames.png", true);
|
||||
Engine::Get().SetImageSource("health_bead", "demo/bead.png", true);
|
||||
|
||||
Engine::Get().AsyncLoadSound("laser", "demo/laser.mp3");
|
||||
Engine::Get().AsyncLoadSound("nuke", "demo/nuke.mp3");
|
||||
Engine::Get().AsyncLoadSound("no_nuke", "demo/no_nuke.mp3");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Player::Initialize() {
|
||||
if (!CreateRenderResources())
|
||||
return false;
|
||||
|
||||
laser_shot_sound_ = std::make_shared<Sound>();
|
||||
if (!laser_shot_sound_->Load("laser.mp3", false))
|
||||
return false;
|
||||
|
||||
nuke_explosion_sound_ = std::make_shared<Sound>();
|
||||
if (!nuke_explosion_sound_->Load("nuke.mp3", false))
|
||||
return false;
|
||||
|
||||
no_nuke_sound_ = std::make_shared<Sound>();
|
||||
if (!no_nuke_sound_->Load("no_nuke.mp3", false))
|
||||
return false;
|
||||
|
||||
SetupWeapons();
|
||||
|
||||
Vector2f hb_pos = Engine::Get().GetScreenSize() / Vector2f(2, -2) +
|
||||
|
@ -75,12 +74,12 @@ bool Player::Initialize() {
|
|||
|
||||
nuke_symbol_animator_.Attach(&nuke_symbol_);
|
||||
|
||||
nuke_explosion_.SetSound(nuke_explosion_sound_);
|
||||
nuke_explosion_.SetSound("nuke");
|
||||
nuke_explosion_.SetVariate(false);
|
||||
nuke_explosion_.SetSimulateStereo(false);
|
||||
nuke_explosion_.SetMaxAplitude(0.8f);
|
||||
nuke_explosion_.SetMaxAmplitude(0.8f);
|
||||
|
||||
no_nuke_.SetSound(no_nuke_sound_);
|
||||
no_nuke_.SetSound("no_nuke");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -153,7 +152,7 @@ void Player::AddNuke(int n) {
|
|||
|
||||
if (!nuke_symbol_animator_.IsPlaying(Animator::kRotation)) {
|
||||
nuke_symbol_animator_.SetRotation(
|
||||
M_PI * 5, 2, std::bind(SmootherStep, std::placeholders::_1));
|
||||
PIf * 5, 2, std::bind(SmootherStep, std::placeholders::_1));
|
||||
nuke_symbol_animator_.Play(Animator::kRotation, false);
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +222,7 @@ void Player::Fire(DamageType type, Vector2f dir) {
|
|||
|
||||
dir.Normalize();
|
||||
float cos_theta = dir.DotProduct(Vector2f(1, 0));
|
||||
float theta = acos(cos_theta) + M_PI;
|
||||
float theta = acos(cos_theta) + PIf;
|
||||
beam_[type].SetTheta(theta);
|
||||
auto offset = beam_[type].GetRotation() * (len / 2);
|
||||
beam_[type].Translate({offset.y, -offset.x});
|
||||
|
@ -288,7 +287,7 @@ void Player::SetupWeapons() {
|
|||
|
||||
weapon_[i].SetFrame(wepon_warmup_frame[i]);
|
||||
warmup_animator_[i].SetFrames(wepon_warmup_frame_count, wepon_anim_speed);
|
||||
warmup_animator_[i].SetRotation(M_PI * 2, 20.0f);
|
||||
warmup_animator_[i].SetRotation(PIf * 2, 20.0f);
|
||||
warmup_animator_[i].Attach(&weapon_[i]);
|
||||
warmup_animator_[i].Play(Animator::kRotation, true);
|
||||
|
||||
|
@ -306,10 +305,10 @@ void Player::SetupWeapons() {
|
|||
beam_animator_[i].SetBlending({1, 1, 1, 0}, 0.16f);
|
||||
beam_animator_[i].Attach(&beam_[i]);
|
||||
|
||||
laser_shot_[i].SetSound(laser_shot_sound_);
|
||||
laser_shot_[i].SetSound("laser");
|
||||
laser_shot_[i].SetVariate(true);
|
||||
laser_shot_[i].SetSimulateStereo(false);
|
||||
laser_shot_[i].SetMaxAplitude(0.4f);
|
||||
laser_shot_[i].SetMaxAmplitude(0.4f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -485,12 +484,3 @@ void Player::NavigateBack() {
|
|||
Engine& engine = Engine::Get();
|
||||
static_cast<Demo*>(engine.GetGame())->EnterMenuState();
|
||||
}
|
||||
|
||||
bool Player::CreateRenderResources() {
|
||||
Engine::Get().SetImageSource("weapon_tex", "enemy_anims_flare_ok.png", true);
|
||||
Engine::Get().SetImageSource("beam_tex", "enemy_ray_ok.png", true);
|
||||
Engine::Get().SetImageSource("nuke_symbol_tex", "nuke_frames.png", true);
|
||||
Engine::Get().SetImageSource("health_bead", "bead.png", true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
namespace eng {
|
||||
class InputEvent;
|
||||
class Sound;
|
||||
} // namespace eng
|
||||
|
||||
class Player {
|
||||
|
@ -21,6 +20,7 @@ class Player {
|
|||
Player();
|
||||
~Player();
|
||||
|
||||
bool PreInitialize();
|
||||
bool Initialize();
|
||||
|
||||
void Update(float delta_time);
|
||||
|
@ -41,10 +41,6 @@ class Player {
|
|||
int nuke_count() { return nuke_count_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<eng::Sound> nuke_explosion_sound_;
|
||||
std::shared_ptr<eng::Sound> no_nuke_sound_;
|
||||
std::shared_ptr<eng::Sound> laser_shot_sound_;
|
||||
|
||||
eng::ImageQuad drag_sign_[2];
|
||||
eng::ImageQuad weapon_[2];
|
||||
eng::ImageQuad beam_[2];
|
||||
|
@ -101,8 +97,6 @@ class Player {
|
|||
bool ValidateDrag(int i);
|
||||
|
||||
void NavigateBack();
|
||||
|
||||
bool CreateRenderResources();
|
||||
};
|
||||
|
||||
#endif // DEMO_PLAYER_H
|
||||
|
|
|
@ -21,8 +21,8 @@ SkyQuad::~SkyQuad() = default;
|
|||
bool SkyQuad::Create(bool without_nebula) {
|
||||
without_nebula_ = without_nebula;
|
||||
scale_ = Engine::Get().GetScreenSize();
|
||||
shader_ = Engine::Get().GetCustomShader(
|
||||
without_nebula ? "sky_without_nebula" : "sky");
|
||||
shader_ =
|
||||
Engine::Get().GetShader(without_nebula ? "sky_without_nebula" : "sky");
|
||||
|
||||
color_animator_.Attach(this);
|
||||
|
||||
|
|
|
@ -5,11 +5,6 @@
|
|||
#include "engine/animatable.h"
|
||||
#include "engine/animator.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace eng {
|
||||
class Shader;
|
||||
} // namespace eng
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
source_set("engine") {
|
||||
sources = [
|
||||
"animatable.cc",
|
||||
"animatable.h",
|
||||
"animator.cc",
|
||||
"animator.h",
|
||||
"asset/font.cc",
|
||||
"asset/font.h",
|
||||
"asset/image.cc",
|
||||
"asset/image.h",
|
||||
"asset/mesh.cc",
|
||||
"asset/mesh.h",
|
||||
"asset/shader_source.cc",
|
||||
"asset/shader_source.h",
|
||||
"asset/sound.cc",
|
||||
"asset/sound.h",
|
||||
"drawable.cc",
|
||||
"drawable.h",
|
||||
"engine.cc",
|
||||
"engine.h",
|
||||
"game.h",
|
||||
"game_factory.h",
|
||||
"image_quad.cc",
|
||||
"image_quad.h",
|
||||
"imgui_backend.cc",
|
||||
"imgui_backend.h",
|
||||
"input_event.h",
|
||||
"persistent_data.cc",
|
||||
"persistent_data.h",
|
||||
"solid_quad.cc",
|
||||
"solid_quad.h",
|
||||
"sound_player.cc",
|
||||
"sound_player.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//assets/engine",
|
||||
"//src/base",
|
||||
"//src/engine/audio",
|
||||
"//src/engine/platform",
|
||||
"//src/engine/renderer",
|
||||
"//src/third_party/imgui",
|
||||
"//src/third_party/jsoncpp",
|
||||
"//src/third_party/minimp3",
|
||||
"//src/third_party/stb",
|
||||
"//src/third_party/texture_compressor",
|
||||
]
|
||||
}
|
|
@ -51,7 +51,7 @@ class Animatable : public Drawable {
|
|||
|
||||
protected:
|
||||
base::Vector2f position_ = {0, 0};
|
||||
base::Vector2f size_ = {1, 1};
|
||||
base::Vector2f size_ = {0, 0};
|
||||
base::Vector2f scale_ = {1, 1};
|
||||
base::Vector2f rotation_ = {0, 1};
|
||||
float theta_ = 0;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "engine/font.h"
|
||||
#include "engine/asset/font.h"
|
||||
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
|
@ -8,7 +8,8 @@
|
|||
#include "engine/platform/asset_file.h"
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "../third_party/stb/stb_truetype.h"
|
||||
#define STBTT_STATIC
|
||||
#include "third_party/stb/stb_truetype.h"
|
||||
|
||||
namespace eng {
|
||||
|
||||
|
@ -18,7 +19,7 @@ bool Font::Load(const std::string& file_name) {
|
|||
auto buffer = AssetFile::ReadWholeFile(
|
||||
file_name.c_str(), Engine::Get().GetRootPath().c_str(), &buffer_size);
|
||||
if (!buffer) {
|
||||
LOG << "Failed to read font file.";
|
||||
LOG(0) << "Failed to read font file.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -28,7 +29,7 @@ bool Font::Load(const std::string& file_name) {
|
|||
// It's tighly packed.
|
||||
glyph_cache_ = std::make_unique<uint8_t[]>(kGlyphSize * kGlyphSize);
|
||||
if (!glyph_cache_) {
|
||||
LOG << "Failed to allocate glyph cache.";
|
||||
LOG(0) << "Failed to allocate glyph cache.";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -37,7 +38,7 @@ bool Font::Load(const std::string& file_name) {
|
|||
if (stbtt_BakeFontBitmap((unsigned char*)buffer.get(), 0, kFontHeight,
|
||||
glyph_cache_.get(), kGlyphSize, kGlyphSize,
|
||||
kFirstChar, kNumChars, glyph_info_) <= 0) {
|
||||
LOG << "Failed to bake the glyph cache: ";
|
||||
LOG(0) << "Failed to bake the glyph cache: ";
|
||||
glyph_cache_.reset();
|
||||
break;
|
||||
}
|
||||
|
@ -67,10 +68,10 @@ static void StretchBlit_I8_to_RGBA32(int dst_x0,
|
|||
int dst_pitch,
|
||||
const uint8_t* src_i,
|
||||
int src_pitch) {
|
||||
// LOG << "-- StretchBlit: --";
|
||||
// LOG << "dst: rect(" << dst_x0 << ", " << dst_y0 << ")..("
|
||||
// LOG(0) << "-- StretchBlit: --";
|
||||
// LOG(0) << "dst: rect(" << dst_x0 << ", " << dst_y0 << ")..("
|
||||
// << dst_x1 << ".." << dst_y1 << "), pitch(" << dst_pitch << ")";
|
||||
// LOG << "src: rect(" << src_x0 << ", " << src_y0 << ")..("
|
||||
// LOG(0) << "src: rect(" << src_x0 << ", " << src_y0 << ")..("
|
||||
// << src_x1 << ".." << src_y1 << "), pitch(" << src_pitch << ")";
|
||||
|
||||
int dst_width = dst_x1 - dst_x0, dst_height = dst_y1 - dst_y0,
|
||||
|
@ -79,8 +80,8 @@ static void StretchBlit_I8_to_RGBA32(int dst_x0,
|
|||
// int dst_dx = dst_width > 0 ? 1 : -1,
|
||||
// dst_dy = dst_height > 0 ? 1 : -1;
|
||||
|
||||
// LOG << "dst_width = " << dst_width << ", dst_height = " << dst_height;
|
||||
// LOG << "src_width = " << src_width << ", src_height = " << src_height;
|
||||
// LOG(0) << "dst_width = " << dst_width << ", dst_height = " << dst_height;
|
||||
// LOG(0) << "src_width = " << src_width << ", src_height = " << src_height;
|
||||
|
||||
uint8_t* dst = dst_rgba + (dst_x0 + dst_y0 * dst_pitch) * 4;
|
||||
const uint8_t* src = src_i + (src_x0 + src_y0 * src_pitch) * 1;
|
||||
|
@ -158,7 +159,7 @@ void Font::CalculateBoundingBox(const std::string& text,
|
|||
CalculateBoundingBox(text, x0, y0, x1, y1);
|
||||
width = x1 - x0;
|
||||
height = y1 - y0;
|
||||
// LOG << "width = " << width << ", height = " << height;
|
||||
// LOG(0) << "width = " << width << ", height = " << height;
|
||||
}
|
||||
|
||||
void Font::Print(int x,
|
||||
|
@ -166,7 +167,7 @@ void Font::Print(int x,
|
|||
const std::string& text,
|
||||
uint8_t* buffer,
|
||||
int width) const {
|
||||
// LOG("Font::Print() = %s\n", text);
|
||||
// LOG(0)("Font::Print() = %s\n", text);
|
||||
|
||||
if (!glyph_cache_)
|
||||
return;
|
||||
|
@ -183,7 +184,7 @@ void Font::Print(int x,
|
|||
stbtt_GetBakedQuad(glyph_info_, kGlyphSize, kGlyphSize, *ptr - kFirstChar,
|
||||
&fx, &fy, &q, 1);
|
||||
|
||||
// LOG("-- glyph --\nxy = (%f %f) .. (%f %f)\nuv = (%f %f) .. (%f %f)\n",
|
||||
// LOG(0)("-- glyph --\nxy = (%f %f) .. (%f %f)\nuv = (%f %f) .. (%f %f)\n",
|
||||
// q.x0, q.y0, q.x1, q.y1, q.s0, q.t0, q.s1, q.t1);
|
||||
|
||||
int ix0 = (int)q.x0, iy0 = (int)q.y0, ix1 = (int)q.x1, iy1 = (int)q.y1,
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef ENGINE_FONT_H
|
||||
#define ENGINE_FONT_H
|
||||
#ifndef ENGINE_ASSET_FONT_H
|
||||
#define ENGINE_ASSET_FONT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
@ -51,4 +51,4 @@ class Font {
|
|||
|
||||
} // namespace eng
|
||||
|
||||
#endif // ENGINE_FONT_H
|
||||
#endif // ENGINE_ASSET_FONT_H
|
|
@ -1,19 +1,19 @@
|
|||
#include "engine/image.h"
|
||||
#include "engine/asset/image.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include "base/interpolation.h"
|
||||
#include "base/log.h"
|
||||
#include "base/mem.h"
|
||||
#include "base/misc.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/platform/asset_file.h"
|
||||
#include "third_party/texture_compressor/texture_compressor.h"
|
||||
|
||||
// This 3rd party library is written in C and uses malloc, which means that we
|
||||
// have to do the same.
|
||||
// Use aligned memory for SIMD in texture compressor.
|
||||
#define STBI_NO_STDIO
|
||||
#include "../third_party/stb/stb_image.h"
|
||||
#include "third_party/stb/stb_image.h"
|
||||
|
||||
using namespace base;
|
||||
|
||||
|
@ -78,7 +78,7 @@ bool Image::Create(int w, int h) {
|
|||
width_ = w;
|
||||
height_ = h;
|
||||
|
||||
buffer_.reset((uint8_t*)AlignedAlloc<16>(w * h * 4 * sizeof(uint8_t)));
|
||||
buffer_.reset((uint8_t*)AlignedAlloc(w * h * 4 * sizeof(uint8_t), 16));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ bool Image::Create(int w, int h) {
|
|||
void Image::Copy(const Image& other) {
|
||||
if (other.buffer_) {
|
||||
int size = other.GetSize();
|
||||
buffer_.reset((uint8_t*)AlignedAlloc<16>(size));
|
||||
buffer_.reset((uint8_t*)AlignedAlloc(size, 16));
|
||||
memcpy(buffer_.get(), other.buffer_.get(), size);
|
||||
}
|
||||
width_ = other.width_;
|
||||
|
@ -95,14 +95,15 @@ void Image::Copy(const Image& other) {
|
|||
}
|
||||
|
||||
bool Image::CreateMip(const Image& other) {
|
||||
if (other.width_ <= 1 || other.height_ <= 1 || other.GetFormat() != kRGBA32)
|
||||
if (other.width_ <= 1 || other.height_ <= 1 ||
|
||||
other.GetFormat() != ImageFormat::kRGBA32)
|
||||
return false;
|
||||
|
||||
// Reduce the dimensions.
|
||||
width_ = std::max(other.width_ >> 1, 1);
|
||||
height_ = std::max(other.height_ >> 1, 1);
|
||||
format_ = kRGBA32;
|
||||
buffer_.reset((uint8_t*)AlignedAlloc<16>(GetSize()));
|
||||
format_ = ImageFormat::kRGBA32;
|
||||
buffer_.reset((uint8_t*)AlignedAlloc(GetSize(), 16));
|
||||
|
||||
// If the width isn't perfectly divisable with two, then we end up skewing
|
||||
// the image because the source offset isn't updated properly.
|
||||
|
@ -139,7 +140,7 @@ bool Image::Load(const std::string& file_name) {
|
|||
auto file_buffer = AssetFile::ReadWholeFile(
|
||||
file_name.c_str(), Engine::Get().GetRootPath().c_str(), &buffer_size);
|
||||
if (!file_buffer) {
|
||||
LOG << "Failed to read file: " << file_name;
|
||||
LOG(0) << "Failed to read file: " << file_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -147,19 +148,19 @@ bool Image::Load(const std::string& file_name) {
|
|||
buffer_.reset((uint8_t*)stbi_load_from_memory(
|
||||
(const stbi_uc*)file_buffer.get(), buffer_size, &w, &h, &c, 0));
|
||||
if (!buffer_) {
|
||||
LOG << "Failed to load image file: " << file_name;
|
||||
LOG(0) << "Failed to load image file: " << file_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG << "Loaded " << file_name << ". number of color components: " << c;
|
||||
LOG(0) << "Loaded " << file_name << ". number of color components: " << c;
|
||||
|
||||
uint8_t* converted_buffer = NULL;
|
||||
switch (c) {
|
||||
case 1:
|
||||
// LOG("Converting image from 1 to 4 channels.\n");
|
||||
// LOG(0)("Converting image from 1 to 4 channels.\n");
|
||||
// Assume it's an intensity, duplicate it to RGB and fill A with opaque.
|
||||
converted_buffer =
|
||||
(uint8_t*)AlignedAlloc<16>(w * h * 4 * sizeof(uint8_t));
|
||||
(uint8_t*)AlignedAlloc(w * h * 4 * sizeof(uint8_t), 16);
|
||||
for (int i = 0; i < w * h; ++i) {
|
||||
converted_buffer[i * 4 + 0] = buffer_[i];
|
||||
converted_buffer[i * 4 + 1] = buffer_[i];
|
||||
|
@ -169,10 +170,10 @@ bool Image::Load(const std::string& file_name) {
|
|||
break;
|
||||
|
||||
case 3:
|
||||
// LOG("Converting image from 3 to 4 channels.\n");
|
||||
// LOG(0)("Converting image from 3 to 4 channels.\n");
|
||||
// Add an opaque channel.
|
||||
converted_buffer =
|
||||
(uint8_t*)AlignedAlloc<16>(w * h * 4 * sizeof(uint8_t));
|
||||
(uint8_t*)AlignedAlloc(w * h * 4 * sizeof(uint8_t), 16);
|
||||
for (int i = 0; i < w * h; ++i) {
|
||||
converted_buffer[i * 4 + 0] = buffer_[i * 3 + 0];
|
||||
converted_buffer[i * 4 + 1] = buffer_[i * 3 + 1];
|
||||
|
@ -186,8 +187,8 @@ bool Image::Load(const std::string& file_name) {
|
|||
|
||||
case 2:
|
||||
default:
|
||||
LOG << "Image had unsuitable number of color components: " << c << " "
|
||||
<< file_name;
|
||||
LOG(0) << "Image had unsuitable number of color components: " << c << " "
|
||||
<< file_name;
|
||||
buffer_.reset();
|
||||
return false;
|
||||
}
|
||||
|
@ -214,32 +215,23 @@ bool Image::Load(const std::string& file_name) {
|
|||
return !!buffer_;
|
||||
}
|
||||
|
||||
bool Image::IsCompressed() const {
|
||||
return IsCompressedFormat(format_);
|
||||
}
|
||||
|
||||
size_t Image::GetSize() const {
|
||||
switch (format_) {
|
||||
case kRGBA32:
|
||||
return width_ * height_ * 4;
|
||||
case kDXT1:
|
||||
case kATC:
|
||||
return ((width_ + 3) / 4) * ((height_ + 3) / 4) * 8;
|
||||
case kDXT5:
|
||||
case kATCIA:
|
||||
return ((width_ + 3) / 4) * ((height_ + 3) / 4) * 16;
|
||||
case kETC1:
|
||||
return (width_ * height_ * 4) / 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return GetImageSize(width_, height_, format_);
|
||||
}
|
||||
|
||||
void Image::ConvertToPow2() {
|
||||
int new_width = RoundUpToPow2(width_);
|
||||
int new_height = RoundUpToPow2(height_);
|
||||
if ((new_width != width_) || (new_height != height_)) {
|
||||
LOG << "Converting image from (" << width_ << ", " << height_ << ") to ("
|
||||
<< new_width << ", " << new_height << ")";
|
||||
LOG(0) << "Converting image from (" << width_ << ", " << height_ << ") to ("
|
||||
<< new_width << ", " << new_height << ")";
|
||||
|
||||
int bigger_size = new_width * new_height * 4 * sizeof(uint8_t);
|
||||
uint8_t* bigger_buffer = (uint8_t*)AlignedAlloc<16>(bigger_size);
|
||||
uint8_t* bigger_buffer = (uint8_t*)AlignedAlloc(bigger_size, 16);
|
||||
|
||||
// Fill it with black.
|
||||
memset(bigger_buffer, 0, bigger_size);
|
||||
|
@ -275,29 +267,29 @@ bool Image::Compress() {
|
|||
|
||||
switch (tc->format()) {
|
||||
case TextureCompressor::kFormatATC:
|
||||
format_ = kATC;
|
||||
format_ = ImageFormat::kATC;
|
||||
break;
|
||||
case TextureCompressor::kFormatATCIA:
|
||||
format_ = kATCIA;
|
||||
format_ = ImageFormat::kATCIA;
|
||||
break;
|
||||
case TextureCompressor::kFormatDXT1:
|
||||
format_ = kDXT1;
|
||||
format_ = ImageFormat::kDXT1;
|
||||
break;
|
||||
case TextureCompressor::kFormatDXT5:
|
||||
format_ = kDXT5;
|
||||
format_ = ImageFormat::kDXT5;
|
||||
break;
|
||||
case TextureCompressor::kFormatETC1:
|
||||
format_ = kETC1;
|
||||
format_ = ImageFormat::kETC1;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG << "Compressing image. Format: " << format_;
|
||||
LOG(0) << "Compressing image. Format: " << ImageFormatToString(format_);
|
||||
|
||||
unsigned compressedSize = GetSize();
|
||||
uint8_t* compressedBuffer =
|
||||
(uint8_t*)AlignedAlloc<16>(compressedSize * sizeof(uint8_t));
|
||||
(uint8_t*)AlignedAlloc(compressedSize * sizeof(uint8_t), 16);
|
||||
|
||||
const uint8_t* src = buffer_.get();
|
||||
uint8_t* dst = compressedBuffer;
|
|
@ -1,18 +1,17 @@
|
|||
#ifndef ENGINE_IMAGE_H
|
||||
#define ENGINE_IMAGE_H
|
||||
#ifndef ENGINE_ASSET_IMAGE_H
|
||||
#define ENGINE_ASSET_IMAGE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
#include "base/mem.h"
|
||||
#include "base/vecmath.h"
|
||||
#include "engine/renderer/renderer_types.h"
|
||||
|
||||
namespace eng {
|
||||
|
||||
class Image {
|
||||
public:
|
||||
enum Format { kRGBA32, kDXT1, kDXT5, kETC1, kATC, kATCIA };
|
||||
|
||||
Image();
|
||||
Image(const Image& other);
|
||||
~Image();
|
||||
|
@ -31,8 +30,8 @@ class Image {
|
|||
int GetWidth() const { return width_; }
|
||||
int GetHeight() const { return height_; }
|
||||
|
||||
Format GetFormat() const { return format_; }
|
||||
bool IsCompressed() const { return format_ > kRGBA32; }
|
||||
ImageFormat GetFormat() const { return format_; }
|
||||
bool IsCompressed() const;
|
||||
|
||||
size_t GetSize() const;
|
||||
|
||||
|
@ -51,9 +50,9 @@ class Image {
|
|||
base::AlignedMemPtr<uint8_t[]> buffer_;
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
Format format_ = kRGBA32;
|
||||
ImageFormat format_ = ImageFormat::kRGBA32;
|
||||
};
|
||||
|
||||
} // namespace eng
|
||||
|
||||
#endif // ENGINE_IMAGE_H
|
||||
#endif // ENGINE_ASSET_IMAGE_H
|
|
@ -1,4 +1,4 @@
|
|||
#include "engine/mesh.h"
|
||||
#include "engine/asset/mesh.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
@ -22,7 +22,7 @@ bool Mesh::Create(Primitive primitive,
|
|||
num_indices_ = num_indices;
|
||||
|
||||
if (!ParseVertexDescription(vertex_description, vertex_description_)) {
|
||||
LOG << "Failed to parse vertex description.";
|
||||
LOG(0) << "Failed to parse vertex description.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ bool Mesh::Load(const std::string& file_name) {
|
|||
Engine::Get().GetRootPath().c_str(),
|
||||
&buffer_size, true);
|
||||
if (!json_mesh) {
|
||||
LOG << "Failed to read file: " << file_name;
|
||||
LOG(0) << "Failed to read file: " << file_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ bool Mesh::Load(const std::string& file_name) {
|
|||
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
|
||||
if (!reader->parse(json_mesh.get(), json_mesh.get() + buffer_size, &root,
|
||||
&err)) {
|
||||
LOG << "Failed to load mesh. Json parser error: " << err;
|
||||
LOG(0) << "Failed to load mesh. Json parser error: " << err;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ bool Mesh::Load(const std::string& file_name) {
|
|||
} else if (primitive_str == "TriangleStrip") {
|
||||
primitive_ = kPrimitive_TriangleStrip;
|
||||
} else {
|
||||
LOG << "Failed to load mesh. Invalid primitive: " << primitive_str;
|
||||
LOG(0) << "Failed to load mesh. Invalid primitive: " << primitive_str;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ bool Mesh::Load(const std::string& file_name) {
|
|||
|
||||
if (!ParseVertexDescription(root["vertex_description"].asString(),
|
||||
vertex_description_)) {
|
||||
LOG << "Failed to parse vertex description.";
|
||||
LOG(0) << "Failed to parse vertex description.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -90,18 +90,19 @@ bool Mesh::Load(const std::string& file_name) {
|
|||
|
||||
const Json::Value vertices = root["vertices"];
|
||||
if (vertices.size() != array_size) {
|
||||
LOG << "Failed to load mesh. Vertex array size: " << vertices.size()
|
||||
<< ", expected " << array_size;
|
||||
LOG(0) << "Failed to load mesh. Vertex array size: " << vertices.size()
|
||||
<< ", expected " << array_size;
|
||||
return false;
|
||||
}
|
||||
|
||||
int vertex_buffer_size = GetVertexSize() * num_vertices_;
|
||||
if (vertex_buffer_size <= 0) {
|
||||
LOG << "Failed to load mesh. Invalid vertex size.";
|
||||
LOG(0) << "Failed to load mesh. Invalid vertex size.";
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG << "Loaded " << file_name << ". Vertex array size: " << vertices.size();
|
||||
LOG(0) << "Loaded " << file_name
|
||||
<< ". Vertex array size: " << vertices.size();
|
||||
|
||||
vertices_ = std::make_unique<char[]>(vertex_buffer_size);
|
||||
|
||||
|
@ -131,35 +132,23 @@ bool Mesh::Load(const std::string& file_name) {
|
|||
*((unsigned short*)dst) = (unsigned short)vertices[i].asUInt();
|
||||
break;
|
||||
default:
|
||||
NOTREACHED << "- Unknown data type: " << data_type;
|
||||
NOTREACHED() << "- Unknown data type: " << data_type;
|
||||
}
|
||||
dst += type_size;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Load indices
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Mesh::GetVertexSize() const {
|
||||
unsigned int size = 0;
|
||||
for (auto& attr : vertex_description_) {
|
||||
size += std::get<2>(attr) * std::get<3>(attr);
|
||||
}
|
||||
return size;
|
||||
return eng::GetVertexSize(vertex_description_);
|
||||
}
|
||||
|
||||
size_t Mesh::GetIndexSize() const {
|
||||
switch (index_description_) {
|
||||
case kDataType_Byte:
|
||||
return sizeof(char);
|
||||
case kDataType_UShort:
|
||||
return sizeof(unsigned short);
|
||||
case kDataType_UInt:
|
||||
return sizeof(unsigned int);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return eng::GetIndexSize(index_description_);
|
||||
}
|
||||
|
||||
} // namespace eng
|