Compare commits
141 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 | |
|
f6f67d7e53 | |
|
43afdf855f | |
|
66557f07e3 | |
|
d5ee1c7313 | |
|
8d28d85a09 | |
|
b160ae0bd3 | |
|
b7f1f7faa2 | |
|
94242fca0b | |
|
be36d121b0 | |
|
217420823c | |
|
b2e5f19963 | |
|
971540dce2 | |
|
5cad50bf55 | |
|
41bb5e286a | |
|
0454bf6a18 | |
|
c90d039944 | |
|
be1d562a07 | |
|
cda1d750f8 |
|
@ -1,7 +1,2 @@
|
||||||
BasedOnStyle: Chromium
|
BasedOnStyle: Chromium
|
||||||
Standard: Cpp11
|
Standard: Cpp11
|
||||||
|
|
||||||
MacroBlockBegin: "^\
|
|
||||||
RENDER_COMMAND_BEGIN$"
|
|
||||||
MacroBlockEnd: "^\
|
|
||||||
RENDER_COMMAND_END$"
|
|
||||||
|
|
|
@ -4,8 +4,4 @@ build/android/*.idsig
|
||||||
build/android/app/.cxx
|
build/android/app/.cxx
|
||||||
build/android/app/build
|
build/android/app/build
|
||||||
build/android/build
|
build/android/build
|
||||||
build/linux/demo_x86_64_debug
|
|
||||||
build/linux/demo_x86_64_release
|
|
||||||
build/linux/obj
|
|
||||||
build/linux/woom
|
|
||||||
out
|
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",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "(gdb) Launch",
|
"name": "Debug demo - Linux",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/build/linux/demo_x86_64_debug",
|
"program": "${workspaceFolder}/out/debug/demo",
|
||||||
"args": [],
|
"args": [],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}/build/linux",
|
"cwd": "${workspaceFolder}/out/debug",
|
||||||
"environment": [],
|
"environment": [],
|
||||||
"console": "externalTerminal",
|
"console": "externalTerminal",
|
||||||
"MIMode": "gdb",
|
"MIMode": "gdb",
|
||||||
|
@ -22,6 +22,19 @@
|
||||||
"ignoreFailures": true
|
"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",
|
||||||
|
]
|
||||||
|
}
|
88
README.md
|
@ -1,20 +1,87 @@
|
||||||
|
# Kaliber
|
||||||
|
|
||||||
A simple, cross-platform 2D game engine with OpenGL and Vulkan renderers.
|
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
|
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)
|
[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.
|
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
|
```text
|
||||||
cd build/linux
|
gn gen out/release
|
||||||
make
|
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
|
```text
|
||||||
cd build/android
|
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),
|
[glew](https://github.com/nigels-com/glew),
|
||||||
[jsoncpp](https://github.com/open-source-parsers/jsoncpp),
|
[jsoncpp](https://github.com/open-source-parsers/jsoncpp),
|
||||||
[minimp3](https://github.com/lieff/minimp3),
|
[minimp3](https://github.com/lieff/minimp3),
|
||||||
|
@ -25,5 +92,6 @@ cd build/android
|
||||||
[glslang](https://github.com/KhronosGroup/glslang),
|
[glslang](https://github.com/KhronosGroup/glslang),
|
||||||
[spirv-reflect](https://github.com/KhronosGroup/SPIRV-Reflect),
|
[spirv-reflect](https://github.com/KhronosGroup/SPIRV-Reflect),
|
||||||
[vma](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator),
|
[vma](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator),
|
||||||
[vulkan-sdk](https://vulkan.lunarg.com)
|
[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,171 +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_base.cc
|
|
||||||
../../../src/engine/audio/audio_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/platform/platform.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: 'com.android.application'
|
||||||
|
apply plugin: Utils
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdk 33
|
compileSdk rootProject.ext.compileSdk
|
||||||
ndkVersion '25.1.8937393'
|
ndkVersion rootProject.ext.ndkVersion
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = 'com.woom.game'
|
minSdk rootProject.ext.minSdk
|
||||||
minSdk 24
|
targetSdk rootProject.ext.targetSdk
|
||||||
targetSdk 33
|
|
||||||
externalNativeBuild {
|
|
||||||
cmake {
|
|
||||||
arguments '-DANDROID_STL=c++_static'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
|
abiFilters = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
||||||
'proguard-rules.pro'
|
'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 {
|
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 {
|
sourceSets {
|
||||||
main {
|
main {
|
||||||
java.srcDirs += ['../../../src/engine/platform/java/com/kaliber/base']
|
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"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace 'com.woom.game'
|
}
|
||||||
|
android.buildTypes.each { buildType ->
|
||||||
|
"${buildType.name}" {
|
||||||
|
jniLibs.srcDirs = ["${utils.getGnOutDir(buildType.name)}/jniLibs"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace "com.kaliber.base"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -48,3 +134,247 @@ dependencies {
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||||
implementation 'com.google.android.gms:play-services-ads:22.0.0'
|
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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:versionCode="18"
|
android:versionCode="22"
|
||||||
android:versionName="1.0.2">
|
android:versionName="1.0.4">
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:fullBackupContent="false"
|
android:fullBackupContent="false"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="${appIcon}"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
@ -27,16 +27,16 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.app.lib_name"
|
android:name="android.app.lib_name"
|
||||||
android:value="kaliber" />
|
android:value="@string/lib_name" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.gms.ads.APPLICATION_ID"
|
android:name="com.google.android.gms.ads.APPLICATION_ID"
|
||||||
android:value="ca-app-pub-1321063817979967~1100949243" />
|
android:value="@string/admob_application_id" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="com.woom.game.fileprovider"
|
android:authorities="${applicationId}.fileprovider"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:grantUriPermissions="true">
|
android:grantUriPermissions="true">
|
||||||
<meta-data
|
<meta-data
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">woom</string>
|
<string name="app_name">Kaliber app</string>
|
||||||
<string name="interstitial_ad_unit_id">ca-app-pub-1321063817979967/8373182022</string>
|
<string name="interstitial_ad_unit_id"></string>
|
||||||
|
<string name="admob_application_id">ca-app-pub-3940256099942544~3347511713</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -5,7 +5,7 @@ buildscript {
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
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) {
|
task clean(type: Delete) {
|
||||||
delete rootProject.buildDir
|
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,283 +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_alsa.cc \
|
|
||||||
$(SRC_ROOT)/engine/audio/audio_base.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.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__)
|
#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) \
|
#define LOCATION(from) \
|
||||||
std::get<0>(from) << "() [" << [](const char* path) -> std::string { \
|
std::get<0>(from) << "() [" << [](std::string path) -> std::string { \
|
||||||
std::string file_name(path); \
|
size_t last_slash_pos = path.find_last_of("\\/"); \
|
||||||
size_t last_slash_pos = file_name.find_last_of("\\/"); \
|
|
||||||
if (last_slash_pos != std::string::npos) \
|
if (last_slash_pos != std::string::npos) \
|
||||||
file_name = file_name.substr(last_slash_pos + 1); \
|
path = path.substr(last_slash_pos + 1); \
|
||||||
return file_name; \
|
return path; \
|
||||||
}(std::get<1>(from)) << ":" \
|
}(std::get<1>(from)) << ":" \
|
||||||
<< std::get<2>(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
|
// Provides location info (function name, file name and line number) where of a
|
||||||
// Closure was constructed.
|
// Closure was constructed.
|
||||||
using Location = std::tuple<const char*, const char*, int>;
|
using Location = std::tuple<std::string, std::string, int>;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
|
@ -6,17 +6,15 @@
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
|
|
||||||
// Compile-time string hashing function.
|
|
||||||
template <size_t N>
|
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;
|
size_t hash_value = 0;
|
||||||
for (int i = 0; str[i] != '\0'; ++i)
|
for (int i = 0; str[i] != '\0'; ++i)
|
||||||
hash_value = str[i] + 31 * hash_value;
|
hash_value = str[i] + 31 * hash_value;
|
||||||
return hash_value;
|
return hash_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The same hashing function for run-time.
|
inline size_t KR2Hash(const std::string& str) {
|
||||||
inline size_t Hash(const std::string& str) {
|
|
||||||
size_t hash_value = 0;
|
size_t hash_value = 0;
|
||||||
for (std::string::value_type c : str)
|
for (std::string::value_type c : str)
|
||||||
hash_value = c + 31 * hash_value;
|
hash_value = c + 31 * hash_value;
|
||||||
|
|
|
@ -2,52 +2,74 @@
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#include <format>
|
||||||
#else
|
#else
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#endif
|
#endif
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace base {
|
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
|
// 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
|
// an object of the correct type on the LHS of the unused part of the ternary
|
||||||
// operator.
|
// operator.
|
||||||
std::ostream* LogMessage::swallow_stream;
|
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() {
|
LogMessage::~LogMessage() {
|
||||||
stream_ << std::endl;
|
stream_ << std::endl;
|
||||||
std::string text(stream_.str());
|
std::string message(stream_.str());
|
||||||
std::string filename(file_);
|
std::string filename(file_);
|
||||||
size_t last_slash_pos = filename.find_last_of("\\/");
|
size_t last_slash_pos = filename.find_last_of("\\/");
|
||||||
if (last_slash_pos != std::string::npos)
|
if (last_slash_pos != std::string::npos)
|
||||||
filename = filename.substr(last_slash_pos + 1);
|
filename = filename.substr(last_slash_pos + 1);
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
__android_log_print(ANDROID_LOG_ERROR, "kaliber", "[%s:%d] %s",
|
__android_log_print(ANDROID_LOG_ERROR, "kaliber", "%d [%s:%d] %s",
|
||||||
filename.c_str(), line_, text.c_str());
|
verbosity_level_, filename.c_str(), line_,
|
||||||
|
message.c_str());
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
OutputDebugStringA(
|
||||||
|
std::format("{} [{}:{}] {}", verbosity_level_, filename, line_, message)
|
||||||
|
.c_str());
|
||||||
#else
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
LogAbort LogAbort::Check(const char* file, int line, const char* expr) {
|
LogAbort LogAbort::Check(const char* file, int line, const char* expr) {
|
||||||
LogAbort instance(new LogMessage(file, line));
|
LogAbort instance(new LogMessage(file, line, 0));
|
||||||
instance.GetLog().stream() << "CHECK: "
|
instance.GetLog().stream() << "CHECK(" << expr << ") ";
|
||||||
<< "(" << expr << ") ";
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
LogAbort LogAbort::DCheck(const char* file, int line, const char* expr) {
|
LogAbort LogAbort::DCheck(const char* file, int line, const char* expr) {
|
||||||
LogAbort instance(new LogMessage(file, line));
|
LogAbort instance(new LogMessage(file, line, 0));
|
||||||
instance.GetLog().stream() << "DCHECK: "
|
instance.GetLog().stream() << "DCHECK(" << expr << ") ";
|
||||||
<< "(" << expr << ") ";
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
LogAbort LogAbort::NotReached(const char* file, int line) {
|
LogAbort LogAbort::NotReached(const char* file, int line) {
|
||||||
LogAbort instance(new LogMessage(file, line));
|
LogAbort instance(new LogMessage(file, line, 0));
|
||||||
instance.GetLog().stream() << "NOTREACHED ";
|
instance.GetLog().stream() << "NOTREACHED() ";
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,45 +11,66 @@
|
||||||
// CHECK(condition) terminates the process if the condition is false.
|
// CHECK(condition) terminates the process if the condition is false.
|
||||||
// NOTREACHED annotates unreachable codepaths and terminates the process if
|
// NOTREACHED annotates unreachable codepaths and terminates the process if
|
||||||
// reached.
|
// reached.
|
||||||
#define LOG base::LogMessage(__FILE__, __LINE__).stream()
|
#define LOG(verbosity_level) \
|
||||||
#define LOG_IF(condition) \
|
|
||||||
LAZY_STREAM(condition, base::LogMessage(__FILE__, __LINE__).stream())
|
|
||||||
#define CHECK(condition) \
|
|
||||||
LAZY_STREAM( \
|
LAZY_STREAM( \
|
||||||
!(condition), \
|
LOG_IS_ON(verbosity_level), \
|
||||||
base::LogAbort::Check(__FILE__, __LINE__, #condition).GetLog().stream())
|
::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 \
|
#define NOTREACHED() \
|
||||||
base::LogAbort::NotReached(__FILE__, __LINE__).GetLog().stream()
|
::base::LogAbort::NotReached(__FILE__, __LINE__).GetLog().stream()
|
||||||
|
|
||||||
// Macros for logging which are active only in debug builds.
|
// Macros for logging which are active only in debug builds.
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define DLOG base::LogMessage(__FILE__, __LINE__).stream()
|
#define DLOG(verbosity_level) \
|
||||||
#define DLOG_IF(condition) \
|
LAZY_STREAM( \
|
||||||
LAZY_STREAM(condition, base::LogMessage(__FILE__, __LINE__).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) \
|
#define DCHECK(condition) \
|
||||||
LAZY_STREAM(!(condition), \
|
LAZY_STREAM(!(condition), \
|
||||||
base::LogAbort::DCheck(__FILE__, __LINE__, #condition) \
|
::base::LogAbort::DCheck(__FILE__, __LINE__, #condition) \
|
||||||
.GetLog() \
|
.GetLog() \
|
||||||
.stream())
|
.stream())
|
||||||
#else
|
#else
|
||||||
// "debug mode" logging is compiled away to nothing for release builds.
|
// "debug mode" logging is compiled away to nothing for release builds.
|
||||||
#define DLOG EAT_STREAM_PARAMETERS
|
#define DLOG(verbosity_level) EAT_STREAM_PARAMETERS
|
||||||
#define DLOG_IF(condition) EAT_STREAM_PARAMETERS
|
#define DLOG_IF(verbosity_level, condition) EAT_STREAM_PARAMETERS
|
||||||
#define DCHECK(condition) EAT_STREAM_PARAMETERS
|
#define DCHECK(condition) EAT_STREAM_PARAMETERS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Helper macro which avoids evaluating the arguments to a stream if
|
// Helper macro which avoids evaluating the arguments to a stream if
|
||||||
// the condition doesn't hold.
|
// the condition doesn't hold.
|
||||||
#define LAZY_STREAM(condition, stream) \
|
#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.
|
// Avoid any pointless instructions to be emitted by the compiler.
|
||||||
#define EAT_STREAM_PARAMETERS \
|
#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 {
|
namespace base {
|
||||||
|
|
||||||
|
int GlobalMaxLogVerbosityLevel();
|
||||||
|
|
||||||
class LogMessage {
|
class LogMessage {
|
||||||
public:
|
public:
|
||||||
class Voidify {
|
class Voidify {
|
||||||
|
@ -61,18 +82,17 @@ class LogMessage {
|
||||||
void operator&(std::ostream&) {}
|
void operator&(std::ostream&) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
LogMessage(const char* file, int line);
|
LogMessage(const char* file, int line, int verbosity_level);
|
||||||
~LogMessage();
|
~LogMessage();
|
||||||
|
|
||||||
LogMessage& base() { return *this; }
|
|
||||||
|
|
||||||
std::ostream& stream() { return stream_; }
|
std::ostream& stream() { return stream_; }
|
||||||
|
|
||||||
static std::ostream* swallow_stream;
|
static std::ostream* swallow_stream;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const char* file_;
|
const char* file_;
|
||||||
const int line_;
|
int line_;
|
||||||
|
int verbosity_level_;
|
||||||
std::ostringstream stream_;
|
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
|
#ifndef BASE_MEM_H
|
||||||
#define BASE_MEM_H
|
#define BASE_MEM_H
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(_WIN32)
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#else
|
||||||
|
#include <stdlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
|
#include "base/misc.h"
|
||||||
#define ALIGN_MEM(alignment) __attribute__((aligned(alignment)))
|
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
|
|
||||||
|
inline void AlignedFree(void* mem) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
_aligned_free(mem);
|
||||||
|
#else
|
||||||
|
free(mem);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
struct ScopedAlignedFree {
|
struct ScopedAlignedFree {
|
||||||
inline void operator()(void* x) const {
|
inline void operator()(void* x) const { AlignedFree(x); }
|
||||||
if (x)
|
|
||||||
free(x);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -28,27 +35,16 @@ struct ScopedAlignedFree {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using AlignedMemPtr = std::unique_ptr<T, internal::ScopedAlignedFree>;
|
using AlignedMemPtr = std::unique_ptr<T, internal::ScopedAlignedFree>;
|
||||||
|
|
||||||
template <int kAlignment>
|
void* AlignedAlloc(size_t size, size_t alignment);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void AlignedFree(void* mem) {
|
void* AlignedRealloc(void* ptr,
|
||||||
free(mem);
|
size_t old_size,
|
||||||
}
|
size_t new_size,
|
||||||
|
size_t alignment);
|
||||||
|
|
||||||
template <int kAlignment>
|
inline bool IsAligned(const void* val, size_t alignment) {
|
||||||
inline bool IsAligned(void* ptr) {
|
DCHECK(IsPow2(alignment)) << alignment << " is not a power of 2";
|
||||||
return (reinterpret_cast<uintptr_t>(ptr) & (kAlignment - 1)) == 0U;
|
return (reinterpret_cast<uintptr_t>(val) & (alignment - 1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace base
|
} // namespace base
|
||||||
|
|
|
@ -1,31 +1,42 @@
|
||||||
#ifndef BASE_MISC_H
|
#ifndef BASE_MISC_H
|
||||||
#define BASE_MISC_H
|
#define BASE_MISC_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#define CRASH *((int*)nullptr) = 0;
|
#define CRASH *((int*)nullptr) = 0;
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
|
|
||||||
// ToDo: x86 has the bsr instruction.
|
inline uint32_t GetHighestBitPos(uint32_t value) {
|
||||||
inline int GetHighestBitPos(int value) {
|
uint32_t result = 0;
|
||||||
return (0xFFFF0000 & value ? value &= 0xFFFF0000, 1 : 0) * 0x10 +
|
if (0xFFFF0000 & value) {
|
||||||
(0xFF00FF00 & value ? value &= 0xFF00FF00, 1 : 0) * 0x08 +
|
value &= 0xFFFF0000;
|
||||||
(0xF0F0F0F0 & value ? value &= 0xF0F0F0F0, 1 : 0) * 0x04 +
|
result += 0x10;
|
||||||
(0xCCCCCCCC & value ? value &= 0xCCCCCCCC, 1 : 0) * 0x02 +
|
}
|
||||||
(0xAAAAAAAA & value ? 1 : 0) * 0x01;
|
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) {
|
inline bool IsPow2(int value) {
|
||||||
return GetHighestBit(value) == value;
|
return ((value & (value - 1)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int RoundUpToPow2(int val) {
|
inline uint32_t RoundUpToPow2(uint32_t val) {
|
||||||
int i = GetHighestBit(val);
|
uint32_t i = 1 << GetHighestBitPos(val);
|
||||||
return val == i ? val : i << 1;
|
return val == i ? val : i << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,55 +4,75 @@
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void PostTaskAndReplyRelay(base::Location from,
|
void PostTaskAndReplyRelay(Location from,
|
||||||
base::Closure task_cb,
|
Closure task_cb,
|
||||||
base::Closure reply_cb,
|
Closure reply_cb,
|
||||||
base::TaskRunner* destination) {
|
std::shared_ptr<TaskRunner> destination,
|
||||||
|
bool front) {
|
||||||
task_cb();
|
task_cb();
|
||||||
|
|
||||||
if (reply_cb)
|
if (reply_cb)
|
||||||
destination->PostTask(from, std::move(reply_cb));
|
destination->PostTask(from, std::move(reply_cb), front);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace base {
|
// 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.
|
||||||
thread_local std::unique_ptr<TaskRunner> TaskRunner::thread_local_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() {
|
void TaskRunner::CreateThreadLocalTaskRunner() {
|
||||||
DCHECK(!thread_local_task_runner);
|
DCHECK(!thread_local_task_runner);
|
||||||
|
|
||||||
thread_local_task_runner = std::make_unique<TaskRunner>();
|
thread_local_task_runner = std::make_shared<TaskRunner>();
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskRunner* TaskRunner::GetThreadLocalTaskRunner() {
|
std::shared_ptr<TaskRunner> TaskRunner::GetThreadLocalTaskRunner() {
|
||||||
return thread_local_task_runner.get();
|
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);
|
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_);
|
std::lock_guard<std::mutex> scoped_lock(lock_);
|
||||||
|
if (front)
|
||||||
|
queue_.emplace_front(from, std::move(task));
|
||||||
|
else
|
||||||
queue_.emplace_back(from, std::move(task));
|
queue_.emplace_back(from, std::move(task));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskRunner::PostTaskAndReply(const Location& from,
|
void TaskRunner::PostTaskAndReply(Location from,
|
||||||
Closure task,
|
Closure task,
|
||||||
Closure reply) {
|
Closure reply,
|
||||||
|
bool front) {
|
||||||
DCHECK(task) << LOCATION(from);
|
DCHECK(task) << LOCATION(from);
|
||||||
DCHECK(reply) << LOCATION(from);
|
DCHECK(reply) << LOCATION(from);
|
||||||
DCHECK(thread_local_task_runner) << LOCATION(from);
|
DCHECK(thread_local_task_runner) << LOCATION(from);
|
||||||
|
|
||||||
auto relay = std::bind(::PostTaskAndReplyRelay, from, std::move(task),
|
auto relay = std::bind(PostTaskAndReplyRelay, from, std::move(task),
|
||||||
std::move(reply), thread_local_task_runner.get());
|
std::move(reply), thread_local_task_runner, front);
|
||||||
PostTask(from, std::move(relay));
|
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 (;;) {
|
for (;;) {
|
||||||
Task task;
|
Task task;
|
||||||
{
|
{
|
||||||
|
@ -66,7 +86,7 @@ void TaskRunner::MultiConsumerRun() {
|
||||||
auto [from, task_cb] = task;
|
auto [from, task_cb] = task;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
LOG << __func__ << " from: " << LOCATION(from);
|
LOG(0) << __func__ << " from: " << LOCATION(from);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
task_cb();
|
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
|
} // namespace base
|
||||||
|
|
|
@ -18,55 +18,66 @@ namespace internal {
|
||||||
// one that returns via an output parameter.
|
// one that returns via an output parameter.
|
||||||
template <typename ReturnType>
|
template <typename ReturnType>
|
||||||
void ReturnAsParamAdapter(std::function<ReturnType()> func,
|
void ReturnAsParamAdapter(std::function<ReturnType()> func,
|
||||||
ReturnType* result) {
|
std::shared_ptr<ReturnType> result) {
|
||||||
*result = func();
|
*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>
|
template <typename ReturnType>
|
||||||
void ReplyAdapter(std::function<void(ReturnType)> callback,
|
void ReplyAdapter(std::function<void(ReturnType)> callback,
|
||||||
ReturnType* result) {
|
std::shared_ptr<ReturnType> result) {
|
||||||
callback(*result);
|
callback(std::move(*result));
|
||||||
delete result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
// Runs queued tasks (in the form of Closure objects). All methods are
|
// Runs queued tasks (in the form of Closure objects). All methods are
|
||||||
// thread-safe and can be called on any thread.
|
// thread-safe and can be called on any thread.
|
||||||
// Tasks run in FIFO order. When consumed concurrently by multiple threads, it
|
// Tasks run in FIFO order when consumed by a single thread. When consumed
|
||||||
// doesn't guarantee whether tasks overlap, or whether they run on a particular
|
// concurrently by multiple threads, it doesn't guarantee whether tasks overlap,
|
||||||
// thread.
|
// or whether they run on a particular thread.
|
||||||
class TaskRunner {
|
class TaskRunner {
|
||||||
public:
|
public:
|
||||||
TaskRunner() = default;
|
TaskRunner() = default;
|
||||||
~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>
|
template <typename ReturnType>
|
||||||
void PostTaskAndReplyWithResult(const Location& from,
|
void PostTaskAndReplyWithResult(Location from,
|
||||||
std::function<ReturnType()> task,
|
std::function<ReturnType()> task,
|
||||||
std::function<void(ReturnType)> reply) {
|
std::function<void(ReturnType)> reply,
|
||||||
auto* result = new ReturnType;
|
bool front = false) {
|
||||||
|
auto result = std::make_shared<ReturnType>();
|
||||||
return PostTaskAndReply(
|
return PostTaskAndReply(
|
||||||
from,
|
from,
|
||||||
std::bind(internal::ReturnAsParamAdapter<ReturnType>, std::move(task),
|
std::bind(internal::ReturnAsParamAdapter<ReturnType>, std::move(task),
|
||||||
result),
|
result),
|
||||||
std::bind(internal::ReplyAdapter<ReturnType>, std::move(reply),
|
std::bind(internal::ReplyAdapter<ReturnType>, std::move(reply), result),
|
||||||
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();
|
void WaitForCompletion();
|
||||||
|
|
||||||
static void CreateThreadLocalTaskRunner();
|
void RunTasks();
|
||||||
static TaskRunner* GetThreadLocalTaskRunner();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using Task = std::tuple<Location, Closure>;
|
using Task = std::tuple<Location, Closure>;
|
||||||
|
@ -75,7 +86,7 @@ class TaskRunner {
|
||||||
mutable std::mutex lock_;
|
mutable std::mutex lock_;
|
||||||
std::atomic<size_t> task_count_{0};
|
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(TaskRunner const&) = delete;
|
||||||
TaskRunner& operator=(TaskRunner const&) = delete;
|
TaskRunner& operator=(TaskRunner const&) = delete;
|
||||||
|
|
|
@ -40,30 +40,30 @@ void ThreadPool::Shutdown() {
|
||||||
threads_.clear();
|
threads_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadPool::PostTask(const Location& from, Closure task) {
|
void ThreadPool::PostTask(Location from, Closure task, bool front) {
|
||||||
DCHECK((!threads_.empty()));
|
task_runner_.PostTask(from, std::move(task), front);
|
||||||
|
|
||||||
task_runner_.PostTask(from, std::move(task));
|
|
||||||
semaphore_.release();
|
semaphore_.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadPool::PostTaskAndReply(const Location& from,
|
void ThreadPool::PostTaskAndReply(Location from,
|
||||||
Closure task,
|
Closure task,
|
||||||
Closure reply) {
|
Closure reply,
|
||||||
DCHECK((!threads_.empty()));
|
bool front) {
|
||||||
|
task_runner_.PostTaskAndReply(from, std::move(task), std::move(reply), front);
|
||||||
task_runner_.PostTaskAndReply(from, std::move(task), std::move(reply));
|
|
||||||
semaphore_.release();
|
semaphore_.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ThreadPool::CancelTasks() {
|
||||||
|
task_runner_.CancelTasks();
|
||||||
|
}
|
||||||
|
|
||||||
void ThreadPool::WorkerMain() {
|
void ThreadPool::WorkerMain() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
semaphore_.acquire();
|
semaphore_.acquire();
|
||||||
|
|
||||||
if (quit_.load(std::memory_order_relaxed))
|
if (quit_.load(std::memory_order_relaxed))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
task_runner_.MultiConsumerRun();
|
task_runner_.RunTasks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
|
|
||||||
class TaskRunner;
|
|
||||||
|
|
||||||
// Feed the ThreadPool tasks (in the form of Closure objects) and they will be
|
// Feed the ThreadPool tasks (in the form of Closure objects) and they will be
|
||||||
// called on any thread from the pool.
|
// called on any thread from the pool.
|
||||||
class ThreadPool {
|
class ThreadPool {
|
||||||
|
@ -26,19 +24,25 @@ class ThreadPool {
|
||||||
|
|
||||||
void Shutdown();
|
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>
|
template <typename ReturnType>
|
||||||
void PostTaskAndReplyWithResult(const Location& from,
|
void PostTaskAndReplyWithResult(Location from,
|
||||||
std::function<ReturnType()> task,
|
std::function<ReturnType()> task,
|
||||||
std::function<void(ReturnType)> reply) {
|
std::function<void(ReturnType)> reply,
|
||||||
|
bool front = false) {
|
||||||
task_runner_.PostTaskAndReplyWithResult(from, std::move(task),
|
task_runner_.PostTaskAndReplyWithResult(from, std::move(task),
|
||||||
std::move(reply));
|
std::move(reply), front);
|
||||||
semaphore_.release();
|
semaphore_.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CancelTasks();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::thread> threads_;
|
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
|
#ifndef BASE_TIMER_H
|
||||||
#define BASE_TIMER_H
|
#define BASE_TIMER_H
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
|
|
||||||
class Timer {
|
class ElapsedTimer {
|
||||||
public:
|
public:
|
||||||
Timer();
|
ElapsedTimer() { time_ = std::chrono::high_resolution_clock::now(); }
|
||||||
~Timer() = default;
|
|
||||||
|
|
||||||
void Reset();
|
// Return seconds passed since creating the object.
|
||||||
|
double Elapsed() const {
|
||||||
void Update();
|
auto current_time = std::chrono::high_resolution_clock::now();
|
||||||
|
std::chrono::duration<double> diff = current_time - time_;
|
||||||
static void Sleep(float duration);
|
return diff.count();
|
||||||
|
}
|
||||||
float GetSecondsPassed() const { return seconds_passed_; }
|
|
||||||
float GetSecondsAccumulated() const { return seconds_accumulated_; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float seconds_passed_ = 0.0f;
|
std::chrono::time_point<std::chrono::high_resolution_clock> time_;
|
||||||
float seconds_accumulated_ = 0.0f;
|
|
||||||
|
|
||||||
timeval last_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
|
} // namespace base
|
||||||
|
|
||||||
#endif // BASE_TIMER_H
|
#endif // BASE_TIMER_H
|
||||||
|
|
|
@ -1247,8 +1247,8 @@ class Matrix4 {
|
||||||
T fov_aspect,
|
T fov_aspect,
|
||||||
T width,
|
T width,
|
||||||
T height,
|
T height,
|
||||||
T near,
|
T near_plane,
|
||||||
T far) {
|
T far_plane) {
|
||||||
// Calc x and y scale from FOV.
|
// Calc x and y scale from FOV.
|
||||||
T scale =
|
T scale =
|
||||||
T(2.0) /
|
T(2.0) /
|
||||||
|
@ -1257,8 +1257,8 @@ class Matrix4 {
|
||||||
T x_scale = y_scale / (width / height);
|
T x_scale = y_scale / (width / height);
|
||||||
_M_SET_ROW(0, x_scale / T(2.0), 0, 0, 0);
|
_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(1, 0, (-y_scale) / T(2.0), 0, 0);
|
||||||
_M_SET_ROW(2, 0, 0, far / (far - near), 1);
|
_M_SET_ROW(2, 0, 0, far_plane / (far_plane - near_plane), 1);
|
||||||
_M_SET_ROW(3, 0, 0, -near * far / (far - near), 0);
|
_M_SET_ROW(3, 0, 0, -near_plane * far_plane / (far_plane - near_plane), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateTranslation(const Vector3<T>& t) {
|
void CreateTranslation(const Vector3<T>& t) {
|
||||||
|
@ -1343,7 +1343,7 @@ class Matrix4 {
|
||||||
M_x_RotZ(angles[2]);
|
M_x_RotZ(angles[2]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
NOTREACHED;
|
NOTREACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1534,7 +1534,7 @@ class Matrix4 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
NOTREACHED;
|
NOTREACHED();
|
||||||
}
|
}
|
||||||
return -angles;
|
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/log.h"
|
||||||
#include "base/vecmath.h"
|
#include "base/vecmath.h"
|
||||||
#include "demo/demo.h"
|
#include "demo/demo.h"
|
||||||
|
#include "engine/asset/font.h"
|
||||||
|
#include "engine/asset/image.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/font.h"
|
|
||||||
#include "engine/image.h"
|
|
||||||
#include "engine/input_event.h"
|
#include "engine/input_event.h"
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
@ -95,7 +95,7 @@ void Credits::Show() {
|
||||||
void Credits::Hide() {
|
void Credits::Hide() {
|
||||||
text_animator_.SetEndCallback(Animator::kBlending, [&]() -> void {
|
text_animator_.SetEndCallback(Animator::kBlending, [&]() -> void {
|
||||||
for (int i = 0; i < kNumLines; ++i)
|
for (int i = 0; i < kNumLines; ++i)
|
||||||
text_[i].Destory();
|
text_[i].Destroy();
|
||||||
text_animator_.SetEndCallback(Animator::kBlending, nullptr);
|
text_animator_.SetEndCallback(Animator::kBlending, nullptr);
|
||||||
text_animator_.SetVisible(false);
|
text_animator_.SetVisible(false);
|
||||||
});
|
});
|
||||||
|
|
126
src/demo/demo.cc
|
@ -13,11 +13,8 @@
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/game_factory.h"
|
#include "engine/game_factory.h"
|
||||||
#include "engine/input_event.h"
|
#include "engine/input_event.h"
|
||||||
#include "engine/sound.h"
|
|
||||||
|
|
||||||
DECLARE_GAME_BEGIN
|
GAME_FACTORIES{GAME_CLASS(Demo)};
|
||||||
DECLARE_GAME(Demo)
|
|
||||||
DECLARE_GAME_END
|
|
||||||
|
|
||||||
// #define RECORD 15
|
// #define RECORD 15
|
||||||
// #define REPLAY
|
// #define REPLAY
|
||||||
|
@ -47,55 +44,73 @@ Demo::~Demo() {
|
||||||
saved_data_.Save();
|
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() {
|
bool Demo::Initialize() {
|
||||||
saved_data_.Load(kSaveFileName);
|
saved_data_.Load(kSaveFileName);
|
||||||
|
|
||||||
if (!font_.Load("PixelCaps!.ttf"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!sky_.Create(false)) {
|
if (!sky_.Create(false)) {
|
||||||
LOG << "Could not create the sky.";
|
LOG(0) << "Could not create the sky.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enemy_.Initialize()) {
|
if (!enemy_.Initialize()) {
|
||||||
LOG << "Failed to create the enemy.";
|
LOG(0) << "Failed to create the enemy.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!player_.Initialize()) {
|
if (!player_.Initialize()) {
|
||||||
LOG << "Failed to create the enemy.";
|
LOG(0) << "Failed to create the enemy.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hud_.Initialize()) {
|
if (!hud_.Initialize()) {
|
||||||
LOG << "Failed to create the hud.";
|
LOG(0) << "Failed to create the hud.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!menu_.Initialize()) {
|
if (!menu_.Initialize()) {
|
||||||
LOG << "Failed to create the menu.";
|
LOG(0) << "Failed to create the menu.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!credits_.Initialize()) {
|
if (!credits_.Initialize()) {
|
||||||
LOG << "Failed to create the credits.";
|
LOG(0) << "Failed to create the credits.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sound = std::make_unique<Sound>();
|
music_.SetSound("music");
|
||||||
if (!sound->Load("Game_2_Main.mp3", true))
|
music_.SetMaxAmplitude(0.5f);
|
||||||
return false;
|
|
||||||
|
|
||||||
auto boss_sound = std::make_unique<Sound>();
|
boss_music_.SetSound("boss_music");
|
||||||
if (!boss_sound->Load("Game_2_Boss.mp3", true))
|
boss_music_.SetMaxAmplitude(0.5f);
|
||||||
return false;
|
|
||||||
|
|
||||||
music_.SetSound(std::move(sound));
|
|
||||||
music_.SetMaxAplitude(0.5f);
|
|
||||||
|
|
||||||
boss_music_.SetSound(std::move(boss_sound));
|
|
||||||
boss_music_.SetMaxAplitude(0.5f);
|
|
||||||
|
|
||||||
if (!saved_data_.root().get("audio", Json::Value(true)).asBool())
|
if (!saved_data_.root().get("audio", Json::Value(true)).asBool())
|
||||||
Engine::Get().SetEnableAudio(false);
|
Engine::Get().SetEnableAudio(false);
|
||||||
|
@ -126,11 +141,11 @@ void Demo::Update(float delta_time) {
|
||||||
|
|
||||||
if (do_benchmark_) {
|
if (do_benchmark_) {
|
||||||
benchmark_time_ += delta_time;
|
benchmark_time_ += delta_time;
|
||||||
if (benchmark_time_ > 1) {
|
if (benchmark_time_ > 3) {
|
||||||
avarage_fps_ += Engine::Get().fps();
|
avarage_fps_ += Engine::Get().fps();
|
||||||
++num_benchmark_samples_;
|
++num_benchmark_samples_;
|
||||||
}
|
}
|
||||||
if (benchmark_time_ > 6) {
|
if (benchmark_time_ > 5) {
|
||||||
avarage_fps_ /= num_benchmark_samples_;
|
avarage_fps_ /= num_benchmark_samples_;
|
||||||
do_benchmark_ = false;
|
do_benchmark_ = false;
|
||||||
BenchmarkResult(avarage_fps_);
|
BenchmarkResult(avarage_fps_);
|
||||||
|
@ -163,18 +178,22 @@ void Demo::Update(float delta_time) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Demo::ContextLost() {
|
void Demo::ContextLost() {
|
||||||
sky_.ContextLost();
|
if (do_benchmark_) {
|
||||||
enemy_.ContextLost();
|
benchmark_time_ = 0;
|
||||||
|
num_benchmark_samples_ = 0;
|
||||||
|
avarage_fps_ = 0;
|
||||||
|
}
|
||||||
|
menu_.SetRendererType();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Demo::LostFocus() {}
|
void Demo::LostFocus() {}
|
||||||
|
|
||||||
void Demo::GainedFocus(bool from_interstitial_ad) {
|
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 (!from_interstitial_ad) {
|
||||||
if (saved_data_.root().get(kLaunchCount, Json::Value(0)).asInt() >
|
// if (saved_data_.root().get(kLaunchCount, Json::Value(0)).asInt() >
|
||||||
kLaunchCountBeforeAd)
|
// kLaunchCountBeforeAd)
|
||||||
Engine::Get().ShowInterstitialAd();
|
// Engine::Get().ShowInterstitialAd();
|
||||||
if (state_ == kGame)
|
if (state_ == kGame)
|
||||||
EnterMenuState();
|
EnterMenuState();
|
||||||
}
|
}
|
||||||
|
@ -262,15 +281,15 @@ void Demo::EnterGameOverState() {
|
||||||
hud_.ShowMessage("Game Over", 3);
|
hud_.ShowMessage("Game Over", 3);
|
||||||
state_ = kGameOver;
|
state_ = kGameOver;
|
||||||
|
|
||||||
|
SetDelayedWork(1, [&]() -> void {
|
||||||
|
enemy_.RemoveAll();
|
||||||
|
SetDelayedWork(3, [&]() -> void {
|
||||||
|
if (saved_data_.root().get("music", Json::Value(true)).asBool()) {
|
||||||
if (boss_fight_) {
|
if (boss_fight_) {
|
||||||
music_.Resume(10);
|
music_.Resume(10);
|
||||||
boss_music_.Stop(10);
|
boss_music_.Stop(10);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
SetDelayedWork(1, [&]() -> void {
|
|
||||||
enemy_.RemoveAll();
|
|
||||||
// hud_.Hide();
|
|
||||||
SetDelayedWork(3, [&]() -> void {
|
|
||||||
wave_ = 0;
|
wave_ = 0;
|
||||||
boss_fight_ = false;
|
boss_fight_ = false;
|
||||||
EnterMenuState();
|
EnterMenuState();
|
||||||
|
@ -306,7 +325,7 @@ void Demo::UpdateMenuState(float delta_time) {
|
||||||
Engine::Get().Exit();
|
Engine::Get().Exit();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
NOTREACHED << "- Unknown menu option: " << menu_.selected_option();
|
NOTREACHED() << "- Unknown menu option: " << menu_.selected_option();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,21 +409,13 @@ void Demo::StartNextStage(bool boss) {
|
||||||
waiting_for_next_wave_ = true;
|
waiting_for_next_wave_ = true;
|
||||||
hud_.SetProgress(wave_ > 0 ? 0 : 1);
|
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;
|
<< "wave: " << wave_ << " time: " << stage_time_ / 60.0f;
|
||||||
stage_time_ = 0;
|
stage_time_ = 0;
|
||||||
|
|
||||||
enemy_.PauseProgress();
|
enemy_.PauseProgress();
|
||||||
enemy_.StopAllEnemyUnits();
|
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 {
|
SetDelayedWork(1.25f, [&, boss]() -> void {
|
||||||
enemy_.KillAllEnemyUnits();
|
enemy_.KillAllEnemyUnits();
|
||||||
|
|
||||||
|
@ -414,8 +425,12 @@ void Demo::StartNextStage(bool boss) {
|
||||||
|
|
||||||
hud_.HideProgress();
|
hud_.HideProgress();
|
||||||
|
|
||||||
|
if (saved_data_.root().get("music", Json::Value(true)).asBool()) {
|
||||||
|
boss_music_.Play(true, 10);
|
||||||
|
music_.Stop(10);
|
||||||
|
}
|
||||||
boss_fight_ = true;
|
boss_fight_ = true;
|
||||||
DLOG << "Boss fight.";
|
DLOG(0) << "Boss fight.";
|
||||||
} else {
|
} else {
|
||||||
size_t bonus_factor = [&]() -> size_t {
|
size_t bonus_factor = [&]() -> size_t {
|
||||||
if (wave_ <= 3)
|
if (wave_ <= 3)
|
||||||
|
@ -427,7 +442,7 @@ void Demo::StartNextStage(bool boss) {
|
||||||
return 100;
|
return 100;
|
||||||
}();
|
}();
|
||||||
size_t bonus_score = wave_score_ * (bonus_factor - 1);
|
size_t bonus_score = wave_score_ * (bonus_factor - 1);
|
||||||
DLOG << "total_score_" << total_score_ << " wave " << wave_
|
DLOG(0) << "total_score_" << total_score_ << " wave " << wave_
|
||||||
<< " score: " << wave_score_ << " bonus: " << bonus_score;
|
<< " score: " << wave_score_ << " bonus: " << bonus_score;
|
||||||
|
|
||||||
if (bonus_score > 0) {
|
if (bonus_score > 0) {
|
||||||
|
@ -456,13 +471,18 @@ void Demo::StartNextStage(bool boss) {
|
||||||
hud_.Show();
|
hud_.Show();
|
||||||
hud_.SetProgress(1);
|
hud_.SetProgress(1);
|
||||||
|
|
||||||
if (boss_fight_)
|
if (boss_fight_) {
|
||||||
player_.TakeDamage(-1);
|
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;
|
total_enemies_ = 23.0897f * log((float)wave_ + 1.0f) - 10.0f;
|
||||||
last_num_enemies_killed_ = 0;
|
last_num_enemies_killed_ = 0;
|
||||||
boss_fight_ = false;
|
boss_fight_ = false;
|
||||||
DLOG << "wave: " << wave_ << " total_enemies_: " << total_enemies_;
|
DLOG(0) << "wave: " << wave_ << " total_enemies_: " << total_enemies_;
|
||||||
}
|
}
|
||||||
|
|
||||||
hud_.SetScore(total_score_, true);
|
hud_.SetScore(total_score_, true);
|
||||||
|
@ -513,7 +533,7 @@ void Demo::SetDelayedWork(float seconds, base::Closure cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Demo::BenchmarkResult(int avarage_fps) {
|
void Demo::BenchmarkResult(int avarage_fps) {
|
||||||
LOG << __func__ << " avarage_fps: " << avarage_fps;
|
LOG(0) << __func__ << " avarage_fps: " << avarage_fps;
|
||||||
if (avarage_fps < 30)
|
if (avarage_fps < 30)
|
||||||
sky_.Create(true);
|
sky_.Create(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include "base/closure.h"
|
#include "base/closure.h"
|
||||||
#include "engine/animator.h"
|
#include "engine/animator.h"
|
||||||
#include "engine/font.h"
|
#include "engine/asset/font.h"
|
||||||
#include "engine/game.h"
|
#include "engine/game.h"
|
||||||
#include "engine/persistent_data.h"
|
#include "engine/persistent_data.h"
|
||||||
#include "engine/solid_quad.h"
|
#include "engine/solid_quad.h"
|
||||||
|
@ -23,14 +23,12 @@ class Demo final : public eng::Game {
|
||||||
Demo();
|
Demo();
|
||||||
~Demo() final;
|
~Demo() final;
|
||||||
|
|
||||||
|
// Game interface
|
||||||
|
bool PreInitialize() final;
|
||||||
bool Initialize() final;
|
bool Initialize() final;
|
||||||
|
|
||||||
void Update(float delta_time) final;
|
void Update(float delta_time) final;
|
||||||
|
|
||||||
void ContextLost() final;
|
void ContextLost() final;
|
||||||
|
|
||||||
void LostFocus() final;
|
void LostFocus() final;
|
||||||
|
|
||||||
void GainedFocus(bool from_interstitial_ad) final;
|
void GainedFocus(bool from_interstitial_ad) final;
|
||||||
|
|
||||||
void AddScore(size_t score);
|
void AddScore(size_t score);
|
||||||
|
|
|
@ -9,13 +9,10 @@
|
||||||
#include "base/collusion_test.h"
|
#include "base/collusion_test.h"
|
||||||
#include "base/interpolation.h"
|
#include "base/interpolation.h"
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
|
#include "engine/asset/font.h"
|
||||||
|
#include "engine/asset/image.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/font.h"
|
|
||||||
#include "engine/image.h"
|
|
||||||
#include "engine/renderer/geometry.h"
|
#include "engine/renderer/geometry.h"
|
||||||
#include "engine/renderer/shader.h"
|
|
||||||
#include "engine/shader_source.h"
|
|
||||||
#include "engine/sound.h"
|
|
||||||
|
|
||||||
#include "demo/demo.h"
|
#include "demo/demo.h"
|
||||||
|
|
||||||
|
@ -76,51 +73,54 @@ float SnapSpawnPosX(int col) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Enemy::Enemy()
|
Enemy::Enemy() = default;
|
||||||
: chromatic_aberration_(Engine::Get().CreateRenderResource<Shader>()) {}
|
|
||||||
|
|
||||||
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() {
|
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_.SetZOrder(10);
|
||||||
boss_animator_.Attach(&boss_);
|
boss_animator_.Attach(&boss_);
|
||||||
|
|
||||||
boss_intro_.SetSound(boss_intro_sound_);
|
boss_intro_.SetSound("boss_intro");
|
||||||
boss_intro_.SetVariate(false);
|
boss_intro_.SetVariate(false);
|
||||||
boss_intro_.SetSimulateStereo(false);
|
boss_intro_.SetSimulateStereo(false);
|
||||||
|
|
||||||
|
@ -205,10 +205,6 @@ void Enemy::Pause(bool pause) {
|
||||||
boss_animator_.PauseOrResumeAll(pause);
|
boss_animator_.PauseOrResumeAll(pause);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Enemy::ContextLost() {
|
|
||||||
CreateShaders();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Enemy::HasTarget(DamageType damage_type) {
|
bool Enemy::HasTarget(DamageType damage_type) {
|
||||||
DCHECK(damage_type > kDamageType_Invalid && damage_type < kDamageType_Any);
|
DCHECK(damage_type > kDamageType_Invalid && damage_type < kDamageType_Any);
|
||||||
|
|
||||||
|
@ -357,8 +353,8 @@ void Enemy::HitTarget(DamageType damage_type) {
|
||||||
|
|
||||||
if (target->damage_type != kDamageType_Any &&
|
if (target->damage_type != kDamageType_Any &&
|
||||||
target->damage_type != damage_type) {
|
target->damage_type != damage_type) {
|
||||||
// No shield until wave 4.
|
// No shield until wave 8.
|
||||||
if (wave_ <= 3)
|
if (wave_ <= 8)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!target->shield_active) {
|
if (!target->shield_active) {
|
||||||
|
@ -423,7 +419,7 @@ void Enemy::StopAllEnemyUnits(bool chromatic_aberration_effect) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (chromatic_aberration_effect) {
|
if (chromatic_aberration_effect) {
|
||||||
e.sprite.SetCustomShader(chromatic_aberration_.get());
|
e.sprite.SetCustomShader("chromatic_aberration");
|
||||||
e.chromatic_aberration_active_ = true;
|
e.chromatic_aberration_active_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,7 +516,7 @@ void Enemy::OnWaveStarted(int wave, bool boss_fight) {
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
return 1.6f;
|
return 1.6f;
|
||||||
}();
|
}();
|
||||||
DLOG << "boss_spawn_time_factor_: " << boss_spawn_time_factor_;
|
DLOG(0) << "boss_spawn_time_factor_: " << boss_spawn_time_factor_;
|
||||||
SpawnBoss();
|
SpawnBoss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -611,7 +607,7 @@ void Enemy::SpawnUnit(EnemyType enemy_type,
|
||||||
e.sprite.Create("crate_tex", {8, 3});
|
e.sprite.Create("crate_tex", {8, 3});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
NOTREACHED << "- Unkown enemy type: " << enemy_type;
|
NOTREACHED() << "- Unkown enemy type: " << enemy_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.sprite.SetZOrder(11);
|
e.sprite.SetZOrder(11);
|
||||||
|
@ -657,11 +653,13 @@ void Enemy::SpawnUnit(EnemyType enemy_type,
|
||||||
e.health_bar.PlaceToBottomOf(e.sprite);
|
e.health_bar.PlaceToBottomOf(e.sprite);
|
||||||
e.health_bar.SetColor({0.161f, 0.89f, 0.322f, 1});
|
e.health_bar.SetColor({0.161f, 0.89f, 0.322f, 1});
|
||||||
|
|
||||||
|
if (enemy_type != kEnemyType_PowerUp) {
|
||||||
e.score.Create("score_tex"s + std::to_string(e.enemy_type));
|
e.score.Create("score_tex"s + std::to_string(e.enemy_type));
|
||||||
e.score.SetZOrder(12);
|
e.score.SetZOrder(12);
|
||||||
e.score.Scale(1.1f);
|
e.score.Scale(1.1f);
|
||||||
e.score.SetColor({1, 1, 1, 1});
|
e.score.SetColor({1, 1, 1, 1});
|
||||||
e.score.SetPosition(spawn_pos);
|
e.score.SetPosition(spawn_pos);
|
||||||
|
}
|
||||||
|
|
||||||
e.target_animator.Attach(&e.target);
|
e.target_animator.Attach(&e.target);
|
||||||
|
|
||||||
|
@ -736,32 +734,32 @@ void Enemy::SpawnUnit(EnemyType enemy_type,
|
||||||
e.movement_animator.Play(Animator::kMovement, false);
|
e.movement_animator.Play(Animator::kMovement, false);
|
||||||
|
|
||||||
if (e.enemy_type == kEnemyType_PowerUp) {
|
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.SetSound("powerup-spawn");
|
||||||
e.spawn.SetMaxAplitude(2.0f);
|
e.spawn.SetMaxAmplitude(2.0f);
|
||||||
e.spawn.Play(false);
|
e.spawn.Play(false);
|
||||||
} else {
|
} else {
|
||||||
e.explosion.SetSound(explosion_sound_);
|
e.explosion.SetSound("explosion");
|
||||||
e.explosion.SetVariate(true);
|
e.explosion.SetVariate(true);
|
||||||
e.explosion.SetSimulateStereo(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.SetVariate(false);
|
||||||
e.stealth.SetSimulateStereo(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.SetVariate(false);
|
||||||
e.shield_on.SetSimulateStereo(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.SetVariate(true);
|
||||||
e.hit.SetSimulateStereo(false);
|
e.hit.SetSimulateStereo(false);
|
||||||
e.hit.SetMaxAplitude(0.5f);
|
e.hit.SetMaxAmplitude(0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Enemy::SpawnBoss() {
|
void Enemy::SpawnBoss() {
|
||||||
|
@ -788,7 +786,7 @@ void Enemy::SpawnBoss() {
|
||||||
e.enemy_type = kEnemyType_Boss;
|
e.enemy_type = kEnemyType_Boss;
|
||||||
e.damage_type = kDamageType_Any;
|
e.damage_type = kDamageType_Any;
|
||||||
e.total_health = e.hit_points = 41.1283f * log((float)game->wave()) - 20.0f;
|
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 =
|
Vector2f hit_box_pos =
|
||||||
boss_.GetPosition() - boss_.GetSize() * Vector2f(0, 0.2f);
|
boss_.GetPosition() - boss_.GetSize() * Vector2f(0, 0.2f);
|
||||||
|
@ -832,14 +830,14 @@ void Enemy::SpawnBoss() {
|
||||||
Animator::kMovement, [&]() -> void { e.marked_for_removal = true; });
|
Animator::kMovement, [&]() -> void { e.marked_for_removal = true; });
|
||||||
e.score_animator.Attach(&e.score);
|
e.score_animator.Attach(&e.score);
|
||||||
|
|
||||||
e.explosion.SetSound(boss_explosion_sound_);
|
e.explosion.SetSound("boss_explosion");
|
||||||
e.explosion.SetVariate(false);
|
e.explosion.SetVariate(false);
|
||||||
e.explosion.SetSimulateStereo(false);
|
e.explosion.SetSimulateStereo(false);
|
||||||
|
|
||||||
e.hit.SetSound(hit_sound_);
|
e.hit.SetSound("hit");
|
||||||
e.hit.SetVariate(true);
|
e.hit.SetVariate(true);
|
||||||
e.hit.SetSimulateStereo(false);
|
e.hit.SetSimulateStereo(false);
|
||||||
e.hit.SetMaxAplitude(0.5f);
|
e.hit.SetMaxAmplitude(0.5f);
|
||||||
});
|
});
|
||||||
boss_animator_.Play(Animator::kFrames, true);
|
boss_animator_.Play(Animator::kFrames, true);
|
||||||
boss_animator_.Play(Animator::kMovement, false);
|
boss_animator_.Play(Animator::kMovement, false);
|
||||||
|
@ -1174,11 +1172,7 @@ int Enemy::GetScore(EnemyType enemy_type) {
|
||||||
std::unique_ptr<Image> Enemy::GetScoreImage(EnemyType enemy_type) {
|
std::unique_ptr<Image> Enemy::GetScoreImage(EnemyType enemy_type) {
|
||||||
const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont();
|
const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont();
|
||||||
|
|
||||||
int score = GetScore(enemy_type);
|
std::string text = std::to_string(GetScore(enemy_type));
|
||||||
if (!score)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
std::string text = std::to_string(score);
|
|
||||||
int width, height;
|
int width, height;
|
||||||
font.CalculateBoundingBox(text.c_str(), width, height);
|
font.CalculateBoundingBox(text.c_str(), width, height);
|
||||||
|
|
||||||
|
@ -1192,40 +1186,6 @@ std::unique_ptr<Image> Enemy::GetScoreImage(EnemyType enemy_type) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Enemy::CreateRenderResources() {
|
|
||||||
if (!CreateShaders())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Enemy::CreateShaders() {
|
|
||||||
auto source = std::make_unique<ShaderSource>();
|
|
||||||
if (!source->Load("chromatic_aberration.glsl"))
|
|
||||||
return false;
|
|
||||||
chromatic_aberration_->Create(std::move(source),
|
|
||||||
Engine::Get().GetQuad()->vertex_description(),
|
|
||||||
Engine::Get().GetQuad()->primitive(), false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Enemy::TranslateEnemyUnit(EnemyUnit& e, const Vector2f& delta) {
|
void Enemy::TranslateEnemyUnit(EnemyUnit& e, const Vector2f& delta) {
|
||||||
e.sprite.Translate(delta);
|
e.sprite.Translate(delta);
|
||||||
e.target.Translate(delta);
|
e.target.Translate(delta);
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
class Image;
|
class Image;
|
||||||
class Shader;
|
|
||||||
class Sound;
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
||||||
class Enemy {
|
class Enemy {
|
||||||
|
@ -24,14 +22,13 @@ class Enemy {
|
||||||
Enemy();
|
Enemy();
|
||||||
~Enemy();
|
~Enemy();
|
||||||
|
|
||||||
|
bool PreInitialize();
|
||||||
bool Initialize();
|
bool Initialize();
|
||||||
|
|
||||||
void Update(float delta_time);
|
void Update(float delta_time);
|
||||||
|
|
||||||
void Pause(bool pause);
|
void Pause(bool pause);
|
||||||
|
|
||||||
void ContextLost();
|
|
||||||
|
|
||||||
bool HasTarget(DamageType damage_type);
|
bool HasTarget(DamageType damage_type);
|
||||||
base::Vector2f GetTargetPos(DamageType damage_type);
|
base::Vector2f GetTargetPos(DamageType damage_type);
|
||||||
|
|
||||||
|
@ -106,22 +103,12 @@ class Enemy {
|
||||||
eng::SoundPlayer hit;
|
eng::SoundPlayer hit;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<eng::Shader> chromatic_aberration_;
|
|
||||||
float chromatic_aberration_offset_ = 0;
|
float chromatic_aberration_offset_ = 0;
|
||||||
|
|
||||||
eng::ImageQuad boss_;
|
eng::ImageQuad boss_;
|
||||||
eng::Animator boss_animator_;
|
eng::Animator boss_animator_;
|
||||||
eng::SoundPlayer boss_intro_;
|
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_;
|
std::list<EnemyUnit> enemies_;
|
||||||
|
|
||||||
int num_enemies_killed_in_current_wave_ = 0;
|
int num_enemies_killed_in_current_wave_ = 0;
|
||||||
|
@ -168,9 +155,6 @@ class Enemy {
|
||||||
|
|
||||||
std::unique_ptr<eng::Image> GetScoreImage(EnemyType enemy_type);
|
std::unique_ptr<eng::Image> GetScoreImage(EnemyType enemy_type);
|
||||||
|
|
||||||
bool CreateRenderResources();
|
|
||||||
bool CreateShaders();
|
|
||||||
|
|
||||||
void TranslateEnemyUnit(EnemyUnit& e, const base::Vector2f& delta);
|
void TranslateEnemyUnit(EnemyUnit& e, const base::Vector2f& delta);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
#include "base/interpolation.h"
|
#include "base/interpolation.h"
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "base/vecmath.h"
|
#include "base/vecmath.h"
|
||||||
|
#include "engine/asset/font.h"
|
||||||
|
#include "engine/asset/image.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/font.h"
|
|
||||||
#include "engine/image.h"
|
|
||||||
|
|
||||||
#include "demo/demo.h"
|
#include "demo/demo.h"
|
||||||
|
|
||||||
|
@ -198,7 +198,6 @@ void Hud::ShowMessage(const std::string& text, float duration) {
|
||||||
message_text_ = text;
|
message_text_ = text;
|
||||||
Engine::Get().RefreshImage("message");
|
Engine::Get().RefreshImage("message");
|
||||||
|
|
||||||
message_.AutoScale();
|
|
||||||
message_.Scale(1.5f);
|
message_.Scale(1.5f);
|
||||||
message_.SetColor({1, 1, 1, 0});
|
message_.SetColor({1, 1, 1, 0});
|
||||||
message_.SetVisible(true);
|
message_.SetVisible(true);
|
||||||
|
@ -215,7 +214,6 @@ void Hud::ShowMessage(const std::string& text, float duration) {
|
||||||
void Hud::ShowBonus(size_t bonus) {
|
void Hud::ShowBonus(size_t bonus) {
|
||||||
bonus_score_ = bonus;
|
bonus_score_ = bonus;
|
||||||
Engine::Get().RefreshImage("bonus_tex");
|
Engine::Get().RefreshImage("bonus_tex");
|
||||||
bonus_.AutoScale();
|
|
||||||
bonus_.Scale(1.3f);
|
bonus_.Scale(1.3f);
|
||||||
bonus_.SetColor({1, 1, 1, 1});
|
bonus_.SetColor({1, 1, 1, 1});
|
||||||
bonus_.SetVisible(true);
|
bonus_.SetVisible(true);
|
||||||
|
@ -245,26 +243,20 @@ std::unique_ptr<Image> Hud::CreateMessageImage() {
|
||||||
font.Print(x, 0, message_text_.c_str(), image->GetBuffer(),
|
font.Print(x, 0, message_text_.c_str(), image->GetBuffer(),
|
||||||
image->GetWidth());
|
image->GetWidth());
|
||||||
image->Compress();
|
image->Compress();
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Image> Hud::CreateBonusImage() {
|
std::unique_ptr<Image> Hud::CreateBonusImage() {
|
||||||
const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont();
|
const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont();
|
||||||
|
|
||||||
if (bonus_score_ == 0)
|
auto image = CreateImage();
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
std::string text = std::to_string(bonus_score_);
|
std::string text = std::to_string(bonus_score_);
|
||||||
int width, height;
|
int w, h;
|
||||||
font.CalculateBoundingBox(text.c_str(), width, height);
|
font.CalculateBoundingBox(text.c_str(), w, h);
|
||||||
|
float x = (image->GetWidth() - w) / 2;
|
||||||
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());
|
|
||||||
|
|
||||||
|
font.Print(x, 0, text.c_str(), image->GetBuffer(), image->GetWidth());
|
||||||
image->Compress();
|
image->Compress();
|
||||||
return image;
|
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());
|
font.Print(x, 0, text.c_str(), image->GetBuffer(), image->GetWidth());
|
||||||
|
image->Compress();
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
167
src/demo/menu.cc
|
@ -7,11 +7,12 @@
|
||||||
#include "base/collusion_test.h"
|
#include "base/collusion_test.h"
|
||||||
#include "base/interpolation.h"
|
#include "base/interpolation.h"
|
||||||
#include "base/log.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/engine.h"
|
||||||
#include "engine/font.h"
|
|
||||||
#include "engine/image.h"
|
|
||||||
#include "engine/input_event.h"
|
#include "engine/input_event.h"
|
||||||
#include "engine/sound.h"
|
#include "engine/renderer/renderer.h"
|
||||||
|
|
||||||
#include "demo/demo.h"
|
#include "demo/demo.h"
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ using namespace eng;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr char kVersionStr[] = "Version 1.0.2";
|
constexpr char kVersionStr[] = "Version 1.0.4";
|
||||||
|
|
||||||
constexpr char kMenuOption[Menu::kOption_Max][10] = {"continue", "start",
|
constexpr char kMenuOption[Menu::kOption_Max][10] = {"continue", "start",
|
||||||
"credits", "exit"};
|
"credits", "exit"};
|
||||||
|
@ -33,9 +34,10 @@ const Vector4f kColorNormal = {1, 1, 1, 1};
|
||||||
const Vector4f kColorHighlight = {20, 20, 20, 1};
|
const Vector4f kColorHighlight = {20, 20, 20, 1};
|
||||||
constexpr float kBlendingSpeed = 0.12f;
|
constexpr float kBlendingSpeed = 0.12f;
|
||||||
|
|
||||||
const Vector4f kColorSwitch[2] = {{0.003f, 0.91f, 0.99f, 1},
|
const std::array<Vector4f, 2> kColorSwitch = {Vector4f{0.003f, 0.91f, 0.99f, 1},
|
||||||
{0.33f, 0.47, 0.51f, 1}};
|
Vector4f{0.33f, 0.47, 0.51f, 1}};
|
||||||
|
|
||||||
|
const Vector4f kColorFadeIn = {1, 1, 1, 1};
|
||||||
const Vector4f kColorFadeOut = {1, 1, 1, 0};
|
const Vector4f kColorFadeOut = {1, 1, 1, 0};
|
||||||
constexpr float kFadeSpeed = 0.2f;
|
constexpr float kFadeSpeed = 0.2f;
|
||||||
|
|
||||||
|
@ -51,9 +53,9 @@ Menu::Menu() = default;
|
||||||
|
|
||||||
Menu::~Menu() = default;
|
Menu::~Menu() = default;
|
||||||
|
|
||||||
bool Menu::Initialize() {
|
bool Menu::PreInitialize() {
|
||||||
click_sound_ = std::make_shared<Sound>();
|
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;
|
return false;
|
||||||
|
|
||||||
Demo* game = static_cast<Demo*>(Engine::Get().GetGame());
|
Demo* game = static_cast<Demo*>(Engine::Get().GetGame());
|
||||||
|
@ -68,8 +70,59 @@ bool Menu::Initialize() {
|
||||||
max_text_width_ = width;
|
max_text_width_ = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CreateRenderResources())
|
Engine::Get().SetImageSource("menu_tex",
|
||||||
return false;
|
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) {
|
for (int i = 0; i < kOption_Max; ++i) {
|
||||||
items_[i].text.Create("menu_tex", {1, 4});
|
items_[i].text.Create("menu_tex", {1, 4});
|
||||||
|
@ -96,7 +149,7 @@ bool Menu::Initialize() {
|
||||||
click_.SetSound(click_sound_);
|
click_.SetSound(click_sound_);
|
||||||
click_.SetVariate(false);
|
click_.SetVariate(false);
|
||||||
click_.SetSimulateStereo(false);
|
click_.SetSimulateStereo(false);
|
||||||
click_.SetMaxAplitude(1.5f);
|
click_.SetMaxAmplitude(1.5f);
|
||||||
|
|
||||||
logo_[0].Create("logo_tex0", {3, 8});
|
logo_[0].Create("logo_tex0", {3, 8});
|
||||||
logo_[0].SetZOrder(41);
|
logo_[0].SetZOrder(41);
|
||||||
|
@ -150,7 +203,8 @@ bool Menu::Initialize() {
|
||||||
}
|
}
|
||||||
game->saved_data().root()["audio"] = toggle_audio_.enabled();
|
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() *
|
toggle_audio_.image().SetPosition(Engine::Get().GetScreenSize() *
|
||||||
Vector2f(0, -0.25f));
|
Vector2f(0, -0.25f));
|
||||||
toggle_audio_.image().Scale(0.7f);
|
toggle_audio_.image().Scale(0.7f);
|
||||||
|
@ -162,7 +216,8 @@ bool Menu::Initialize() {
|
||||||
game->SetEnableMusic(toggle_music_.enabled());
|
game->SetEnableMusic(toggle_music_.enabled());
|
||||||
game->saved_data().root()["music"] = 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() *
|
toggle_music_.image().SetPosition(Engine::Get().GetScreenSize() *
|
||||||
Vector2f(0, -0.25f));
|
Vector2f(0, -0.25f));
|
||||||
toggle_music_.image().Scale(0.7f);
|
toggle_music_.image().Scale(0.7f);
|
||||||
|
@ -177,7 +232,8 @@ bool Menu::Initialize() {
|
||||||
game->saved_data().root()["vibration"] = toggle_vibration_.enabled();
|
game->saved_data().root()["vibration"] = toggle_vibration_.enabled();
|
||||||
},
|
},
|
||||||
true,
|
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() *
|
toggle_vibration_.image().SetPosition(Engine::Get().GetScreenSize() *
|
||||||
Vector2f(0, -0.25f));
|
Vector2f(0, -0.25f));
|
||||||
toggle_vibration_.image().Scale(0.7f);
|
toggle_vibration_.image().Scale(0.7f);
|
||||||
|
@ -188,6 +244,19 @@ bool Menu::Initialize() {
|
||||||
toggle_vibration_.image().Translate(
|
toggle_vibration_.image().Translate(
|
||||||
{toggle_music_.image().GetSize().x / 2, 0});
|
{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_value_ = game->GetHighScore();
|
||||||
|
|
||||||
high_score_.Create("high_score_tex");
|
high_score_.Create("high_score_tex");
|
||||||
|
@ -226,7 +295,7 @@ bool Menu::Initialize() {
|
||||||
starting_wave_.image().SetFrame(start_from_wave_ / 3);
|
starting_wave_.image().SetFrame(start_from_wave_ / 3);
|
||||||
click_.Play(false);
|
click_.Play(false);
|
||||||
},
|
},
|
||||||
false, true);
|
false, true, kColorFadeOut, kColorSwitch);
|
||||||
wave_up_.image().Scale(1.5f);
|
wave_up_.image().Scale(1.5f);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -236,6 +305,7 @@ void Menu::OnInputEvent(std::unique_ptr<InputEvent> event) {
|
||||||
if (toggle_audio_.OnInputEvent(event.get()) ||
|
if (toggle_audio_.OnInputEvent(event.get()) ||
|
||||||
toggle_music_.OnInputEvent(event.get()) ||
|
toggle_music_.OnInputEvent(event.get()) ||
|
||||||
toggle_vibration_.OnInputEvent(event.get()) ||
|
toggle_vibration_.OnInputEvent(event.get()) ||
|
||||||
|
renderer_type_.OnInputEvent(event.get()) ||
|
||||||
(wave_up_.image().IsVisible() && wave_up_.OnInputEvent(event.get())))
|
(wave_up_.image().IsVisible() && wave_up_.OnInputEvent(event.get())))
|
||||||
return;
|
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() {
|
void Menu::Show() {
|
||||||
logo_[1].SetColor(kColorNormal);
|
logo_[1].SetColor(kColorNormal);
|
||||||
logo_animator_[0].SetVisible(true);
|
logo_animator_[0].SetVisible(true);
|
||||||
|
@ -350,6 +425,7 @@ void Menu::Show() {
|
||||||
toggle_audio_.Show();
|
toggle_audio_.Show();
|
||||||
toggle_music_.Show();
|
toggle_music_.Show();
|
||||||
toggle_vibration_.Show();
|
toggle_vibration_.Show();
|
||||||
|
renderer_type_.Show();
|
||||||
|
|
||||||
Demo* game = static_cast<Demo*>(Engine::Get().GetGame());
|
Demo* game = static_cast<Demo*>(Engine::Get().GetGame());
|
||||||
|
|
||||||
|
@ -410,6 +486,7 @@ void Menu::Hide(Closure cb) {
|
||||||
toggle_audio_.Hide();
|
toggle_audio_.Hide();
|
||||||
toggle_music_.Hide();
|
toggle_music_.Hide();
|
||||||
toggle_vibration_.Hide();
|
toggle_vibration_.Hide();
|
||||||
|
renderer_type_.Hide();
|
||||||
|
|
||||||
if (starting_wave_.image().IsVisible()) {
|
if (starting_wave_.image().IsVisible()) {
|
||||||
starting_wave_.Hide();
|
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() {
|
std::unique_ptr<Image> Menu::CreateMenuImage() {
|
||||||
const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont();
|
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,
|
int frame2,
|
||||||
Closure pressed_cb,
|
Closure pressed_cb,
|
||||||
bool switch_control,
|
bool switch_control,
|
||||||
bool enabled) {
|
bool enabled,
|
||||||
|
const Vector4f& fade_out_color,
|
||||||
|
const std::array<Vector4f, 2>& switch_color) {
|
||||||
frame1_ = frame1;
|
frame1_ = frame1;
|
||||||
frame2_ = frame2;
|
frame2_ = frame2;
|
||||||
pressed_cb_ = std::move(pressed_cb);
|
pressed_cb_ = std::move(pressed_cb);
|
||||||
switch_control_ = switch_control;
|
switch_control_ = switch_control;
|
||||||
enabled_ = enabled;
|
enabled_ = enabled;
|
||||||
|
fade_out_color_ = fade_out_color;
|
||||||
|
switch_color_ = switch_color;
|
||||||
|
|
||||||
image_.Create(asset_name, num_frames);
|
image_.Create(asset_name, num_frames);
|
||||||
image_.SetFrame(enabled ? frame1 : frame2);
|
image_.SetFrame(enabled ? frame1 : frame2);
|
||||||
image_.SetColor(kColorFadeOut);
|
image_.SetColor(fade_out_color_);
|
||||||
image_.SetZOrder(41);
|
image_.SetZOrder(41);
|
||||||
image_.SetVisible(false);
|
image_.SetVisible(false);
|
||||||
|
|
||||||
|
@ -562,14 +597,14 @@ bool Menu::Button::OnInputEvent(eng::InputEvent* event) {
|
||||||
|
|
||||||
void Menu::Button::Show() {
|
void Menu::Button::Show() {
|
||||||
animator_.SetVisible(true);
|
animator_.SetVisible(true);
|
||||||
animator_.SetBlending(enabled_ ? kColorSwitch[0] : kColorSwitch[1],
|
animator_.SetBlending(enabled_ ? switch_color_[0] : switch_color_[1],
|
||||||
kBlendingSpeed);
|
kBlendingSpeed);
|
||||||
animator_.Play(Animator::kBlending, false);
|
animator_.Play(Animator::kBlending, false);
|
||||||
animator_.SetEndCallback(Animator::kBlending, nullptr);
|
animator_.SetEndCallback(Animator::kBlending, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::Button::Hide() {
|
void Menu::Button::Hide() {
|
||||||
animator_.SetBlending(kColorFadeOut, kBlendingSpeed);
|
animator_.SetBlending(fade_out_color_, kBlendingSpeed);
|
||||||
animator_.Play(Animator::kBlending, false);
|
animator_.Play(Animator::kBlending, false);
|
||||||
animator_.SetEndCallback(Animator::kBlending,
|
animator_.SetEndCallback(Animator::kBlending,
|
||||||
[&]() -> void { animator_.SetVisible(false); });
|
[&]() -> void { animator_.SetVisible(false); });
|
||||||
|
@ -579,7 +614,7 @@ void Menu::Button::SetEnabled(bool enable) {
|
||||||
if (switch_control_) {
|
if (switch_control_) {
|
||||||
enabled_ = enable;
|
enabled_ = enable;
|
||||||
image_.SetFrame(enabled_ ? frame1_ : frame2_);
|
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();
|
||||||
~Menu();
|
~Menu();
|
||||||
|
|
||||||
|
bool PreInitialize();
|
||||||
bool Initialize();
|
bool Initialize();
|
||||||
|
|
||||||
void OnInputEvent(std::unique_ptr<eng::InputEvent> event);
|
void OnInputEvent(std::unique_ptr<eng::InputEvent> event);
|
||||||
|
|
||||||
void SetOptionEnabled(Option o, bool enable);
|
void SetOptionEnabled(Option o, bool enable);
|
||||||
|
void SetRendererType();
|
||||||
|
|
||||||
void Show();
|
void Show();
|
||||||
void Hide(base::Closure cb = nullptr);
|
void Hide(base::Closure cb = nullptr);
|
||||||
|
@ -55,13 +57,17 @@ class Menu {
|
||||||
int frame2,
|
int frame2,
|
||||||
base::Closure pressed_cb,
|
base::Closure pressed_cb,
|
||||||
bool switch_control,
|
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);
|
bool OnInputEvent(eng::InputEvent* event);
|
||||||
|
|
||||||
void Show();
|
void Show();
|
||||||
void Hide();
|
void Hide();
|
||||||
|
|
||||||
|
void SetEnabled(bool enable);
|
||||||
|
|
||||||
eng::ImageQuad& image() { return image_; };
|
eng::ImageQuad& image() { return image_; };
|
||||||
|
|
||||||
bool enabled() const { return enabled_; }
|
bool enabled() const { return enabled_; }
|
||||||
|
@ -77,7 +83,8 @@ class Menu {
|
||||||
bool enabled_ = false;
|
bool enabled_ = false;
|
||||||
base::Vector2f tap_pos_[2] = {{0, 0}, {0, 0}};
|
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 {
|
class Radio {
|
||||||
|
@ -126,6 +133,7 @@ class Menu {
|
||||||
Button toggle_audio_;
|
Button toggle_audio_;
|
||||||
Button toggle_music_;
|
Button toggle_music_;
|
||||||
Button toggle_vibration_;
|
Button toggle_vibration_;
|
||||||
|
Button renderer_type_;
|
||||||
|
|
||||||
size_t high_score_value_ = 0;
|
size_t high_score_value_ = 0;
|
||||||
|
|
||||||
|
@ -139,9 +147,6 @@ class Menu {
|
||||||
|
|
||||||
Radio starting_wave_;
|
Radio starting_wave_;
|
||||||
Button wave_up_;
|
Button wave_up_;
|
||||||
Button wave_down_;
|
|
||||||
|
|
||||||
bool CreateRenderResources();
|
|
||||||
|
|
||||||
std::unique_ptr<eng::Image> CreateMenuImage();
|
std::unique_ptr<eng::Image> CreateMenuImage();
|
||||||
std::unique_ptr<eng::Image> CreateHighScoreImage();
|
std::unique_ptr<eng::Image> CreateHighScoreImage();
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
#include "base/interpolation.h"
|
#include "base/interpolation.h"
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
|
#include "base/vecmath.h"
|
||||||
|
#include "engine/asset/font.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/font.h"
|
|
||||||
#include "engine/input_event.h"
|
#include "engine/input_event.h"
|
||||||
#include "engine/sound.h"
|
|
||||||
|
|
||||||
#include "demo/demo.h"
|
#include "demo/demo.h"
|
||||||
|
|
||||||
|
@ -29,22 +29,21 @@ Player::Player() = default;
|
||||||
|
|
||||||
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() {
|
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();
|
SetupWeapons();
|
||||||
|
|
||||||
Vector2f hb_pos = Engine::Get().GetScreenSize() / Vector2f(2, -2) +
|
Vector2f hb_pos = Engine::Get().GetScreenSize() / Vector2f(2, -2) +
|
||||||
|
@ -75,12 +74,12 @@ bool Player::Initialize() {
|
||||||
|
|
||||||
nuke_symbol_animator_.Attach(&nuke_symbol_);
|
nuke_symbol_animator_.Attach(&nuke_symbol_);
|
||||||
|
|
||||||
nuke_explosion_.SetSound(nuke_explosion_sound_);
|
nuke_explosion_.SetSound("nuke");
|
||||||
nuke_explosion_.SetVariate(false);
|
nuke_explosion_.SetVariate(false);
|
||||||
nuke_explosion_.SetSimulateStereo(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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -153,7 +152,7 @@ void Player::AddNuke(int n) {
|
||||||
|
|
||||||
if (!nuke_symbol_animator_.IsPlaying(Animator::kRotation)) {
|
if (!nuke_symbol_animator_.IsPlaying(Animator::kRotation)) {
|
||||||
nuke_symbol_animator_.SetRotation(
|
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);
|
nuke_symbol_animator_.Play(Animator::kRotation, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,7 +222,7 @@ void Player::Fire(DamageType type, Vector2f dir) {
|
||||||
|
|
||||||
dir.Normalize();
|
dir.Normalize();
|
||||||
float cos_theta = dir.DotProduct(Vector2f(1, 0));
|
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);
|
beam_[type].SetTheta(theta);
|
||||||
auto offset = beam_[type].GetRotation() * (len / 2);
|
auto offset = beam_[type].GetRotation() * (len / 2);
|
||||||
beam_[type].Translate({offset.y, -offset.x});
|
beam_[type].Translate({offset.y, -offset.x});
|
||||||
|
@ -288,7 +287,7 @@ void Player::SetupWeapons() {
|
||||||
|
|
||||||
weapon_[i].SetFrame(wepon_warmup_frame[i]);
|
weapon_[i].SetFrame(wepon_warmup_frame[i]);
|
||||||
warmup_animator_[i].SetFrames(wepon_warmup_frame_count, wepon_anim_speed);
|
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].Attach(&weapon_[i]);
|
||||||
warmup_animator_[i].Play(Animator::kRotation, true);
|
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].SetBlending({1, 1, 1, 0}, 0.16f);
|
||||||
beam_animator_[i].Attach(&beam_[i]);
|
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].SetVariate(true);
|
||||||
laser_shot_[i].SetSimulateStereo(false);
|
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();
|
Engine& engine = Engine::Get();
|
||||||
static_cast<Demo*>(engine.GetGame())->EnterMenuState();
|
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 {
|
namespace eng {
|
||||||
class InputEvent;
|
class InputEvent;
|
||||||
class Sound;
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
||||||
class Player {
|
class Player {
|
||||||
|
@ -21,6 +20,7 @@ class Player {
|
||||||
Player();
|
Player();
|
||||||
~Player();
|
~Player();
|
||||||
|
|
||||||
|
bool PreInitialize();
|
||||||
bool Initialize();
|
bool Initialize();
|
||||||
|
|
||||||
void Update(float delta_time);
|
void Update(float delta_time);
|
||||||
|
@ -41,10 +41,6 @@ class Player {
|
||||||
int nuke_count() { return nuke_count_; }
|
int nuke_count() { return nuke_count_; }
|
||||||
|
|
||||||
private:
|
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 drag_sign_[2];
|
||||||
eng::ImageQuad weapon_[2];
|
eng::ImageQuad weapon_[2];
|
||||||
eng::ImageQuad beam_[2];
|
eng::ImageQuad beam_[2];
|
||||||
|
@ -101,8 +97,6 @@ class Player {
|
||||||
bool ValidateDrag(int i);
|
bool ValidateDrag(int i);
|
||||||
|
|
||||||
void NavigateBack();
|
void NavigateBack();
|
||||||
|
|
||||||
bool CreateRenderResources();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DEMO_PLAYER_H
|
#endif // DEMO_PLAYER_H
|
||||||
|
|
|
@ -6,14 +6,12 @@
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/renderer/geometry.h"
|
#include "engine/renderer/geometry.h"
|
||||||
#include "engine/renderer/shader.h"
|
#include "engine/renderer/shader.h"
|
||||||
#include "engine/shader_source.h"
|
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
using namespace eng;
|
using namespace eng;
|
||||||
|
|
||||||
SkyQuad::SkyQuad()
|
SkyQuad::SkyQuad()
|
||||||
: shader_(Engine::Get().CreateRenderResource<Shader>()),
|
: sky_offset_{
|
||||||
sky_offset_{
|
|
||||||
0, Lerp(0.0f, 10.0f, Engine::Get().GetRandomGenerator().Rand())} {
|
0, Lerp(0.0f, 10.0f, Engine::Get().GetRandomGenerator().Rand())} {
|
||||||
last_sky_offset_ = sky_offset_;
|
last_sky_offset_ = sky_offset_;
|
||||||
}
|
}
|
||||||
|
@ -22,10 +20,9 @@ SkyQuad::~SkyQuad() = default;
|
||||||
|
|
||||||
bool SkyQuad::Create(bool without_nebula) {
|
bool SkyQuad::Create(bool without_nebula) {
|
||||||
without_nebula_ = without_nebula;
|
without_nebula_ = without_nebula;
|
||||||
if (!CreateShaders())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
scale_ = Engine::Get().GetScreenSize();
|
scale_ = Engine::Get().GetScreenSize();
|
||||||
|
shader_ =
|
||||||
|
Engine::Get().GetShader(without_nebula ? "sky_without_nebula" : "sky");
|
||||||
|
|
||||||
color_animator_.Attach(this);
|
color_animator_.Attach(this);
|
||||||
|
|
||||||
|
@ -54,10 +51,6 @@ void SkyQuad::Draw(float frame_frac) {
|
||||||
Engine::Get().GetQuad()->Draw();
|
Engine::Get().GetQuad()->Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyQuad::ContextLost() {
|
|
||||||
CreateShaders();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkyQuad::SwitchColor(const Vector4f& color) {
|
void SkyQuad::SwitchColor(const Vector4f& color) {
|
||||||
color_animator_.Pause(Animator::kBlending);
|
color_animator_.Pause(Animator::kBlending);
|
||||||
color_animator_.SetTime(Animator::kBlending, 0);
|
color_animator_.SetTime(Animator::kBlending, 0);
|
||||||
|
@ -66,17 +59,6 @@ void SkyQuad::SwitchColor(const Vector4f& color) {
|
||||||
color_animator_.Play(Animator::kBlending, false);
|
color_animator_.Play(Animator::kBlending, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkyQuad::CreateShaders() {
|
|
||||||
Engine& engine = Engine::Get();
|
|
||||||
|
|
||||||
auto source = std::make_unique<ShaderSource>();
|
|
||||||
if (!source->Load(without_nebula_ ? "sky_without_nebula.glsl" : "sky.glsl"))
|
|
||||||
return false;
|
|
||||||
shader_->Create(std::move(source), engine.GetQuad()->vertex_description(),
|
|
||||||
Engine::Get().GetQuad()->primitive(), false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkyQuad::SetSpeed(float speed) {
|
void SkyQuad::SetSpeed(float speed) {
|
||||||
speed_ = speed;
|
speed_ = speed;
|
||||||
}
|
}
|
|
@ -5,11 +5,6 @@
|
||||||
#include "engine/animatable.h"
|
#include "engine/animatable.h"
|
||||||
#include "engine/animator.h"
|
#include "engine/animator.h"
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
class Shader;
|
class Shader;
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
@ -36,8 +31,6 @@ class SkyQuad : public eng::Animatable {
|
||||||
// Drawable interface.
|
// Drawable interface.
|
||||||
void Draw(float frame_frac) final;
|
void Draw(float frame_frac) final;
|
||||||
|
|
||||||
void ContextLost();
|
|
||||||
|
|
||||||
void SwitchColor(const base::Vector4f& color);
|
void SwitchColor(const base::Vector4f& color);
|
||||||
|
|
||||||
void SetSpeed(float speed);
|
void SetSpeed(float speed);
|
||||||
|
@ -45,7 +38,7 @@ class SkyQuad : public eng::Animatable {
|
||||||
const base::Vector4f& nebula_color() { return nebula_color_; }
|
const base::Vector4f& nebula_color() { return nebula_color_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<eng::Shader> shader_;
|
eng::Shader* shader_;
|
||||||
|
|
||||||
base::Vector2f sky_offset_ = {0, 0};
|
base::Vector2f sky_offset_ = {0, 0};
|
||||||
base::Vector2f last_sky_offset_ = {0, 0};
|
base::Vector2f last_sky_offset_ = {0, 0};
|
||||||
|
@ -57,8 +50,6 @@ class SkyQuad : public eng::Animatable {
|
||||||
float speed_ = 0;
|
float speed_ = 0;
|
||||||
|
|
||||||
bool without_nebula_ = false;
|
bool without_nebula_ = false;
|
||||||
|
|
||||||
bool CreateShaders();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DEMO_SKY_QUAD_H
|
#endif // DEMO_SKY_QUAD_H
|
||||||
|
|
|
@ -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:
|
protected:
|
||||||
base::Vector2f position_ = {0, 0};
|
base::Vector2f position_ = {0, 0};
|
||||||
base::Vector2f size_ = {1, 1};
|
base::Vector2f size_ = {0, 0};
|
||||||
base::Vector2f scale_ = {1, 1};
|
base::Vector2f scale_ = {1, 1};
|
||||||
base::Vector2f rotation_ = {0, 1};
|
base::Vector2f rotation_ = {0, 1};
|
||||||
float theta_ = 0;
|
float theta_ = 0;
|
||||||
|
|
|
@ -126,10 +126,10 @@ void Animator::SetMovement(Vector2f direction,
|
||||||
a.movement_last_pos = {0, 0};
|
a.movement_last_pos = {0, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animator::SetRotation(float trget,
|
void Animator::SetRotation(float target,
|
||||||
float duration,
|
float duration,
|
||||||
Interpolator interpolator) {
|
Interpolator interpolator) {
|
||||||
rotation_target_ = trget;
|
rotation_target_ = target;
|
||||||
rotation_speed_ = 1.0f / duration;
|
rotation_speed_ = 1.0f / duration;
|
||||||
rotation_interpolator_ = std::move(interpolator);
|
rotation_interpolator_ = std::move(interpolator);
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ void Animator::SetFrames(int count,
|
||||||
frame_count_ = count;
|
frame_count_ = count;
|
||||||
frame_speed_ = (float)frames_per_second / (float)count;
|
frame_speed_ = (float)frames_per_second / (float)count;
|
||||||
for (auto& a : elements_)
|
for (auto& a : elements_)
|
||||||
a.frame_start_ = a.animatable->GetFrame();
|
a.frame_start = a.animatable->GetFrame();
|
||||||
frame_interpolator_ = std::move(interpolator);
|
frame_interpolator_ = std::move(interpolator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,66 +180,43 @@ void Animator::Update(float delta_time) {
|
||||||
UpdateAnimTime(delta_time, kFrames, frame_speed_, frame_time_, frame_cb_);
|
UpdateAnimTime(delta_time, kFrames, frame_speed_, frame_time_, frame_cb_);
|
||||||
if (play_flags_ & kTimer)
|
if (play_flags_ & kTimer)
|
||||||
UpdateAnimTime(delta_time, kTimer, timer_speed_, timer_time_, timer_cb_);
|
UpdateAnimTime(delta_time, kTimer, timer_speed_, timer_time_, timer_cb_);
|
||||||
|
|
||||||
did_evaluate_ = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animator::Evaluate(float frame_frac_time) {
|
void Animator::Evaluate(float frame_frac) {
|
||||||
did_evaluate_ = true;
|
if (play_flags_ & kMovement)
|
||||||
|
EvaluateAnimation<Vector2f, true>(
|
||||||
Vector2f pos = {0, 0};
|
frame_frac, movement_speed_, movement_time_, movement_interpolator_,
|
||||||
if (play_flags_ & kMovement) {
|
movement_direction_, [](Element& a, Vector2f pos) {
|
||||||
float time = movement_time_ + movement_speed_ * frame_frac_time;
|
|
||||||
float interpolated_time =
|
|
||||||
movement_interpolator_ ? movement_interpolator_(time) : time;
|
|
||||||
pos = base::Lerp({0, 0}, movement_direction_, interpolated_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
float theta = 0;
|
|
||||||
if (play_flags_ & kRotation) {
|
|
||||||
float time = rotation_time_ + rotation_speed_ * frame_frac_time;
|
|
||||||
float interpolated_time =
|
|
||||||
rotation_interpolator_ ? rotation_interpolator_(time) : time;
|
|
||||||
theta = base::Lerp(0.0f, rotation_target_, interpolated_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
float blending_itime = 0;
|
|
||||||
if (play_flags_ & kBlending) {
|
|
||||||
float time = blending_time_ + blending_speed_ * frame_frac_time;
|
|
||||||
blending_itime =
|
|
||||||
blending_interpolator_ ? blending_interpolator_(time) : time;
|
|
||||||
}
|
|
||||||
|
|
||||||
float frame_itime = 0;
|
|
||||||
if (play_flags_ & kFrames) {
|
|
||||||
float time = frame_time_ + frame_speed_ * frame_frac_time;
|
|
||||||
frame_itime = frame_interpolator_ ? frame_interpolator_(time) : time;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& a : elements_) {
|
|
||||||
if (play_flags_ & kMovement) {
|
|
||||||
a.animatable->Translate(pos - a.movement_last_pos);
|
a.animatable->Translate(pos - a.movement_last_pos);
|
||||||
a.movement_last_pos = pos;
|
a.movement_last_pos = pos;
|
||||||
}
|
});
|
||||||
|
|
||||||
if (play_flags_ & kRotation) {
|
if (play_flags_ & kRotation)
|
||||||
|
EvaluateAnimation<float, true>(
|
||||||
|
frame_frac, rotation_speed_, rotation_time_, rotation_interpolator_,
|
||||||
|
rotation_target_, [](Element& a, float theta) {
|
||||||
a.animatable->Rotate(theta - a.rotation_last_theta);
|
a.animatable->Rotate(theta - a.rotation_last_theta);
|
||||||
a.rotation_last_theta = theta;
|
a.rotation_last_theta = theta;
|
||||||
}
|
});
|
||||||
|
|
||||||
if (play_flags_ & kBlending) {
|
if (play_flags_ & kBlending)
|
||||||
|
EvaluateAnimation<float, false>(
|
||||||
|
frame_frac, blending_speed_, blending_time_, blending_interpolator_, {},
|
||||||
|
[&](Element& a, float interpolated_time) {
|
||||||
Vector4f blending =
|
Vector4f blending =
|
||||||
base::Lerp(a.blending_start, blending_target_, blending_itime);
|
base::Lerp(a.blending_start, blending_target_, interpolated_time);
|
||||||
a.animatable->SetColor(blending);
|
a.animatable->SetColor(blending);
|
||||||
}
|
});
|
||||||
|
|
||||||
if (play_flags_ & kFrames) {
|
if (play_flags_ & kFrames)
|
||||||
int target = a.frame_start_ + frame_count_;
|
EvaluateAnimation<float, false>(
|
||||||
int frame = base::Lerp(a.frame_start_, target, frame_itime);
|
frame_frac, frame_speed_, frame_time_, frame_interpolator_, {},
|
||||||
|
[&](Element& a, float interpolated_time) {
|
||||||
|
int target = a.frame_start + frame_count_;
|
||||||
|
int frame = base::Lerp(a.frame_start, target, interpolated_time);
|
||||||
if (frame < target)
|
if (frame < target)
|
||||||
a.animatable->SetFrame(frame);
|
a.animatable->SetFrame(frame);
|
||||||
}
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animator::UpdateAnimTime(float delta_time,
|
void Animator::UpdateAnimTime(float delta_time,
|
||||||
|
@ -252,7 +229,7 @@ void Animator::UpdateAnimTime(float delta_time,
|
||||||
if (loop_flags_ & anim) {
|
if (loop_flags_ & anim) {
|
||||||
anim_time = fmod(anim_time, 1.0f);
|
anim_time = fmod(anim_time, 1.0f);
|
||||||
} else {
|
} else {
|
||||||
if (!did_evaluate_)
|
anim_time = 1.0f;
|
||||||
Evaluate(0);
|
Evaluate(0);
|
||||||
anim_time = 0;
|
anim_time = 0;
|
||||||
play_flags_ &= ~anim;
|
play_flags_ &= ~anim;
|
||||||
|
@ -269,4 +246,24 @@ void Animator::UpdateAnimTime(float delta_time,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, bool relative>
|
||||||
|
void Animator::EvaluateAnimation(float frame_frac,
|
||||||
|
float anim_speed,
|
||||||
|
float anim_time,
|
||||||
|
Interpolator& interpolator,
|
||||||
|
T target,
|
||||||
|
ResultSetter<T> set_result) {
|
||||||
|
float time = anim_time + anim_speed * frame_frac;
|
||||||
|
float interpolated_time = interpolator ? interpolator(time) : time;
|
||||||
|
|
||||||
|
if constexpr (relative) {
|
||||||
|
T result = base::Lerp(T{0}, target, interpolated_time);
|
||||||
|
for (auto& a : elements_)
|
||||||
|
set_result(a, result);
|
||||||
|
} else {
|
||||||
|
for (auto& a : elements_)
|
||||||
|
set_result(a, interpolated_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
|
@ -40,7 +40,7 @@ class Animator {
|
||||||
float GetTime(int animation);
|
float GetTime(int animation);
|
||||||
void SetTime(int animation, float time, bool force_update = false);
|
void SetTime(int animation, float time, bool force_update = false);
|
||||||
|
|
||||||
// Set callback ro be called once animation ends.
|
// Set callback to be called once animation ends.
|
||||||
void SetEndCallback(int animation, base::Closure cb);
|
void SetEndCallback(int animation, base::Closure cb);
|
||||||
|
|
||||||
// Distance is the magnitude of direction vector. Duration is in seconds.
|
// Distance is the magnitude of direction vector. Duration is in seconds.
|
||||||
|
@ -69,7 +69,7 @@ class Animator {
|
||||||
void SetVisible(bool visible);
|
void SetVisible(bool visible);
|
||||||
|
|
||||||
void Update(float delta_time);
|
void Update(float delta_time);
|
||||||
void Evaluate(float frame_frac_time);
|
void Evaluate(float frame_frac);
|
||||||
|
|
||||||
bool IsPlaying(int animation) const { return play_flags_ & animation; }
|
bool IsPlaying(int animation) const { return play_flags_ & animation; }
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ class Animator {
|
||||||
base::Vector2f movement_last_pos = {0, 0};
|
base::Vector2f movement_last_pos = {0, 0};
|
||||||
float rotation_last_theta = 0;
|
float rotation_last_theta = 0;
|
||||||
base::Vector4f blending_start = {0, 0, 0, 0};
|
base::Vector4f blending_start = {0, 0, 0, 0};
|
||||||
int frame_start_ = 0;
|
int frame_start = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned int play_flags_ = 0;
|
unsigned int play_flags_ = 0;
|
||||||
|
@ -120,13 +120,22 @@ class Animator {
|
||||||
base::Closure pending_cb_;
|
base::Closure pending_cb_;
|
||||||
Flags inside_cb_ = kNone;
|
Flags inside_cb_ = kNone;
|
||||||
|
|
||||||
bool did_evaluate_ = false;
|
|
||||||
|
|
||||||
void UpdateAnimTime(float delta_time,
|
void UpdateAnimTime(float delta_time,
|
||||||
int anim,
|
int anim,
|
||||||
float anim_speed,
|
float anim_speed,
|
||||||
float& anim_time,
|
float& anim_time,
|
||||||
base::Closure& cb);
|
base::Closure& cb);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using ResultSetter = std::function<void(Element&, T)>;
|
||||||
|
|
||||||
|
template <typename T, bool relative>
|
||||||
|
void EvaluateAnimation(float frame_frac,
|
||||||
|
float anim_speed,
|
||||||
|
float anim_time,
|
||||||
|
Interpolator& interpolator,
|
||||||
|
T target,
|
||||||
|
ResultSetter<T> set_result);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "engine/font.h"
|
#include "engine/asset/font.h"
|
||||||
|
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
@ -8,7 +8,8 @@
|
||||||
#include "engine/platform/asset_file.h"
|
#include "engine/platform/asset_file.h"
|
||||||
|
|
||||||
#define STB_TRUETYPE_IMPLEMENTATION
|
#define STB_TRUETYPE_IMPLEMENTATION
|
||||||
#include "../third_party/stb/stb_truetype.h"
|
#define STBTT_STATIC
|
||||||
|
#include "third_party/stb/stb_truetype.h"
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ bool Font::Load(const std::string& file_name) {
|
||||||
auto buffer = AssetFile::ReadWholeFile(
|
auto buffer = AssetFile::ReadWholeFile(
|
||||||
file_name.c_str(), Engine::Get().GetRootPath().c_str(), &buffer_size);
|
file_name.c_str(), Engine::Get().GetRootPath().c_str(), &buffer_size);
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
LOG << "Failed to read font file.";
|
LOG(0) << "Failed to read font file.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ bool Font::Load(const std::string& file_name) {
|
||||||
// It's tighly packed.
|
// It's tighly packed.
|
||||||
glyph_cache_ = std::make_unique<uint8_t[]>(kGlyphSize * kGlyphSize);
|
glyph_cache_ = std::make_unique<uint8_t[]>(kGlyphSize * kGlyphSize);
|
||||||
if (!glyph_cache_) {
|
if (!glyph_cache_) {
|
||||||
LOG << "Failed to allocate glyph cache.";
|
LOG(0) << "Failed to allocate glyph cache.";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ bool Font::Load(const std::string& file_name) {
|
||||||
if (stbtt_BakeFontBitmap((unsigned char*)buffer.get(), 0, kFontHeight,
|
if (stbtt_BakeFontBitmap((unsigned char*)buffer.get(), 0, kFontHeight,
|
||||||
glyph_cache_.get(), kGlyphSize, kGlyphSize,
|
glyph_cache_.get(), kGlyphSize, kGlyphSize,
|
||||||
kFirstChar, kNumChars, glyph_info_) <= 0) {
|
kFirstChar, kNumChars, glyph_info_) <= 0) {
|
||||||
LOG << "Failed to bake the glyph cache: ";
|
LOG(0) << "Failed to bake the glyph cache: ";
|
||||||
glyph_cache_.reset();
|
glyph_cache_.reset();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -67,10 +68,10 @@ static void StretchBlit_I8_to_RGBA32(int dst_x0,
|
||||||
int dst_pitch,
|
int dst_pitch,
|
||||||
const uint8_t* src_i,
|
const uint8_t* src_i,
|
||||||
int src_pitch) {
|
int src_pitch) {
|
||||||
// LOG << "-- StretchBlit: --";
|
// LOG(0) << "-- StretchBlit: --";
|
||||||
// LOG << "dst: rect(" << dst_x0 << ", " << dst_y0 << ")..("
|
// LOG(0) << "dst: rect(" << dst_x0 << ", " << dst_y0 << ")..("
|
||||||
// << dst_x1 << ".." << dst_y1 << "), pitch(" << dst_pitch << ")";
|
// << 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 << ")";
|
// << src_x1 << ".." << src_y1 << "), pitch(" << src_pitch << ")";
|
||||||
|
|
||||||
int dst_width = dst_x1 - dst_x0, dst_height = dst_y1 - dst_y0,
|
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,
|
// int dst_dx = dst_width > 0 ? 1 : -1,
|
||||||
// dst_dy = dst_height > 0 ? 1 : -1;
|
// dst_dy = dst_height > 0 ? 1 : -1;
|
||||||
|
|
||||||
// LOG << "dst_width = " << dst_width << ", dst_height = " << dst_height;
|
// LOG(0) << "dst_width = " << dst_width << ", dst_height = " << dst_height;
|
||||||
// LOG << "src_width = " << src_width << ", src_height = " << src_height;
|
// LOG(0) << "src_width = " << src_width << ", src_height = " << src_height;
|
||||||
|
|
||||||
uint8_t* dst = dst_rgba + (dst_x0 + dst_y0 * dst_pitch) * 4;
|
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;
|
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);
|
CalculateBoundingBox(text, x0, y0, x1, y1);
|
||||||
width = x1 - x0;
|
width = x1 - x0;
|
||||||
height = y1 - y0;
|
height = y1 - y0;
|
||||||
// LOG << "width = " << width << ", height = " << height;
|
// LOG(0) << "width = " << width << ", height = " << height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::Print(int x,
|
void Font::Print(int x,
|
||||||
|
@ -166,7 +167,7 @@ void Font::Print(int x,
|
||||||
const std::string& text,
|
const std::string& text,
|
||||||
uint8_t* buffer,
|
uint8_t* buffer,
|
||||||
int width) const {
|
int width) const {
|
||||||
// LOG("Font::Print() = %s\n", text);
|
// LOG(0)("Font::Print() = %s\n", text);
|
||||||
|
|
||||||
if (!glyph_cache_)
|
if (!glyph_cache_)
|
||||||
return;
|
return;
|
||||||
|
@ -183,7 +184,7 @@ void Font::Print(int x,
|
||||||
stbtt_GetBakedQuad(glyph_info_, kGlyphSize, kGlyphSize, *ptr - kFirstChar,
|
stbtt_GetBakedQuad(glyph_info_, kGlyphSize, kGlyphSize, *ptr - kFirstChar,
|
||||||
&fx, &fy, &q, 1);
|
&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);
|
// 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,
|
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
|
#ifndef ENGINE_ASSET_FONT_H
|
||||||
#define ENGINE_FONT_H
|
#define ENGINE_ASSET_FONT_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -51,4 +51,4 @@ class Font {
|
||||||
|
|
||||||
} // namespace eng
|
} // 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 <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include "base/interpolation.h"
|
#include "base/interpolation.h"
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
|
#include "base/mem.h"
|
||||||
#include "base/misc.h"
|
#include "base/misc.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/platform/asset_file.h"
|
#include "engine/platform/asset_file.h"
|
||||||
#include "third_party/texture_compressor/texture_compressor.h"
|
#include "third_party/texture_compressor/texture_compressor.h"
|
||||||
|
|
||||||
// This 3rd party library is written in C and uses malloc, which means that we
|
// Use aligned memory for SIMD in texture compressor.
|
||||||
// have to do the same.
|
|
||||||
#define STBI_NO_STDIO
|
#define STBI_NO_STDIO
|
||||||
#include "../third_party/stb/stb_image.h"
|
#include "third_party/stb/stb_image.h"
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ bool Image::Create(int w, int h) {
|
||||||
width_ = w;
|
width_ = w;
|
||||||
height_ = h;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ bool Image::Create(int w, int h) {
|
||||||
void Image::Copy(const Image& other) {
|
void Image::Copy(const Image& other) {
|
||||||
if (other.buffer_) {
|
if (other.buffer_) {
|
||||||
int size = other.GetSize();
|
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);
|
memcpy(buffer_.get(), other.buffer_.get(), size);
|
||||||
}
|
}
|
||||||
width_ = other.width_;
|
width_ = other.width_;
|
||||||
|
@ -95,14 +95,15 @@ void Image::Copy(const Image& other) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Image::CreateMip(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;
|
return false;
|
||||||
|
|
||||||
// Reduce the dimensions.
|
// Reduce the dimensions.
|
||||||
width_ = std::max(other.width_ >> 1, 1);
|
width_ = std::max(other.width_ >> 1, 1);
|
||||||
height_ = std::max(other.height_ >> 1, 1);
|
height_ = std::max(other.height_ >> 1, 1);
|
||||||
format_ = kRGBA32;
|
format_ = ImageFormat::kRGBA32;
|
||||||
buffer_.reset((uint8_t*)AlignedAlloc<16>(GetSize()));
|
buffer_.reset((uint8_t*)AlignedAlloc(GetSize(), 16));
|
||||||
|
|
||||||
// If the width isn't perfectly divisable with two, then we end up skewing
|
// If the width isn't perfectly divisable with two, then we end up skewing
|
||||||
// the image because the source offset isn't updated properly.
|
// 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(
|
auto file_buffer = AssetFile::ReadWholeFile(
|
||||||
file_name.c_str(), Engine::Get().GetRootPath().c_str(), &buffer_size);
|
file_name.c_str(), Engine::Get().GetRootPath().c_str(), &buffer_size);
|
||||||
if (!file_buffer) {
|
if (!file_buffer) {
|
||||||
LOG << "Failed to read file: " << file_name;
|
LOG(0) << "Failed to read file: " << file_name;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,19 +148,19 @@ bool Image::Load(const std::string& file_name) {
|
||||||
buffer_.reset((uint8_t*)stbi_load_from_memory(
|
buffer_.reset((uint8_t*)stbi_load_from_memory(
|
||||||
(const stbi_uc*)file_buffer.get(), buffer_size, &w, &h, &c, 0));
|
(const stbi_uc*)file_buffer.get(), buffer_size, &w, &h, &c, 0));
|
||||||
if (!buffer_) {
|
if (!buffer_) {
|
||||||
LOG << "Failed to load image file: " << file_name;
|
LOG(0) << "Failed to load image file: " << file_name;
|
||||||
return false;
|
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;
|
uint8_t* converted_buffer = NULL;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 1:
|
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.
|
// Assume it's an intensity, duplicate it to RGB and fill A with opaque.
|
||||||
converted_buffer =
|
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) {
|
for (int i = 0; i < w * h; ++i) {
|
||||||
converted_buffer[i * 4 + 0] = buffer_[i];
|
converted_buffer[i * 4 + 0] = buffer_[i];
|
||||||
converted_buffer[i * 4 + 1] = buffer_[i];
|
converted_buffer[i * 4 + 1] = buffer_[i];
|
||||||
|
@ -169,10 +170,10 @@ bool Image::Load(const std::string& file_name) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
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.
|
// Add an opaque channel.
|
||||||
converted_buffer =
|
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) {
|
for (int i = 0; i < w * h; ++i) {
|
||||||
converted_buffer[i * 4 + 0] = buffer_[i * 3 + 0];
|
converted_buffer[i * 4 + 0] = buffer_[i * 3 + 0];
|
||||||
converted_buffer[i * 4 + 1] = buffer_[i * 3 + 1];
|
converted_buffer[i * 4 + 1] = buffer_[i * 3 + 1];
|
||||||
|
@ -186,7 +187,7 @@ bool Image::Load(const std::string& file_name) {
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
default:
|
default:
|
||||||
LOG << "Image had unsuitable number of color components: " << c << " "
|
LOG(0) << "Image had unsuitable number of color components: " << c << " "
|
||||||
<< file_name;
|
<< file_name;
|
||||||
buffer_.reset();
|
buffer_.reset();
|
||||||
return false;
|
return false;
|
||||||
|
@ -214,32 +215,23 @@ bool Image::Load(const std::string& file_name) {
|
||||||
return !!buffer_;
|
return !!buffer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Image::IsCompressed() const {
|
||||||
|
return IsCompressedFormat(format_);
|
||||||
|
}
|
||||||
|
|
||||||
size_t Image::GetSize() const {
|
size_t Image::GetSize() const {
|
||||||
switch (format_) {
|
return GetImageSize(width_, height_, 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::ConvertToPow2() {
|
void Image::ConvertToPow2() {
|
||||||
int new_width = RoundUpToPow2(width_);
|
int new_width = RoundUpToPow2(width_);
|
||||||
int new_height = RoundUpToPow2(height_);
|
int new_height = RoundUpToPow2(height_);
|
||||||
if ((new_width != width_) || (new_height != height_)) {
|
if ((new_width != width_) || (new_height != height_)) {
|
||||||
LOG << "Converting image from (" << width_ << ", " << height_ << ") to ("
|
LOG(0) << "Converting image from (" << width_ << ", " << height_ << ") to ("
|
||||||
<< new_width << ", " << new_height << ")";
|
<< new_width << ", " << new_height << ")";
|
||||||
|
|
||||||
int bigger_size = new_width * new_height * 4 * sizeof(uint8_t);
|
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.
|
// Fill it with black.
|
||||||
memset(bigger_buffer, 0, bigger_size);
|
memset(bigger_buffer, 0, bigger_size);
|
||||||
|
@ -275,29 +267,29 @@ bool Image::Compress() {
|
||||||
|
|
||||||
switch (tc->format()) {
|
switch (tc->format()) {
|
||||||
case TextureCompressor::kFormatATC:
|
case TextureCompressor::kFormatATC:
|
||||||
format_ = kATC;
|
format_ = ImageFormat::kATC;
|
||||||
break;
|
break;
|
||||||
case TextureCompressor::kFormatATCIA:
|
case TextureCompressor::kFormatATCIA:
|
||||||
format_ = kATCIA;
|
format_ = ImageFormat::kATCIA;
|
||||||
break;
|
break;
|
||||||
case TextureCompressor::kFormatDXT1:
|
case TextureCompressor::kFormatDXT1:
|
||||||
format_ = kDXT1;
|
format_ = ImageFormat::kDXT1;
|
||||||
break;
|
break;
|
||||||
case TextureCompressor::kFormatDXT5:
|
case TextureCompressor::kFormatDXT5:
|
||||||
format_ = kDXT5;
|
format_ = ImageFormat::kDXT5;
|
||||||
break;
|
break;
|
||||||
case TextureCompressor::kFormatETC1:
|
case TextureCompressor::kFormatETC1:
|
||||||
format_ = kETC1;
|
format_ = ImageFormat::kETC1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG << "Compressing image. Format: " << format_;
|
LOG(0) << "Compressing image. Format: " << ImageFormatToString(format_);
|
||||||
|
|
||||||
unsigned compressedSize = GetSize();
|
unsigned compressedSize = GetSize();
|
||||||
uint8_t* compressedBuffer =
|
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();
|
const uint8_t* src = buffer_.get();
|
||||||
uint8_t* dst = compressedBuffer;
|
uint8_t* dst = compressedBuffer;
|