├── .clang-format ├── .gitattributes ├── .github └── workflows │ └── cmake.yml ├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CMakeLists.txt ├── LICENSE ├── README.md ├── docs ├── README.md ├── components.md ├── conventions.md ├── engine.md ├── input.md ├── modules.md └── script.md ├── ext ├── assimp.cmake ├── cro_lib.cmake ├── egl_registry.cmake ├── glslang.cmake ├── imgui.cmake ├── json.cmake ├── opengl_registry.cmake ├── rmlui.cmake ├── robin.cmake ├── spirv_cross.cmake ├── stb.cmake ├── yaml.cmake └── zlib.cmake ├── mod ├── alsa │ ├── alsa.cpp │ └── module.cmake ├── assimp │ ├── assimp.cpp │ ├── assimp.h │ ├── assimp_animation.cpp │ ├── assimp_material.cpp │ ├── assimp_mesh.cpp │ ├── assimp_scene.cpp │ ├── assimp_shader.cpp │ ├── assimp_skeleton.cpp │ ├── assimp_texture.cpp │ └── module.cmake ├── audio_win │ ├── audio_win.cpp │ └── module.cmake ├── blue_noise │ ├── blue_noise.cpp │ └── module.cmake ├── cro_mipmap │ ├── cro_mipmap.cpp │ └── module.cmake ├── fmod │ ├── fmod.cpp │ └── module.cmake ├── font_tools │ ├── FontPacker.cpp │ ├── font_tools.cpp │ ├── include │ │ └── FontPacker.h │ └── module.cmake ├── glslang │ ├── glslang.cpp │ └── module.cmake ├── grid2d │ ├── grid2d.cpp │ ├── include │ │ └── grid2d.h │ └── module.cmake ├── imgui │ ├── imgui_integration.cpp │ ├── include │ │ └── imgui_integration.h │ └── module.cmake ├── imgui_console │ ├── imgui_console.cpp │ └── module.cmake ├── imgui_game_platform │ ├── imgui_game_platform.cpp │ └── module.cmake ├── imgui_input │ ├── imgui_input.cpp │ └── module.cmake ├── imgui_resources │ ├── imgui_resources.cpp │ └── module.cmake ├── joystick_unix │ ├── joystick_unix.cpp │ └── module.cmake ├── json │ ├── json.cpp │ └── module.cmake ├── lasm │ ├── lasm.cpp │ └── module.cmake ├── ls │ ├── LSCompiler.cpp │ ├── LSCompiler.h │ ├── LSLexer.cpp │ ├── LSLexer.h │ ├── LSParser.cpp │ ├── LSParser.h │ ├── README.md │ ├── ls.cpp │ └── module.cmake ├── lz │ ├── lz.cpp │ └── module.cmake ├── mesh_format │ ├── mesh_format.cpp │ └── module.cmake ├── mid │ ├── mid.cpp │ └── module.cmake ├── midi_win │ ├── midi_win.cpp │ └── module.cmake ├── opengl │ ├── OpenGLDescriptorSet.cpp │ ├── OpenGLFramebuffer.cpp │ ├── OpenGLMesh.cpp │ ├── OpenGLPipeline.cpp │ ├── OpenGLRenderPass.cpp │ ├── OpenGLRenderer.cpp │ ├── OpenGLRenderer.h │ ├── OpenGLShader.cpp │ ├── OpenGLTexture.cpp │ ├── OpenGLUniformBuffer.cpp │ ├── gl_functions.def │ ├── module.cmake │ └── opengl.cpp ├── pixel_font │ ├── glyphs.def │ ├── module.cmake │ └── pixel_font.cpp ├── rawinput │ ├── module.cmake │ └── rawinput.cpp ├── rmlui │ ├── RmlUiComponent.cpp │ ├── RmlUiComponent.h │ ├── RmlUiFile.cpp │ ├── RmlUiFile.h │ ├── RmlUiFontEngine.cpp │ ├── RmlUiFontEngine.h │ ├── RmlUiRender.cpp │ ├── RmlUiRender.h │ ├── RmlUiSystem.cpp │ ├── RmlUiSystem.h │ ├── module.cmake │ ├── rmlui.cpp │ └── rmlui.h ├── robin │ ├── module.cmake │ └── robin.cpp ├── script_material │ ├── module.cmake │ └── script_material.cpp ├── script_mesh │ ├── module.cmake │ └── script_mesh.cpp ├── script_optimize │ ├── module.cmake │ └── script_optimize.cpp ├── script_server │ ├── module.cmake │ └── script_server.cpp ├── script_texture │ ├── module.cmake │ └── script_texture.cpp ├── shader_reflect │ ├── module.cmake │ └── shader_reflect.cpp ├── stb_dxt │ ├── module.cmake │ └── stb_dxt.cpp ├── stb_image │ ├── module.cmake │ └── stb_image.cpp ├── stb_perlin │ ├── module.cmake │ └── stb_perlin.cpp ├── stb_truetype │ ├── module.cmake │ └── stb_truetype.cpp ├── stb_vorbis │ ├── module.cmake │ └── stb_vorbis.cpp ├── steamworks │ ├── module.cmake │ └── steamworks.cpp ├── test_compression │ ├── module.cmake │ └── test_compression.cpp ├── test_hashing │ ├── module.cmake │ └── test_hashing.cpp ├── test_memory │ ├── module.cmake │ └── test_memory.cpp ├── test_random │ ├── module.cmake │ └── test_random.cpp ├── test_serialization │ ├── module.cmake │ └── test_serialization.cpp ├── vulkan │ ├── VulkanBuffer.cpp │ ├── VulkanBuffer.h │ ├── VulkanDescriptorSet.cpp │ ├── VulkanFramebuffer.cpp │ ├── VulkanMesh.cpp │ ├── VulkanPipeline.cpp │ ├── VulkanRenderPass.cpp │ ├── VulkanRenderer.cpp │ ├── VulkanRenderer.h │ ├── VulkanShader.cpp │ ├── VulkanTexture.cpp │ ├── VulkanUniformBuffer.cpp │ ├── module.cmake │ └── vulkan.cpp ├── wav │ ├── module.cmake │ └── wav.cpp ├── wavefront_obj │ ├── module.cmake │ └── wavefront_obj.cpp ├── win32 │ ├── include │ │ └── win32.h │ ├── module.cmake │ └── win32.cpp ├── wwise │ ├── module.cmake │ └── wwise.cpp ├── xinput_unix │ ├── module.cmake │ └── xinput_unix.cpp ├── xinput_win │ ├── module.cmake │ └── xinput_win.cpp ├── xlib │ ├── include │ │ └── xlib.h │ ├── module.cmake │ └── xlib.cpp ├── yaml │ ├── module.cmake │ └── yaml.cpp └── zlib │ ├── module.cmake │ └── zlib.cpp ├── run.sh ├── smp ├── README.md ├── audio │ ├── bach.ogg │ ├── guitar.wav │ └── mozart.mid ├── material │ ├── DamagedHelmet.glb │ ├── Fox.glb │ ├── box.ls │ ├── bush.ls │ ├── dirlight.ls │ ├── dirlight_cel.ls │ ├── jerrican.ls │ ├── outline.ls │ ├── pixel_text.ls │ ├── pointlight.ls │ ├── pointlight_cel.ls │ ├── sky.ls │ ├── smartphone.ls │ ├── sphere.ls │ ├── sphere_light.ls │ ├── sprite.ls │ ├── ssao.ls │ └── terrain.ls ├── mesh │ ├── bush.obj │ ├── cube.ls │ ├── jerrican.obj │ ├── smartphone.obj │ └── sphere.ls ├── project.cmake ├── script │ ├── camera.ls │ ├── ini.ls │ ├── input_map.ls │ ├── proxy.lasm │ ├── scene.ls │ ├── sink.ls │ └── startup.ls ├── shader │ ├── alpha_lib.glsl │ ├── color.frag │ ├── color.vert │ ├── color_light.frag │ ├── constants.glsl │ ├── dirlight.frag │ ├── dirlight_cel.frag │ ├── font.frag │ ├── font.vert │ ├── fullscreen.vert │ ├── light_lib.glsl │ ├── outline.frag │ ├── pointlight.frag │ ├── pointlight_cel.frag │ ├── present.frag │ ├── quad.vert │ ├── sky.frag │ ├── sky.vert │ ├── sprite.frag │ ├── sprite.vert │ ├── ssao.frag │ ├── staticmesh.frag │ ├── staticmesh.vert │ ├── terrain.frag │ ├── terrain.vert │ └── texture.frag └── texture │ ├── bush.png │ ├── default_mat.png │ ├── jerrican.png │ ├── jerrican_mat.png │ ├── logo.ls │ ├── skybox.png │ ├── smartphone.png │ └── smartphone_mat.png └── src ├── L.ico ├── L.natvis ├── audio ├── Audio.cpp ├── Audio.h ├── AudioDecoder.cpp ├── AudioDecoder.h ├── AudioEngine.cpp ├── AudioEngine.h ├── AudioOutput.cpp ├── AudioOutput.h ├── AudioStream.h ├── Midi.cpp ├── Midi.h ├── MidiSequence.cpp └── MidiSequence.h ├── component ├── AudioListenerComponent.cpp ├── AudioListenerComponent.h ├── AudioSourceComponent.cpp ├── AudioSourceComponent.h ├── Camera.cpp ├── Camera.h ├── Collider.cpp ├── Collider.h ├── Component.h ├── ComponentPool.h ├── Entity.cpp ├── Entity.h ├── GUIComponent.cpp ├── GUIComponent.h ├── GroupComponent.cpp ├── GroupComponent.h ├── HierarchyComponent.cpp ├── HierarchyComponent.h ├── InputComponent.cpp ├── InputComponent.h ├── MidiSourceComponent.cpp ├── MidiSourceComponent.h ├── NameComponent.cpp ├── NameComponent.h ├── PostProcessComponent.cpp ├── PostProcessComponent.h ├── Primitive.cpp ├── Primitive.h ├── RigidBody.cpp ├── RigidBody.h ├── ScriptComponent.cpp ├── ScriptComponent.h ├── SkeletalAnimatorComponent.cpp ├── SkeletalAnimatorComponent.h ├── Transform.cpp └── Transform.h ├── container ├── Archive.cpp ├── Archive.h ├── Array.h ├── Bitfield.h ├── Buffer.h ├── Handle.cpp ├── Handle.h ├── IntervalTree.h ├── IterablePool.h ├── KeyValue.h ├── Pool.h ├── Queue.h ├── Ref.h ├── Set.h ├── SortedArray.h ├── StaticStack.h ├── Table.h └── Tree.h ├── dev ├── debug.cpp ├── debug.h ├── debug_unix.cpp ├── debug_win.cpp ├── profiling.cpp ├── profiling.h ├── test.cpp └── test.h ├── dynamic ├── Type.cpp ├── Type.h ├── Variable.cpp └── Variable.h ├── engine ├── CullVolume.cpp ├── CullVolume.h ├── Engine.cpp ├── Engine.h ├── GamePlatform.cpp ├── GamePlatform.h ├── Resource.cpp ├── Resource.h ├── Resource.inl ├── Settings.cpp ├── Settings.h ├── debug_draw.cpp └── debug_draw.h ├── hash.h ├── input ├── Device.cpp ├── Device.h ├── InputContext.cpp ├── InputContext.h ├── device_axes.def └── device_buttons.def ├── macros.h ├── main.cpp ├── math ├── Interval.h ├── Matrix.h ├── Quaternion.h ├── Rand.cpp ├── Rand.h ├── Vector.h ├── digits.h ├── geometry.cpp ├── geometry.h └── math.h ├── network ├── Network.cpp ├── Network.h ├── Network_unix.cpp ├── Network_win.cpp ├── Server.cpp └── Server.h ├── objects.h ├── parallelism ├── Lock.h ├── Mutex.h ├── Mutex_unix.cpp ├── Mutex_win.cpp ├── Semaphore.h ├── Semaphore_unix.cpp ├── Semaphore_win.cpp ├── TaskSystem.cpp ├── TaskSystem.h ├── TaskSystem_unix.cpp └── TaskSystem_win.cpp ├── rendering ├── Animation.cpp ├── Animation.h ├── Color.cpp ├── Color.h ├── Font.cpp ├── Font.h ├── Material.cpp ├── Material.h ├── Mesh.cpp ├── Mesh.h ├── Pipeline.cpp ├── Pipeline.h ├── Renderer.cpp ├── Renderer.h ├── Shader.cpp ├── Shader.h ├── Texture.cpp ├── Texture.h ├── UniformBuffer.cpp ├── UniformBuffer.h └── shader_lib.h ├── resource.rc ├── script ├── ScriptContext.cpp ├── ScriptContext.h ├── ScriptGlobal.cpp ├── ScriptGlobal.h ├── script.cpp ├── script.h ├── script_binding.h └── script_standard_functions.cpp ├── stream ├── AsyncFileStream.h ├── AsyncFileStream_win.cpp ├── BufferStream.h ├── CFileStream.h ├── DirectStream.cpp ├── DirectStream.h ├── NetStream.cpp ├── NetStream.h ├── Stream.cpp ├── Stream.h ├── StringStream.cpp ├── StringStream.h ├── serial_bin.h └── serial_text.h ├── system ├── Arguments.cpp ├── Arguments.h ├── File.h ├── FileWatch.h ├── FileWatch_unix.cpp ├── FileWatch_win.cpp ├── File_unix.cpp ├── File_win.cpp ├── Memory.cpp ├── Memory.h ├── Memory_unix.cpp ├── Memory_win.cpp ├── System.cpp ├── System.h ├── System_unix.cpp ├── System_win.cpp ├── Window.cpp ├── Window.h └── intrinsics.h ├── text ├── String.cpp ├── String.h ├── Symbol.cpp ├── Symbol.h ├── compression.cpp ├── compression.h ├── encoding.cpp ├── encoding.h ├── format.cpp └── format.h └── time ├── Date.cpp ├── Date.h ├── ScopedTimer.h ├── Time.cpp ├── Time.h ├── Time_unix.cpp ├── Time_win.cpp ├── Timer.cpp └── Timer.h /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | 3 | ColumnLimit: 0 4 | ConstructorInitializerIndentWidth: 2 5 | ContinuationIndentWidth: 2 6 | IndentWidth: 2 7 | TabWidth: 2 8 | UseTab: Never 9 | 10 | AlignAfterOpenBracket: DontAlign 11 | AlignEscapedNewlines: DontAlign 12 | AlignTrailingComments: false 13 | AllowShortCaseLabelsOnASingleLine: true 14 | AllowShortFunctionsOnASingleLine: Inline 15 | AllowShortLambdasOnASingleLine: All 16 | AlwaysBreakTemplateDeclarations: No 17 | BreakBeforeBraces: Attach 18 | FixNamespaceComments: false 19 | IndentCaseLabels: true 20 | MaxEmptyLinesToKeep: 1 21 | NamespaceIndentation: All 22 | PointerAlignment: Left 23 | SpaceBeforeParens: Never 24 | 25 | #SortIncludes: CaseInsensitive 26 | IncludeBlocks: Regroup 27 | IncludeCategories: 28 | - Regex: '.*\.(cpp|inl)' 29 | Priority: 4 30 | - Regex: '' 31 | Priority: 1 32 | - Regex: '<.+>' 33 | Priority: 2 34 | - Regex: '.*' 35 | Priority: 3 36 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h text 2 | *.cpp text 3 | *.inl text 4 | *.lua text 5 | *.ls text 6 | *.sh text 7 | *.bat text 8 | 9 | -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | stats: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | 11 | - name: Stats 12 | run: ./run.sh stats 13 | 14 | build: 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | build_type: [Debug, RelWithDebInfo, Release] 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | 23 | - name: Configure CMake 24 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DL_ENABLE_ALL_MODULES=ON 25 | 26 | - name: Cache externals 27 | uses: actions/cache@v2 28 | with: 29 | path: ${{github.workspace}}/build/ext 30 | key: ${{runner.os}}-ext-${{hashFiles('**/ext/*.cmake')}} 31 | 32 | - name: Build 33 | run: cmake --build ${{github.workspace}}/build --config ${{matrix.build_type}} 34 | 35 | - name: Test 36 | if: ${{ matrix.build_type != 'Release' && matrix.build_type != 'MinSizeRel' }} 37 | working-directory: ${{github.workspace}}/build 38 | run: ctest -V -C ${{matrix.build_type}} 39 | env: 40 | CTEST_OUTPUT_ON_FAILURE: 1 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries folder 2 | /bin 3 | # Build folder 4 | /bld 5 | /build 6 | # CMake tests 7 | /Testing 8 | # External project folder 9 | /ext/*/ 10 | # Sample folder 11 | smp/Ldev 12 | smp/Ldbg 13 | smp/L 14 | smp/sample_* 15 | smp/tests_* 16 | smp/*.bin 17 | smp/*.dll 18 | smp/*.exe 19 | smp/*.exp 20 | smp/*.pdb 21 | smp/*.ilk 22 | smp/*.lib 23 | smp/*.manifest 24 | smp/trace.json 25 | smp/imgui.ini 26 | smp/steam_appid.txt 27 | # Generated source 28 | *.gen 29 | # Generated logs 30 | *.log 31 | # Visual Studio 32 | *.aps 33 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "(gdb) Debug", 6 | "type": "cppdbg", 7 | "request": "launch", 8 | "program": "${workspaceFolder}/smp/sample_dbg", 9 | "cwd": "${workspaceFolder}/smp", 10 | "MIMode": "gdb", 11 | "preLaunchTask": "build-dbg", 12 | "visualizerFile": "${workspaceFolder}/src/L.natvis", 13 | "showDisplayString": true, 14 | }, 15 | { 16 | "name": "(gdb) Development", 17 | "type": "cppdbg", 18 | "request": "launch", 19 | "program": "${workspaceFolder}/smp/sample_dev", 20 | "cwd": "${workspaceFolder}/smp", 21 | "MIMode": "gdb", 22 | "preLaunchTask": "build-dev", 23 | "visualizerFile": "${workspaceFolder}/src/L.natvis", 24 | }, 25 | { 26 | "name": "(gdb) Release", 27 | "type": "cppdbg", 28 | "request": "launch", 29 | "program": "${workspaceFolder}/smp/sample", 30 | "cwd": "${workspaceFolder}/smp", 31 | "MIMode": "gdb", 32 | "preLaunchTask": "build-rls", 33 | "visualizerFile": "${workspaceFolder}/src/L.natvis", 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "files.trimTrailingWhitespace": true 4 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build-dbg", 6 | "type": "shell", 7 | "command": "./run.sh build dbg", 8 | "group": { 9 | "kind": "build", 10 | "isDefault": true 11 | } 12 | }, 13 | { 14 | "label": "build-dev", 15 | "type": "shell", 16 | "command": "./run.sh build dev" 17 | }, 18 | { 19 | "label": "build-rls", 20 | "type": "shell", 21 | "command": "./run.sh build rls" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # L Engine 2 | 3 | ## About 4 | L is a public-domain modular game engine. 5 | 6 | ## Building 7 | 8 | `run.sh [build|run|open] [dbg|dev|rls]` 9 | 10 | The `build` action will just build the engine (default configuration is development), while the `run` action will also run the [sample](./smp/), and the `open` action will open the Visual Studio project (Windows-only). 11 | 12 | ## Copyright 13 | All parts of this software are released into the public domain (as per [this notice](LICENSE)) unless otherwise stated. Any contribution to this repository is implicitly subjected to the same release. 14 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | Documentation for the L engine. There is a lot missing and a lot wrong. 2 | 3 | * [Conventions](conventions.md) 4 | * [Script](script.md) 5 | * [Engine](engine.md) 6 | * [Input](input.md) 7 | * [Components](components.md) 8 | * [Modules](modules.md) 9 | -------------------------------------------------------------------------------- /docs/conventions.md: -------------------------------------------------------------------------------- 1 | # Conventions 2 | 3 | ## Mathematical and geometric conventions 4 | - X is right, Y is forward, Z is up 5 | - Matrices and Vectors are column-major 6 | 7 | ## Source conventions 8 | - #pragma once (less name repetition and preprocessor pollution) 9 | - 2-spaces indentation 10 | 11 | ## C++ code snippet 12 | ``` C++ 13 | #pragma once 14 | 15 | #define L_MACRO(x) ((x)*(x)) 16 | 17 | namespace L { 18 | enum EnumType { 19 | OnePossibility, 20 | AnotherThing, 21 | }; 22 | class ClassName { 23 | protected: 24 | float _attribute_name; 25 | public: 26 | void method_name(int p1, float p2) { 27 | int var_name(4); 28 | return function_name(p2, var_name, p1); 29 | } 30 | }; 31 | } 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/engine.md: -------------------------------------------------------------------------------- 1 | # Engine reference 2 | 3 | This file documents how to interact with the engine in [script](script.md) in general. 4 | For now, when the engine starts, it reads a script in the current directory named "ini.ls". 5 | 6 | ## Entities 7 | * `entity_make()` takes no argument and returns a new entity 8 | * `entity_copy(e)` takes an entity as argument and returns a new entity copied from the supplied entity 9 | * `entity_destroy(e)` takes an entity as argument and queues it for destruction 10 | 11 | ## Physics 12 | * `engine_gravity(v)` takes a vector in meter per second per second and sets the global gravity to that 13 | -------------------------------------------------------------------------------- /docs/input.md: -------------------------------------------------------------------------------- 1 | # Input 2 | 3 | ## Devices 4 | Devices can be keyboards, mice, trackpads or gamepads. 5 | * `get_axis(a)` is a device method that takes a symbol as argument and returns the value of that axis as float 6 | * `get_button(b)` is a device method that takes a symbol as argument and returns the value of that button as bool 7 | 8 | ## Events 9 | Device events signal the press or release of a button on a specific device. They are forwarded to scripts through the `event` callback, which receives objects with `device`, `button` and `pressed` fields. 10 | 11 | ## Globals 12 | * `get_devices()` returns an object with all devices as keys 13 | * `button_pressed(b)` takes a symbol parameter and returns true if the button is currently pressed (by any device). 14 | 15 | The list of buttons can be found in `src\system\device_buttons.def`. 16 | 17 | The list of axes can be found in `src\system\device_axes.def`. 18 | -------------------------------------------------------------------------------- /docs/script.md: -------------------------------------------------------------------------------- 1 | # Script reference 2 | 3 | ## Math 4 | 5 | - `clamp(x, min, max)` returns `min` if `x < min`, `max` if `x > max`, or `x` otherwise 6 | - `max(...)` returns the maximum value of all its parameters 7 | - `min(...)` returns the minimum value of all its parameters 8 | - `rand()` returns a random float from 0 to 1 9 | 10 | ### Vectors 11 | 12 | - `vec(x, y, [z], [w])` returns a vector from its [2-4] parameters 13 | - `normalize(v)` returns the normalized vector `v` 14 | - `length(v)` returns the length of vector `v` 15 | - `dist(a, b)` returns the distance between vectors `a` and `b` 16 | - `dot(a, b)` returns the dot product of vectors `a` and `b` 17 | - `cross(a, b)` returns the cross product of 3-float vectors `a` and `b` 18 | 19 | ### Scalars 20 | 21 | - `pow(x, p)` returns float `x` raised to the power `p` 22 | - `sqrt(x)` returns the square root of float `x` 23 | - `sin(x)` returns `sin(x)` 24 | - `cos(x)` returns `cos(x)` 25 | - `tan(x)` returns `tan(x)` 26 | - `abs(x)` returns absolute value of `x` 27 | - `floor(x)` returns closest lesser integer to `x` 28 | - `ceil(x)` returns closest greater integer to `x` 29 | 30 | ## Time 31 | 32 | - `now()` returns the current time 33 | - `time(s)` returns time from seconds 34 | 35 | ## Miscellaneous 36 | 37 | - `count(o)` returns the number of values in table `o` 38 | - `print(...)` prints all its parameters in order to stdout 39 | - `typename(v)` returns the name of the type of `v` as a string 40 | -------------------------------------------------------------------------------- /ext/assimp.cmake: -------------------------------------------------------------------------------- 1 | 2 | if(MSVC) 3 | if(MSVC_TOOLSET_VERSION) 4 | set(ASSIMP_LIB_SUFFIX "-vc${MSVC_TOOLSET_VERSION}-mt") 5 | else() 6 | if(MSVC12) 7 | set(ASSIMP_LIB_SUFFIX "-vc120-mt") 8 | elseif(MSVC14) 9 | set(ASSIMP_LIB_SUFFIX "-vc140-mt") 10 | elseif(MSVC15) 11 | set(ASSIMP_LIB_SUFFIX "-vc141-mt") 12 | endif(MSVC12) 13 | endif() 14 | endif() 15 | 16 | set(ASSIMP_RLS_LIBRARIES 17 | lib/assimp${ASSIMP_LIB_SUFFIX} 18 | lib/IrrXML 19 | lib/zlibstatic 20 | ) 21 | set(ASSIMP_DBG_LIBRARIES ${ASSIMP_RLS_LIBRARIES}) 22 | 23 | if(MSVC) 24 | list(TRANSFORM ASSIMP_DBG_LIBRARIES APPEND "d") 25 | endif() 26 | 27 | add_external( 28 | assimp 29 | CMAKE 30 | GIT_REPOSITORY https://github.com/assimp/assimp.git 31 | GIT_TAG 8f0c6b04b2257a520aaab38421b2e090204b69df # v5.0.1 32 | INCLUDE_DIRS include 33 | DBG_LIBRARIES ${ASSIMP_DBG_LIBRARIES} 34 | RLS_LIBRARIES ${ASSIMP_RLS_LIBRARIES} 35 | CMAKE_ARGS 36 | -DCMAKE_BUILD_TYPE=$,DEBUG,RELEASE> 37 | -DBUILD_SHARED_LIBS=OFF 38 | -DASSIMP_BUILD_ZLIB=ON 39 | -DASSIMP_NO_EXPORT=ON 40 | -DASSIMP_BUILD_ASSIMP_TOOLS=OFF 41 | -DASSIMP_BUILD_TESTS=OFF 42 | ) 43 | -------------------------------------------------------------------------------- /ext/cro_lib.cmake: -------------------------------------------------------------------------------- 1 | add_external( 2 | cro_lib 3 | GIT_REPOSITORY https://github.com/thebeast33/cro_lib.git 4 | GIT_TAG 1a30db34757ca063f6daaeefffd28ec17b7e0866 5 | ) 6 | -------------------------------------------------------------------------------- /ext/egl_registry.cmake: -------------------------------------------------------------------------------- 1 | add_external( 2 | egl_registry 3 | GIT_REPOSITORY https://github.com/KhronosGroup/EGL-Registry.git 4 | GIT_TAG dc0b58dca533c5882c38bc623d133190fff883a4 5 | INCLUDE_DIRS api 6 | ) 7 | -------------------------------------------------------------------------------- /ext/glslang.cmake: -------------------------------------------------------------------------------- 1 | set(GLSLANG_RLS_LIBRARIES 2 | lib/glslang 3 | lib/OSDependent 4 | lib/HLSL 5 | lib/OGLCompiler 6 | lib/SPIRV 7 | ) 8 | set(GLSLANG_DBG_LIBRARIES ${GLSLANG_RLS_LIBRARIES}) 9 | 10 | if(MSVC) 11 | list(TRANSFORM GLSLANG_DBG_LIBRARIES APPEND "d") 12 | endif() 13 | 14 | add_external( 15 | glslang 16 | CMAKE 17 | GIT_REPOSITORY https://github.com/KhronosGroup/glslang.git 18 | GIT_TAG bcf6a2430e99e8fc24f9f266e99316905e6d5134 # v8.13.3743 19 | INCLUDE_DIRS include 20 | DBG_LIBRARIES ${GLSLANG_DBG_LIBRARIES} 21 | RLS_LIBRARIES ${GLSLANG_RLS_LIBRARIES} 22 | ) 23 | -------------------------------------------------------------------------------- /ext/imgui.cmake: -------------------------------------------------------------------------------- 1 | add_external( 2 | imgui 3 | GIT_REPOSITORY https://github.com/ocornut/imgui.git 4 | GIT_TAG c71a50deb5ddf1ea386b91e60fa2e4a26d080074 # v1.87 5 | ) 6 | -------------------------------------------------------------------------------- /ext/json.cmake: -------------------------------------------------------------------------------- 1 | add_external( 2 | json 3 | GIT_REPOSITORY https://github.com/sheredom/json.h.git 4 | GIT_TAG adf662d166f1890f456b1c86a6d923dbfe6c7397 5 | ) 6 | -------------------------------------------------------------------------------- /ext/opengl_registry.cmake: -------------------------------------------------------------------------------- 1 | add_external( 2 | opengl_registry 3 | GIT_REPOSITORY https://github.com/KhronosGroup/OpenGL-Registry.git 4 | GIT_TAG d15191e446614fcec3369577495dfb45b131a27a 5 | INCLUDE_DIRS api 6 | ) 7 | -------------------------------------------------------------------------------- /ext/rmlui.cmake: -------------------------------------------------------------------------------- 1 | set(RMLUI_LIBRARIES 2 | lib/RmlCore 3 | ) 4 | if(WIN32) 5 | list(APPEND RMLUI_LIBRARIES lib/RmlDebugger) 6 | endif() 7 | 8 | add_compile_definitions( 9 | L_RMLUI_WITH_DEBUGGER=$ 10 | ) 11 | 12 | add_external( 13 | rmlui 14 | CMAKE 15 | CONFIG_INSTALL_DIR 16 | GIT_REPOSITORY https://github.com/mikke89/RmlUi.git 17 | GIT_TAG d3e97d8e4d94ea5031bb50a4969d1c0fcf3dc9e6 # 4.2 18 | INCLUDE_DIRS include 19 | LIBRARIES ${RMLUI_LIBRARIES} 20 | CMAKE_ARGS 21 | -DBUILD_SHARED_LIBS=OFF 22 | -DNO_FONT_INTERFACE_DEFAULT=ON 23 | -DNO_THIRDPARTY_CONTAINERS=ON 24 | -DDISABLE_RTTI_AND_EXCEPTIONS=ON 25 | ) 26 | -------------------------------------------------------------------------------- /ext/robin.cmake: -------------------------------------------------------------------------------- 1 | add_external( 2 | robin 3 | GIT_REPOSITORY https://github.com/Lyatus/robin.git 4 | GIT_TAG 027ee53a3955d8ba7954e02f0396037ae2c3c1b0 5 | ) 6 | -------------------------------------------------------------------------------- /ext/spirv_cross.cmake: -------------------------------------------------------------------------------- 1 | set(SPIRV_CROSS_RLS_LIBRARIES 2 | lib/spirv-cross-c 3 | lib/spirv-cross-core 4 | lib/spirv-cross-cpp 5 | lib/spirv-cross-glsl 6 | lib/spirv-cross-hlsl 7 | lib/spirv-cross-msl 8 | lib/spirv-cross-reflect 9 | ) 10 | set(SPIRV_CROSS_DBG_LIBRARIES ${SPIRV_CROSS_RLS_LIBRARIES}) 11 | 12 | if(MSVC) 13 | list(TRANSFORM SPIRV_CROSS_DBG_LIBRARIES APPEND "d") 14 | endif() 15 | 16 | add_external( 17 | spirv_cross 18 | CMAKE 19 | GIT_REPOSITORY https://github.com/KhronosGroup/SPIRV-Cross.git 20 | GIT_TAG 8891bd35120ca91c252a66ccfdc3f9a9d03c70cd # 2020-09-17 21 | INCLUDE_DIRS include 22 | DBG_LIBRARIES ${SPIRV_CROSS_DBG_LIBRARIES} 23 | RLS_LIBRARIES ${SPIRV_CROSS_RLS_LIBRARIES} 24 | ) 25 | -------------------------------------------------------------------------------- /ext/stb.cmake: -------------------------------------------------------------------------------- 1 | add_external( 2 | stb 3 | GIT_REPOSITORY https://github.com/nothings/stb.git 4 | GIT_TAG 8e51be04dc7dcee462e1f09e410faceab52cc6d2 5 | ) 6 | -------------------------------------------------------------------------------- /ext/yaml.cmake: -------------------------------------------------------------------------------- 1 | add_external( 2 | yaml 3 | CMAKE 4 | GIT_REPOSITORY https://github.com/yaml/libyaml.git 5 | GIT_TAG 2c891fc7a770e8ba2fec34fc6b545c672beb37e6 # v0.2.5 6 | INCLUDE_DIRS include 7 | LIBRARIES lib/yaml 8 | ) 9 | -------------------------------------------------------------------------------- /ext/zlib.cmake: -------------------------------------------------------------------------------- 1 | if(UNIX) 2 | set(ZLIB_RLS_LIBRARIES lib/z) 3 | else() 4 | set(ZLIB_RLS_LIBRARIES lib/zlibstatic) 5 | endif() 6 | 7 | set(ZLIB_DBG_LIBRARIES ${ZLIB_RLS_LIBRARIES}) 8 | 9 | if(MSVC) 10 | list(TRANSFORM ZLIB_DBG_LIBRARIES APPEND "d") 11 | endif() 12 | 13 | add_external( 14 | zlib 15 | CMAKE 16 | GIT_REPOSITORY https://github.com/madler/zlib.git 17 | GIT_TAG cacf7f1d4e3d44d871b605da3b647f07d718623f # v1.2.11 18 | INCLUDE_DIRS include 19 | DBG_LIBRARIES ${ZLIB_DBG_LIBRARIES} 20 | RLS_LIBRARIES ${ZLIB_RLS_LIBRARIES} 21 | ) 22 | -------------------------------------------------------------------------------- /mod/alsa/module.cmake: -------------------------------------------------------------------------------- 1 | find_path(ALSA_PATHS alsa/asoundlib.h) 2 | if(NOT ALSA_PATHS) 3 | message("Could NOT find ALSA") 4 | unset(ALSA_PATHS CACHE) 5 | return() 6 | else() 7 | unset(ALSA_PATHS CACHE) 8 | endif() 9 | 10 | add_module( 11 | alsa 12 | CONDITION $ 13 | LIBRARIES asound 14 | ) 15 | -------------------------------------------------------------------------------- /mod/assimp/assimp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "assimp.h" 6 | 7 | using namespace L; 8 | 9 | unsigned int assimp_import_flags = aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_LimitBoneWeights | aiProcess_FlipUVs; 10 | Array assimp_supported_extensions = { 11 | "blend", "fbx", "glb", "gltf", 12 | }; 13 | 14 | void assimp_module_init() { 15 | ResourceLoading::add_loader(assimp_animation_loader); 16 | ResourceLoading::add_loader(assimp_material_loader); 17 | ResourceLoading::add_loader(assimp_mesh_loader); 18 | ResourceLoading::add_loader(assimp_scene_loader); 19 | ResourceLoading::add_loader(assimp_skeleton_loader); 20 | ResourceLoading::add_loader(assimp_shader_loader); 21 | ResourceLoading::add_loader(assimp_texture_loader); 22 | } 23 | -------------------------------------------------------------------------------- /mod/assimp/assimp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | L_PUSH_NO_WARNINGS 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | L_POP_NO_WARNINGS 21 | 22 | extern unsigned int assimp_import_flags; 23 | extern L::Array assimp_supported_extensions; 24 | 25 | bool assimp_animation_loader(L::ResourceSlot& slot, L::Animation::Intermediate& intermediate); 26 | bool assimp_material_loader(L::ResourceSlot& slot, L::Material::Intermediate& intermediate); 27 | bool assimp_mesh_loader(L::ResourceSlot& slot, L::Mesh::Intermediate& intermediate); 28 | bool assimp_scene_loader(L::ResourceSlot& slot, L::ScriptFunction::Intermediate& intermediate); 29 | bool assimp_skeleton_loader(L::ResourceSlot& slot, L::Skeleton::Intermediate& intermediate); 30 | bool assimp_shader_loader(L::ResourceSlot& slot, L::Shader::Intermediate& intermediate); 31 | bool assimp_texture_loader(L::ResourceSlot& slot, L::Texture::Intermediate& intermediate); 32 | -------------------------------------------------------------------------------- /mod/assimp/assimp_skeleton.cpp: -------------------------------------------------------------------------------- 1 | #include "assimp.h" 2 | 3 | using namespace L; 4 | 5 | bool assimp_skeleton_loader(ResourceSlot& slot, Skeleton::Intermediate& intermediate) { 6 | if(!assimp_supported_extensions.find(slot.ext)) { 7 | return false; 8 | } 9 | 10 | Buffer buffer = slot.read_source_file(); 11 | 12 | const aiScene* scene = aiImportFileFromMemory((const char*)buffer.data(), (unsigned int)buffer.size(), assimp_import_flags, slot.ext); 13 | if(!scene) { 14 | warning("assimp: %s", aiGetErrorString()); 15 | return false; 16 | } 17 | 18 | uint32_t mesh_index = 0; 19 | slot.parameter("mesh", mesh_index); 20 | 21 | const aiMesh* mesh = scene->mMeshes[mesh_index]; 22 | 23 | for(uintptr_t i = 0; i < mesh->mNumBones; i++) { 24 | SkeletonJoint joint; 25 | const aiBone* bone = mesh->mBones[i]; 26 | joint.name = bone->mName.C_Str(); 27 | joint.parent = -1; 28 | Matrix44f inv_bind_pose; 29 | memcpy(&inv_bind_pose, &bone->mOffsetMatrix, sizeof(inv_bind_pose)); 30 | joint.inv_bind_pose = inv_bind_pose.transpose(); 31 | intermediate.joints.push(joint); 32 | } 33 | 34 | // Recreate index hierarchy 35 | for(uintptr_t i = 0; i < intermediate.joints.size(); i++) { 36 | SkeletonJoint& joint = intermediate.joints[i]; 37 | const aiNode* node = scene->mRootNode->FindNode(joint.name); 38 | for(uintptr_t j = 0; j < intermediate.joints.size(); j++) { 39 | SkeletonJoint& other_joint = intermediate.joints[j]; 40 | const aiNode* other_node = scene->mRootNode->FindNode(other_joint.name); 41 | if(node->mParent == other_node) { 42 | joint.parent = j; 43 | } 44 | } 45 | } 46 | 47 | return true; 48 | } 49 | -------------------------------------------------------------------------------- /mod/assimp/assimp_texture.cpp: -------------------------------------------------------------------------------- 1 | #include "assimp.h" 2 | 3 | using namespace L; 4 | 5 | bool assimp_texture_loader(ResourceSlot& slot, Texture::Intermediate& intermediate) { 6 | if(!assimp_supported_extensions.find(slot.ext)) { 7 | return false; 8 | } 9 | 10 | Buffer buffer = slot.read_source_file(); 11 | 12 | const aiScene* scene = aiImportFileFromMemory((const char*)buffer.data(), (unsigned int)buffer.size(), assimp_import_flags, slot.ext); 13 | if(!scene) { 14 | warning("assimp: %s", aiGetErrorString()); 15 | return false; 16 | } 17 | 18 | uint32_t texture_index = 0; 19 | slot.parameter("texture", texture_index); 20 | 21 | const aiTexture* texture = scene->mTextures[texture_index]; 22 | if(texture->mHeight == 0) { // Compressed 23 | slot.ext = texture->achFormatHint; 24 | slot.source_buffer = Buffer(texture->pcData, texture->mWidth); 25 | return ResourceLoading::load_internal(slot, intermediate); 26 | } else { 27 | intermediate.mips.push(Buffer(texture->pcData, texture->mWidth * texture->mHeight * 4)); 28 | intermediate.width = texture->mWidth; 29 | intermediate.height = texture->mHeight; 30 | intermediate.format = RenderFormat::R8G8B8A8_UNorm; 31 | } 32 | return true; 33 | } 34 | -------------------------------------------------------------------------------- /mod/assimp/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | assimp 3 | CONDITION ${DEV_DBG} 4 | EXT_DEPENDENCIES assimp 5 | ) 6 | -------------------------------------------------------------------------------- /mod/audio_win/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | audio_win 3 | CONDITION $ 4 | ) 5 | -------------------------------------------------------------------------------- /mod/blue_noise/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | blue_noise 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/cro_mipmap/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | cro_mipmap 3 | CONDITION ${DEV_DBG} 4 | EXT_DEPENDENCIES cro_lib 5 | ) 6 | -------------------------------------------------------------------------------- /mod/fmod/module.cmake: -------------------------------------------------------------------------------- 1 | set(L_FMOD_SDK "" CACHE PATH "Path to the wanted FMOD SDK") 2 | 3 | if("${L_FMOD_SDK}" STREQUAL "") 4 | message("FMOD SDK not set up") 5 | return() 6 | endif() 7 | 8 | if(NOT EXISTS "${L_FMOD_SDK}/api/core/inc/fmod.h") 9 | message("Invalid FMOD SDK location (cannot find fmod.h)") 10 | return() 11 | endif() 12 | 13 | add_module( 14 | fmod 15 | INCLUDE_DIRS 16 | ${L_FMOD_SDK}/api/core/inc 17 | ${L_FMOD_SDK}/api/studio/inc 18 | LIBRARIES 19 | ${L_FMOD_SDK}/api/core/lib/x64/fmod_vc.lib 20 | ${L_FMOD_SDK}/api/studio/lib/x64/fmodstudio_vc.lib 21 | ) 22 | -------------------------------------------------------------------------------- /mod/font_tools/font_tools.cpp: -------------------------------------------------------------------------------- 1 | void font_tools_module_init() {} 2 | -------------------------------------------------------------------------------- /mod/font_tools/include/FontPacker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | //! Creates signed distance field font atlas from high def bitmaps 8 | //! Should be thread-safe 9 | class FontPacker { 10 | protected: 11 | L::Font::Intermediate& _intermediate; 12 | L::IntervalTree<2, int, bool> _parts; 13 | L::Table _hash_to_part; 14 | L::Set _xs, _ys; 15 | 16 | public: 17 | FontPacker(L::Font::Intermediate&); 18 | 19 | void grow(); 20 | L::Interval2i add_bmp(const uint8_t* data, uint32_t width, uint32_t height, uint32_t hash); 21 | L::Interval2f pixel_to_coords(const L::Interval2i& i) const; 22 | void add_glyph(const uint8_t* bmp, size_t width, size_t height, L::Font::Glyph& glyph); 23 | }; 24 | -------------------------------------------------------------------------------- /mod/font_tools/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | font_tools 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/glslang/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | glslang 3 | DEFAULT_ENABLED ON 4 | CONDITION ${DEV_DBG} 5 | EXT_DEPENDENCIES glslang 6 | ) 7 | -------------------------------------------------------------------------------- /mod/grid2d/include/grid2d.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class Grid2d { 9 | public: 10 | struct Parameters { 11 | L::Vector2i start, target; 12 | float max_dist = 0.f; 13 | bool ignore_obstacles = false; 14 | }; 15 | 16 | protected: 17 | enum class NodeStatus : uint8_t { 18 | New, 19 | Open, 20 | Closed, 21 | }; 22 | 23 | struct Node { 24 | L::Table neighbors; 25 | 26 | L::Vector2i parent; 27 | float g_score, f_score; 28 | NodeStatus status = NodeStatus::New; 29 | bool is_obstacle = false; 30 | }; 31 | 32 | L::Table _nodes; 33 | bool _allow_diagonals = false; 34 | 35 | L::Array get_neighbors(const L::Vector2i&); 36 | float get_estimated_cost(const L::Vector2i& from, const L::Vector2i& to); 37 | float get_cost(const L::Vector2i& from, const L::Vector2i& to); 38 | public: 39 | void set_allow_diagonals(bool allow_diagonals); 40 | void set_edge(const L::Vector2i& start, const L::Vector2i& end, float cost); 41 | void set_obstacle(const L::Vector2i& position, bool is_obstacle); 42 | L::Array find_path(const Parameters& parameters); 43 | L::Array find_zone(const Parameters& parameters); 44 | }; 45 | -------------------------------------------------------------------------------- /mod/grid2d/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | grid2d 3 | ) 4 | -------------------------------------------------------------------------------- /mod/imgui/include/imgui_integration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | bool imgui_begin_main_menu_bar(); 6 | void imgui_end_main_menu_bar(); 7 | 8 | bool imgui_begin_toggleable_window(const char* path); 9 | void imgui_end_toggleable_window(); 10 | -------------------------------------------------------------------------------- /mod/imgui/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | imgui 3 | CONDITION ${DEV_DBG} 4 | EXT_DEPENDENCIES imgui 5 | ) 6 | -------------------------------------------------------------------------------- /mod/imgui_console/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | imgui_console 3 | CONDITION ${DEV_DBG} 4 | MOD_DEPENDENCIES imgui 5 | EXT_DEPENDENCIES imgui 6 | ) 7 | -------------------------------------------------------------------------------- /mod/imgui_game_platform/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | imgui_game_platform 3 | CONDITION ${DEV_DBG} 4 | MOD_DEPENDENCIES imgui 5 | EXT_DEPENDENCIES imgui 6 | ) 7 | -------------------------------------------------------------------------------- /mod/imgui_input/imgui_input.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | using namespace L; 8 | 9 | static void imgui_input_update() { 10 | if(!imgui_begin_toggleable_window("Input")) { 11 | return; 12 | } 13 | 14 | const Array>& contexts = InputContext::contexts(); 15 | 16 | for(Handle context_handle : contexts) { 17 | InputContext* context = context_handle; 18 | if(context == nullptr) { 19 | continue; 20 | } 21 | 22 | if(ImGui::CollapsingHeader(context->get_name())) { 23 | const char* block_mode_string = "None"; 24 | switch(context->get_block_mode()) { 25 | case InputBlockMode::Used: block_mode_string = "Used"; break; 26 | case InputBlockMode::All: block_mode_string = "All"; break; 27 | default: break; 28 | } 29 | 30 | ImGui::Text("Block mode: %s", block_mode_string); 31 | 32 | const auto& inputs = context->get_inputs(); 33 | if(inputs.count() > 0) { 34 | ImGui::Columns(2, "Inputs"); 35 | ImGui::Text("Name"); 36 | ImGui::NextColumn(); 37 | ImGui::Text("Value"); 38 | ImGui::NextColumn(); 39 | ImGui::Separator(); 40 | 41 | for(const auto& input : context->get_inputs()) { 42 | ImGui::Text("%s", (const char*)input.key()); 43 | ImGui::NextColumn(); 44 | ImGui::Text("%f", input.value()); 45 | ImGui::NextColumn(); 46 | } 47 | ImGui::Columns(1); 48 | } 49 | } 50 | } 51 | 52 | imgui_end_toggleable_window(); 53 | } 54 | 55 | void imgui_input_module_init() { 56 | Engine::add_update(imgui_input_update); 57 | } 58 | 59 | -------------------------------------------------------------------------------- /mod/imgui_input/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | imgui_input 3 | CONDITION ${DEV_DBG} 4 | MOD_DEPENDENCIES imgui 5 | EXT_DEPENDENCIES imgui 6 | ) 7 | -------------------------------------------------------------------------------- /mod/imgui_resources/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | imgui_resources 3 | CONDITION ${DEV_DBG} 4 | MOD_DEPENDENCIES imgui 5 | EXT_DEPENDENCIES imgui 6 | ) 7 | -------------------------------------------------------------------------------- /mod/joystick_unix/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | joystick_unix 3 | CONDITION $ 4 | ) 5 | -------------------------------------------------------------------------------- /mod/json/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | json 3 | CONDITION ${DEV_DBG} 4 | EXT_DEPENDENCIES json 5 | ) 6 | -------------------------------------------------------------------------------- /mod/lasm/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | lasm 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/ls/LSParser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "LSLexer.h" 8 | 9 | //! Parses ls script into an abstract syntax tree 10 | //! Should be thread-safe 11 | class LSParser { 12 | public: 13 | enum class NodeType : uint8_t { 14 | Value, 15 | Array, 16 | Access, 17 | Raw, 18 | }; 19 | struct Node { 20 | inline Node() {} 21 | inline Node(const L::Array& c) : children(c), type(NodeType::Array) {} 22 | inline Node(const L::Var& v) : value(v), type(NodeType::Value) {} 23 | L::Array children; 24 | L::Var value; 25 | uint32_t line = 0; 26 | NodeType type = NodeType::Value; 27 | bool dot_access = false; 28 | }; 29 | protected: 30 | LSLexer _lexer; 31 | Node _ast; 32 | L::StaticStack<128, Node*> _stack; 33 | L::Table _lines; 34 | public: 35 | inline LSParser() { reset(); } 36 | //! Read new portion of text 37 | //! @param context Small debug string to give context to warnings 38 | //! @param text Text to read tokens from 39 | //! @param size Char count of the text parameter 40 | //! @return true if successful 41 | bool read(const char* context, const char* text, size_t size); 42 | //! Reset state of the parser 43 | void reset(); 44 | //! Get AST and reset parser 45 | //! @return AST 46 | const Node& finish(); 47 | }; 48 | -------------------------------------------------------------------------------- /mod/ls/ls.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "LSCompiler.h" 4 | 5 | using namespace L; 6 | 7 | static const Symbol ls_symbol("ls"); 8 | 9 | bool ls_script_loader(ResourceSlot& slot, ScriptFunction& intermediate) { 10 | if(slot.ext != ls_symbol) { 11 | return false; 12 | } 13 | 14 | if(Buffer buffer = slot.read_source_file()) { 15 | LSCompiler compiler; 16 | compiler.set_context(slot.id); 17 | if(compiler.read((const char*)buffer.data(), buffer.size())) { 18 | if(compiler.compile(intermediate)) { 19 | return true; 20 | } 21 | } 22 | } 23 | return false; 24 | } 25 | void ls_module_init() { 26 | ResourceLoading::add_loader(ls_script_loader); 27 | } 28 | -------------------------------------------------------------------------------- /mod/ls/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | ls 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/lz/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | lz 3 | ) 4 | -------------------------------------------------------------------------------- /mod/mesh_format/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | mesh_format 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/mid/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | mid 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/midi_win/midi_win.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | using namespace L; 9 | 10 | class MidiWin : public Midi { 11 | protected: 12 | HMIDIOUT _device; 13 | public: 14 | MidiWin() { 15 | MMRESULT midiOutOpen_result(midiOutOpen(&_device, 0, 0, 0, CALLBACK_NULL)); 16 | L_ASSERT(midiOutOpen_result==MMSYSERR_NOERROR); 17 | } 18 | protected: 19 | void send_internal(const MidiEvent& e) override { 20 | midiOutShortMsg(_device, e.msg32); 21 | } 22 | }; 23 | 24 | void midi_win_module_init() { 25 | Memory::new_type(); 26 | } 27 | -------------------------------------------------------------------------------- /mod/midi_win/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | midi_win 3 | CONDITION $ 4 | LIBRARIES Winmm 5 | ) 6 | -------------------------------------------------------------------------------- /mod/opengl/OpenGLDescriptorSet.cpp: -------------------------------------------------------------------------------- 1 | #include "OpenGLRenderer.h" 2 | 3 | using namespace L; 4 | 5 | DescriptorSetImpl* OpenGLRenderer::create_descriptor_set(PipelineImpl*) { 6 | return Memory::new_type(); 7 | } 8 | void OpenGLRenderer::destroy_descriptor_set(DescriptorSetImpl* desc_set, PipelineImpl*) { 9 | OpenGLDescriptorSet* gl_desc_set = (OpenGLDescriptorSet*)desc_set; 10 | if(gl_desc_set->constants) { 11 | destroy_uniform_buffer(gl_desc_set->constants); 12 | } 13 | Memory::delete_type(gl_desc_set); 14 | } 15 | void OpenGLRenderer::update_descriptor_set(DescriptorSetImpl* desc_set, const ShaderBinding& binding, TextureImpl* texture) { 16 | OpenGLDescriptorSet* gl_desc_set = (OpenGLDescriptorSet*)desc_set; 17 | gl_desc_set->textures[binding] = (OpenGLTexture*)texture; 18 | } 19 | void OpenGLRenderer::update_descriptor_set(DescriptorSetImpl* desc_set, const ShaderBinding& binding, UniformBufferImpl* uniform_buffer) { 20 | OpenGLDescriptorSet* gl_desc_set = (OpenGLDescriptorSet*)desc_set; 21 | gl_desc_set->uniform_buffers[binding] = (OpenGLUniformBuffer*)uniform_buffer; 22 | } 23 | void OpenGLRenderer::update_descriptor_set(DescriptorSetImpl* desc_set, const ShaderBinding& binding, FramebufferImpl* framebuffer, int32_t texture_index) { 24 | OpenGLFramebuffer* gl_framebuffer = (OpenGLFramebuffer*)framebuffer; 25 | update_descriptor_set(desc_set, binding, gl_framebuffer->textures[texture_index]); 26 | } 27 | -------------------------------------------------------------------------------- /mod/opengl/OpenGLRenderPass.cpp: -------------------------------------------------------------------------------- 1 | #include "OpenGLRenderer.h" 2 | 3 | using namespace L; 4 | 5 | RenderPassImpl* OpenGLRenderer::create_render_pass(const RenderFormat*, size_t, bool, bool depth_write) { 6 | OpenGLRenderPass* render_pass = Memory::new_type(); 7 | render_pass->depth_write = depth_write; 8 | return render_pass; 9 | } 10 | void OpenGLRenderer::destroy_render_pass(RenderPassImpl* render_pass) { 11 | Memory::delete_type((OpenGLRenderPass*)render_pass); 12 | } 13 | -------------------------------------------------------------------------------- /mod/opengl/OpenGLUniformBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "OpenGLRenderer.h" 2 | 3 | using namespace L; 4 | 5 | L::UniformBufferImpl* OpenGLRenderer::create_uniform_buffer(size_t size) { 6 | L_SCOPE_THREAD_MASK(1); 7 | 8 | OpenGLUniformBuffer* uniform_buffer = Memory::new_type(); 9 | glCreateBuffers(1, &uniform_buffer->id); 10 | glNamedBufferData(uniform_buffer->id, size, nullptr, GL_DYNAMIC_DRAW); 11 | return uniform_buffer; 12 | } 13 | void OpenGLRenderer::destroy_uniform_buffer(UniformBufferImpl* uniform_buffer) { 14 | OpenGLUniformBuffer* gl_uniform_buffer = (OpenGLUniformBuffer*)uniform_buffer; 15 | glDeleteBuffers(1, &gl_uniform_buffer->id); 16 | Memory::delete_type(gl_uniform_buffer); 17 | } 18 | void OpenGLRenderer::load_uniform_buffer(UniformBufferImpl* uniform_buffer, const void* data, size_t size, size_t offset) { 19 | L_SCOPE_THREAD_MASK(1); 20 | 21 | OpenGLUniformBuffer* gl_uniform_buffer = (OpenGLUniformBuffer*)uniform_buffer; 22 | glNamedBufferSubData(gl_uniform_buffer->id, offset, size, data); 23 | } 24 | -------------------------------------------------------------------------------- /mod/opengl/module.cmake: -------------------------------------------------------------------------------- 1 | set(OpenGL_GL_PREFERENCE GLVND) 2 | find_package(OpenGL) 3 | if(NOT OpenGL_OpenGL_FOUND) 4 | return() 5 | endif() 6 | 7 | set(GL_LIBRARIES ${OPENGL_gl_LIBRARY}) 8 | if(EXISTS ${OPENGL_opengl_LIBRARY}) 9 | list(APPEND GL_LIBRARIES ${OPENGL_opengl_LIBRARY}) 10 | endif() 11 | if(OpenGL_GLX_FOUND) 12 | list(APPEND GL_LIBRARIES ${OPENGL_glx_LIBRARY}) 13 | endif() 14 | 15 | add_module( 16 | opengl 17 | INCLUDE_DIRS ${OPENGL_INCLUDE_DIR} 18 | LIBRARIES ${GL_LIBRARIES} 19 | OPT_MOD_DEPENDENCIES win32 xlib 20 | EXT_DEPENDENCIES spirv_cross opengl_registry egl_registry 21 | ) 22 | -------------------------------------------------------------------------------- /mod/opengl/opengl.cpp: -------------------------------------------------------------------------------- 1 | #include "OpenGLRenderer.h" 2 | 3 | using namespace L; 4 | 5 | void opengl_module_init() { 6 | static OpenGLRenderer renderer; 7 | } 8 | -------------------------------------------------------------------------------- /mod/pixel_font/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | pixel_font 3 | CONDITION ${DEV_DBG} 4 | MOD_DEPENDENCIES font_tools 5 | ) 6 | -------------------------------------------------------------------------------- /mod/pixel_font/pixel_font.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | using namespace L; 8 | 9 | static const Symbol pixel_symbol("pixel"); 10 | 11 | // Metrics: 12 | // Line height: 11px 13 | // Ascent: 8px 14 | // Descent: 2px 15 | // Size: 10px 16 | // Cap height: 7px 17 | // X height: 5px 18 | 19 | bool pixel_font_loader(ResourceSlot& slot, Font::Intermediate& intermediate) { 20 | if(slot.ext != pixel_symbol) { 21 | return false; 22 | } 23 | 24 | intermediate.line_height = 11.f / 10.f; 25 | intermediate.ascent = 8.f / 10.f; 26 | FontPacker helper(intermediate); 27 | 28 | #define O 0xff 29 | #define _ 0x0 30 | #define MAKE_GLYPH(utf32, width, height, ...) \ 31 | { \ 32 | const uint8_t bmp[]{__VA_ARGS__}; \ 33 | Font::Glyph& glyph(intermediate.glyphs[utf32]); \ 34 | glyph.size = {width / 10.f, height / 10.f}; \ 35 | glyph.origin = {1.f / 10.f, 3.f / 10.f}; \ 36 | glyph.advance = (width + 1) / 10.f; \ 37 | helper.add_glyph(bmp, width, height, glyph); \ 38 | } 39 | #include "glyphs.def" 40 | #undef MAKE_GLYPH 41 | 42 | ResourceLoading::transform_internal(slot, intermediate.texture_intermediate); 43 | 44 | return true; 45 | } 46 | 47 | void pixel_font_module_init() { 48 | ResourceLoading::add_loader(pixel_font_loader); 49 | } 50 | -------------------------------------------------------------------------------- /mod/rawinput/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | rawinput 3 | CONDITION $ 4 | LIBRARIES hid 5 | ) 6 | -------------------------------------------------------------------------------- /mod/rmlui/RmlUiComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "rmlui.h" 8 | 9 | class RmlUiComponent : public L::TComponent { 10 | protected: 11 | struct EventListener : public Rml::EventListener { 12 | RmlUiSafeElement element; 13 | L::Ref function; 14 | L::ScriptContext script_context; 15 | 16 | virtual void ProcessEvent(Rml::Event& event) override; 17 | }; 18 | static L::Array _event_listeners; 19 | L::Camera* _camera; 20 | Rml::Context* _context; 21 | L::InputContext _input_context; 22 | 23 | public: 24 | RmlUiComponent(); 25 | ~RmlUiComponent(); 26 | 27 | virtual void update_components() override; 28 | static void script_registration(); 29 | 30 | void update(); 31 | 32 | RmlUiSafeElement load_document(const char* path); 33 | 34 | inline Rml::Context* get_context() { return _context; } 35 | 36 | #if !L_RLS 37 | void refresh(); 38 | #endif 39 | }; 40 | 41 | -------------------------------------------------------------------------------- /mod/rmlui/RmlUiFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "rmlui.h" 9 | 10 | class RmlUiFile : public Rml::FileInterface { 11 | protected: 12 | struct File { 13 | L::Resource resource; 14 | uintptr_t offset = 0; 15 | }; 16 | L::Table _files; 17 | L::Array> _resources; 18 | Rml::FileHandle _next_handle = 1; 19 | L::Date _mtime = 0; 20 | 21 | public: 22 | virtual Rml::FileHandle Open(const Rml::String& path) override; 23 | virtual void Close(Rml::FileHandle file) override; 24 | 25 | virtual size_t Read(void* buffer, size_t size, Rml::FileHandle file) override; 26 | virtual bool Seek(Rml::FileHandle file, long offset, int origin) override; 27 | virtual size_t Tell(Rml::FileHandle file) override; 28 | 29 | virtual size_t Length(Rml::FileHandle file) override; 30 | 31 | bool HasOutOfDateResources(); 32 | }; 33 | -------------------------------------------------------------------------------- /mod/rmlui/RmlUiFontEngine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "rmlui.h" 8 | 9 | class RmlUiFontEngine : public Rml::FontEngineInterface { 10 | protected: 11 | struct FontFace { 12 | L::Resource font; 13 | Rml::Texture* texture; 14 | int size, x_height, line_height, baseline; 15 | float underline; 16 | }; 17 | 18 | L::Array _font_faces; 19 | 20 | public: 21 | RmlUiFontEngine(); 22 | virtual bool LoadFontFace(const Rml::String& file_name, bool fallback_face) override; 23 | virtual bool LoadFontFace(const Rml::byte* data, int data_size, const Rml::String& family, Rml::Style::FontStyle style, Rml::Style::FontWeight weight, bool fallback_face) override; 24 | virtual Rml::FontFaceHandle GetFontFaceHandle(const Rml::String& family, Rml::Style::FontStyle style, Rml::Style::FontWeight weight, int size) override; 25 | 26 | virtual int GetSize(Rml::FontFaceHandle handle) override; 27 | virtual int GetXHeight(Rml::FontFaceHandle handle) override; 28 | virtual int GetLineHeight(Rml::FontFaceHandle handle) override; 29 | virtual int GetBaseline(Rml::FontFaceHandle handle) override; 30 | virtual float GetUnderline(Rml::FontFaceHandle handle, float& thickness) override; 31 | virtual int GetStringWidth(Rml::FontFaceHandle handle, const Rml::String& string, Rml::Character) override; 32 | virtual int GenerateString(Rml::FontFaceHandle handle, Rml::FontEffectsHandle font_effects_handle, const Rml::String& string, const Rml::Vector2f& position, const Rml::Colourb& colour, Rml::GeometryList& geometry_list) override; 33 | }; 34 | -------------------------------------------------------------------------------- /mod/rmlui/RmlUiRender.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "rmlui.h" 7 | #include "RmlUiComponent.h" 8 | 9 | class RmlUiRender : public Rml::RenderInterface { 10 | protected: 11 | struct MaterialTransform { 12 | L::Handle component; 13 | L::Material material; 14 | L::Matrix44f transform; 15 | }; 16 | 17 | L::Array _vertices; 18 | L::Array _indices; 19 | L::Resource _mesh; 20 | 21 | bool _enable_scissor = false; 22 | L::Interval2i _scissor; 23 | 24 | L::Handle _current_component; 25 | L::Array _material_transforms; 26 | L::Array> _textures; 27 | L::Array> _fonts; 28 | const size_t _font_offset = 1 << 24; 29 | 30 | L::Resource _shader_vert, _shader_frag, _shader_frag_tex, _shader_frag_font; 31 | 32 | public: 33 | RmlUiRender(); 34 | virtual void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle resource, const Rml::Vector2f& translation) override; 35 | virtual void EnableScissorRegion(bool enable) override; 36 | virtual void SetScissorRegion(int x, int y, int width, int height) override; 37 | virtual bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override; 38 | 39 | void Init(); 40 | void Shutdown(); 41 | void Update(); 42 | void Render(const class L::Camera& camera); 43 | }; 44 | -------------------------------------------------------------------------------- /mod/rmlui/RmlUiSystem.cpp: -------------------------------------------------------------------------------- 1 | #include "RmlUiSystem.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace L; 7 | 8 | double RmlUiSystem::GetElapsedTime() { 9 | return Time::now().seconds_float(); 10 | } 11 | bool RmlUiSystem::LogMessage(Rml::Log::Type type, const Rml::String& message) { 12 | switch(type) { 13 | case Rml::Log::Type::LT_ERROR: 14 | case Rml::Log::Type::LT_ASSERT: 15 | case Rml::Log::Type::LT_WARNING: 16 | warning("rmlui: %s", message.c_str()); 17 | break; 18 | case Rml::Log::Type::LT_INFO: 19 | #if L_DBG 20 | case Rml::Log::Type::LT_DEBUG: 21 | #endif 22 | log("rmlui: %s", message.c_str()); 23 | break; 24 | default: break; 25 | } 26 | return true; 27 | } 28 | -------------------------------------------------------------------------------- /mod/rmlui/RmlUiSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rmlui.h" 4 | 5 | class RmlUiSystem : public Rml::SystemInterface { 6 | virtual double GetElapsedTime() override; 7 | virtual bool LogMessage(Rml::Log::Type type, const Rml::String& message) override; 8 | }; 9 | -------------------------------------------------------------------------------- /mod/rmlui/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | rmlui 3 | EXT_DEPENDENCIES rmlui 4 | ) 5 | -------------------------------------------------------------------------------- /mod/rmlui/rmlui.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "RmlUiFile.h" 4 | #include "RmlUiFontEngine.h" 5 | #include "RmlUiRender.h" 6 | #include "RmlUiSystem.h" 7 | 8 | using namespace L; 9 | 10 | static RmlUiFile file_implementation; 11 | static RmlUiFontEngine font_engine_implementation; 12 | static RmlUiRender render_implementation; 13 | static RmlUiSystem system_implementation; 14 | 15 | static void rmlui_update() { 16 | #if !L_RLS 17 | if(file_implementation.HasOutOfDateResources()) { 18 | ComponentPool::iterate( 19 | [&](RmlUiComponent& component) { 20 | component.refresh(); 21 | }); 22 | } 23 | #endif 24 | render_implementation.Update(); 25 | } 26 | 27 | static void rmlui_gui(const class Camera& camera) { 28 | render_implementation.Render(camera); 29 | } 30 | 31 | void rmlui_module_init() { 32 | Rml::SetFileInterface(&file_implementation); 33 | Rml::SetFontEngineInterface(&font_engine_implementation); 34 | Rml::SetRenderInterface(&render_implementation); 35 | Rml::SetSystemInterface(&system_implementation); 36 | 37 | if(!Rml::Initialise()) { 38 | warning("rmlui: Could not initialize"); 39 | return; 40 | } 41 | 42 | Engine::register_component(); 43 | 44 | // Defer init because we need resources and task system up 45 | Engine::add_deferred_action(Engine::DeferredAction { 46 | [](void*) { 47 | render_implementation.Init(); 48 | Engine::add_update(rmlui_update); 49 | Engine::add_gui(rmlui_gui); 50 | }}); 51 | 52 | Engine::add_shutdown( 53 | []() { 54 | render_implementation.Shutdown(); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /mod/rmlui/rmlui.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | L_PUSH_NO_WARNINGS 6 | 7 | #define RMLUI_STATIC_LIB 8 | #define RMLUI_USE_CUSTOM_RTTI 9 | #define RMLUI_NO_THIRDPARTY_CONTAINERS 10 | #include 11 | #include 12 | 13 | L_POP_NO_WARNINGS 14 | 15 | typedef Rml::ObserverPtr RmlUiSafeElement; 16 | -------------------------------------------------------------------------------- /mod/robin/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | robin 3 | EXT_DEPENDENCIES robin 4 | ) 5 | -------------------------------------------------------------------------------- /mod/script_material/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | script_material 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/script_material/script_material.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace L; 6 | 7 | bool script_material_loader(ResourceSlot& slot, Material& intermediate) { 8 | ScriptFunction::Intermediate script_intermediate; 9 | if(ResourceLoading::load_internal(slot, script_intermediate)) { 10 | ScriptContext context(intermediate.handle()); 11 | context.execute(ref(script_intermediate)); 12 | return true; 13 | } 14 | return false; 15 | } 16 | 17 | void script_material_module_init() { 18 | ResourceLoading::add_loader(script_material_loader); 19 | } 20 | -------------------------------------------------------------------------------- /mod/script_mesh/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | script_mesh 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/script_optimize/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | script_optimize 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/script_server/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | script_server 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/script_texture/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | script_texture 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/shader_reflect/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | shader_reflect 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/stb_dxt/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | stb_dxt 3 | CONDITION ${DEV_DBG} 4 | EXT_DEPENDENCIES stb 5 | ) 6 | -------------------------------------------------------------------------------- /mod/stb_image/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | stb_image 3 | DEFAULT_ENABLED ON 4 | CONDITION ${DEV_DBG} 5 | EXT_DEPENDENCIES stb 6 | ) 7 | -------------------------------------------------------------------------------- /mod/stb_image/stb_image.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | L_PUSH_NO_WARNINGS 7 | 8 | #define STB_IMAGE_IMPLEMENTATION 9 | #define STB_IMAGE_STATIC 10 | #include 11 | 12 | L_POP_NO_WARNINGS 13 | 14 | using namespace L; 15 | 16 | static const Array extensions = { 17 | "bmp", 18 | "gif", 19 | "hdr", 20 | "jpeg", 21 | "jpg", 22 | "pgm", 23 | "png", 24 | "ppm", 25 | "psd", 26 | "tga", 27 | }; 28 | 29 | bool stb_image_loader(ResourceSlot& slot, Texture::Intermediate& intermediate) { 30 | if(!extensions.find(slot.ext)) { 31 | return false; 32 | } 33 | 34 | int width, height, components; 35 | uint8_t* img; 36 | { 37 | Buffer buffer(slot.read_source_file()); 38 | L_SCOPE_MARKER("stbi_load_from_memory"); 39 | img = stbi_load_from_memory((const stbi_uc*)buffer.data(), int(buffer.size()), &width, &height, &components, 4); 40 | } 41 | if(img) { 42 | intermediate.width = width; 43 | intermediate.height = height; 44 | intermediate.format = RenderFormat::R8G8B8A8_UNorm; 45 | intermediate.mips.push(Buffer(img, width * height * 4)); 46 | stbi_image_free(img); 47 | return true; 48 | } else { 49 | warning("stb_image: %s: %s", slot.id, stbi_failure_reason()); 50 | return false; 51 | } 52 | } 53 | 54 | void stb_image_module_init() { 55 | ResourceLoading::add_loader(stb_image_loader); 56 | } 57 | -------------------------------------------------------------------------------- /mod/stb_perlin/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | stb_perlin 3 | CONDITION ${DEV_DBG} 4 | EXT_DEPENDENCIES stb 5 | ) 6 | -------------------------------------------------------------------------------- /mod/stb_truetype/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | stb_truetype 3 | CONDITION ${DEV_DBG} 4 | EXT_DEPENDENCIES stb 5 | MOD_DEPENDENCIES font_tools 6 | ) 7 | -------------------------------------------------------------------------------- /mod/stb_vorbis/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | stb_vorbis 3 | EXT_DEPENDENCIES stb 4 | ) 5 | -------------------------------------------------------------------------------- /mod/steamworks/module.cmake: -------------------------------------------------------------------------------- 1 | set(L_STEAMWORKS_SDK "" CACHE PATH "Path to the wanted Steamworks SDK") 2 | 3 | if("${L_STEAMWORKS_SDK}" STREQUAL "") 4 | message("Steamworks SDK not set up") 5 | return() 6 | endif() 7 | 8 | if(NOT EXISTS "${L_STEAMWORKS_SDK}/public/steam/steam_api.h") 9 | message("Invalid Steamworks SDK location (cannot find steam_api.h)") 10 | return() 11 | endif() 12 | 13 | add_module( 14 | steamworks 15 | SYSTEM_INCLUDE_DIRS ${L_STEAMWORKS_SDK}/public 16 | LIBRARIES ${L_STEAMWORKS_SDK}/redistributable_bin/win64/steam_api64.lib 17 | ) 18 | -------------------------------------------------------------------------------- /mod/test_compression/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | test_compression 3 | CONDITION ${DEV_DBG} 4 | MOD_DEPENDENCIES lz zlib 5 | ) 6 | -------------------------------------------------------------------------------- /mod/test_hashing/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | test_hashing 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/test_memory/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | test_memory 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/test_random/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | test_random 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/test_random/test_random.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace L; 8 | 9 | constexpr uintptr_t max_width = 1 << 8; 10 | constexpr uintptr_t iterations = max_width * 128; 11 | 12 | void test_random_module_init() { 13 | Test test_random{}; 14 | test_random.name = "random"; 15 | test_random.func = []() { 16 | uint64_t dist[max_width] = {}; 17 | float max_variance = 0.f; 18 | bool success = true; 19 | 20 | for(uintptr_t width = 2; width < max_width; width++) { 21 | memset(dist, 0, sizeof(uint64_t) * width); 22 | 23 | for(uintptr_t i = 0; i < iterations; i++) { 24 | uint64_t value = Rand::next(width); 25 | if(value >= width) { 26 | warning("test_random: bounded uint64_t next returned number out-of-bounds"); 27 | continue; 28 | } 29 | 30 | dist[value] += 1; 31 | } 32 | 33 | uint64_t min_value = dist[0]; 34 | uint64_t max_value = dist[0]; 35 | for(uintptr_t i = 0; i < width; i++) { 36 | min_value = min(min_value, dist[i]); 37 | max_value = max(max_value, dist[i]); 38 | } 39 | 40 | const float variance = 1.f - (float(min_value) / float(max_value)); 41 | if(variance > max_variance) { 42 | log("test_random: width=%d min=%d max=%d var=%.2f%%", width, min_value, max_value, variance * 100.f); 43 | max_variance = variance; 44 | } 45 | } 46 | return success; 47 | }; 48 | 49 | add_test(test_random); 50 | } 51 | -------------------------------------------------------------------------------- /mod/test_serialization/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | test_serialization 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/vulkan/VulkanBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "VulkanRenderer.h" 6 | 7 | class VulkanBuffer { 8 | L_NOCOPY(VulkanBuffer) 9 | protected: 10 | VkBuffer _buffer; 11 | VkDeviceMemory _memory; 12 | VkDeviceSize _size; 13 | VkBufferUsageFlagBits _usage; 14 | public: 15 | VulkanBuffer(size_t size, VkBufferUsageFlagBits usage); 16 | ~VulkanBuffer(); 17 | 18 | inline void load(const void* data) { load(data, _size); } 19 | void load(const void* data, size_t size, size_t offset = 0); 20 | template void load_item(const T& datum, size_t offset = 0) { load(&datum, sizeof(T), offset); } 21 | 22 | inline VkDeviceSize size() const { return _size; } 23 | inline operator VkBuffer() { return _buffer; } 24 | inline operator VkDeviceMemory() { return _memory; } 25 | inline VkDescriptorBufferInfo descriptor_info() const { return {_buffer,0,_size}; } 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /mod/vulkan/VulkanMesh.cpp: -------------------------------------------------------------------------------- 1 | #include "VulkanRenderer.h" 2 | 3 | #include "VulkanBuffer.h" 4 | 5 | using namespace L; 6 | 7 | MeshImpl* VulkanRenderer::create_mesh(size_t, const void* data, size_t size, const VertexAttribute*, size_t, const uint16_t* iarray, size_t icount) { 8 | VulkanMesh* mesh = Memory::new_type(); 9 | 10 | mesh->vertex_buffer = Memory::new_type(size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); 11 | mesh->vertex_buffer->load(data); 12 | if(iarray) { 13 | mesh->index_buffer = Memory::new_type(icount * sizeof(*iarray), VK_BUFFER_USAGE_INDEX_BUFFER_BIT); 14 | mesh->index_buffer->load(iarray); 15 | } 16 | 17 | return mesh; 18 | } 19 | 20 | void VulkanRenderer::destroy_mesh(MeshImpl* mesh) { 21 | VulkanMesh* vk_mesh = (VulkanMesh*)mesh; 22 | if(vk_mesh->vertex_buffer) { 23 | Memory::delete_type(vk_mesh->vertex_buffer); 24 | vk_mesh->vertex_buffer = nullptr; 25 | } 26 | if(vk_mesh->index_buffer) { 27 | Memory::delete_type(vk_mesh->index_buffer); 28 | vk_mesh->index_buffer = nullptr; 29 | } 30 | Memory::delete_type(vk_mesh); 31 | } 32 | -------------------------------------------------------------------------------- /mod/vulkan/VulkanShader.cpp: -------------------------------------------------------------------------------- 1 | #include "VulkanRenderer.h" 2 | 3 | using namespace L; 4 | 5 | ShaderImpl* VulkanRenderer::create_shader(L::ShaderStage stage, const void* binary, size_t binary_size) { 6 | VulkanShader* shader = Memory::new_type(); 7 | shader->stage = to_vk_shader_stage(stage); 8 | 9 | VkShaderModuleCreateInfo create_info {}; 10 | create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 11 | create_info.codeSize = binary_size; 12 | create_info.pCode = (uint32_t*)binary; 13 | 14 | L_VK_CHECKED(vkCreateShaderModule(_device, &create_info, nullptr, &shader->module)); 15 | 16 | return shader; 17 | } 18 | void VulkanRenderer::destroy_shader(ShaderImpl* shader) { 19 | VulkanShader* vk_shader = (VulkanShader*)shader; 20 | vkDestroyShaderModule(_device, vk_shader->module, nullptr); 21 | } 22 | -------------------------------------------------------------------------------- /mod/vulkan/VulkanUniformBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "VulkanBuffer.h" 2 | 3 | using namespace L; 4 | 5 | L::UniformBufferImpl* VulkanRenderer::create_uniform_buffer(size_t size) { 6 | return (UniformBufferImpl*)Memory::new_type(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); 7 | } 8 | void VulkanRenderer::destroy_uniform_buffer(UniformBufferImpl* uniform_buffer) { 9 | Memory::delete_type((VulkanBuffer*)uniform_buffer); 10 | } 11 | void VulkanRenderer::load_uniform_buffer(UniformBufferImpl* uniform_buffer, const void* src, size_t size, size_t offset) { 12 | VulkanBuffer* vk_uniform_buffer = (VulkanBuffer*)uniform_buffer; 13 | vk_uniform_buffer->load(src, size, offset); 14 | } 15 | -------------------------------------------------------------------------------- /mod/vulkan/module.cmake: -------------------------------------------------------------------------------- 1 | find_package(Vulkan) 2 | if(NOT Vulkan_FOUND) 3 | return() 4 | endif() 5 | 6 | add_module( 7 | vulkan 8 | INCLUDE_DIRS ${Vulkan_INCLUDE_DIRS} 9 | LIBRARIES ${Vulkan_LIBRARIES} 10 | OPT_MOD_DEPENDENCIES win32 xlib 11 | ) 12 | -------------------------------------------------------------------------------- /mod/vulkan/vulkan.cpp: -------------------------------------------------------------------------------- 1 | #include "VulkanRenderer.h" 2 | 3 | using namespace L; 4 | 5 | void vulkan_module_init() { 6 | static VulkanRenderer renderer; 7 | } 8 | -------------------------------------------------------------------------------- /mod/wav/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | wav 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/wavefront_obj/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | wavefront_obj 3 | CONDITION ${DEV_DBG} 4 | ) 5 | -------------------------------------------------------------------------------- /mod/win32/include/win32.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | extern L::Symbol win32_window_type; 8 | 9 | struct Win32WindowData : public L::GenericWindowData { 10 | HMODULE module; 11 | HWND window; 12 | }; 13 | 14 | -------------------------------------------------------------------------------- /mod/win32/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | win32 3 | CONDITION $ 4 | ) 5 | -------------------------------------------------------------------------------- /mod/wwise/module.cmake: -------------------------------------------------------------------------------- 1 | if(NOT DEFINED ENV{WWISESDK}) 2 | message("Could NOT find Wwise") 3 | return() 4 | endif() 5 | 6 | set(WWISE_RLS_LIBRARIES 7 | AkSoundEngine 8 | AkMemoryMgr 9 | AkStreamMgr 10 | AkMusicEngine 11 | AkSpatialAudio 12 | ) 13 | set(WWISE_DBG_LIBRARIES ${WWISE_RLS_LIBRARIES}) 14 | list(APPEND WWISE_DBG_LIBRARIES CommunicationCentral) 15 | 16 | set(WWISE_ARCH x64_vc160) 17 | 18 | list(TRANSFORM WWISE_DBG_LIBRARIES PREPEND $ENV{WWISESDK}/${WWISE_ARCH}/Debug/lib/) 19 | list(TRANSFORM WWISE_RLS_LIBRARIES PREPEND $ENV{WWISESDK}/${WWISE_ARCH}/Release/lib/) 20 | 21 | add_module( 22 | wwise 23 | INCLUDE_DIRS 24 | $ENV{WWISESDK}/include 25 | $ENV{WWISESDK}/samples/SoundEngine/Common 26 | $ENV{WWISESDK}/samples/SoundEngine/Win32 27 | DBG_LIBRARIES ${WWISE_DBG_LIBRARIES} 28 | RLS_LIBRARIES ${WWISE_RLS_LIBRARIES} 29 | ) 30 | -------------------------------------------------------------------------------- /mod/xinput_unix/module.cmake: -------------------------------------------------------------------------------- 1 | find_path(XINPUT2_PATHS X11/extensions/XInput2.h) 2 | if(NOT XINPUT2_PATHS) 3 | message("Could NOT find XInput2") 4 | unset(XINPUT2_PATHS CACHE) 5 | return() 6 | else() 7 | unset(XINPUT2_PATHS CACHE) 8 | endif() 9 | 10 | add_module( 11 | xinput_unix 12 | CONDITION $ 13 | LIBRARIES dl 14 | ) 15 | -------------------------------------------------------------------------------- /mod/xinput_win/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | xinput_win 3 | CONDITION $ 4 | ) 5 | -------------------------------------------------------------------------------- /mod/xlib/include/xlib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | // Undefine conflicting macros 9 | #undef None 10 | #undef Always 11 | #undef Window 12 | 13 | extern L::Symbol xlib_window_type; 14 | 15 | struct XlibWindowData : public L::GenericWindowData { 16 | ::Display* display; 17 | ::Window window; 18 | }; 19 | 20 | -------------------------------------------------------------------------------- /mod/xlib/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | xlib 3 | CONDITION $ 4 | ) 5 | -------------------------------------------------------------------------------- /mod/yaml/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | yaml 3 | CONDITION ${DEV_DBG} 4 | EXT_DEPENDENCIES yaml 5 | ) 6 | -------------------------------------------------------------------------------- /mod/zlib/module.cmake: -------------------------------------------------------------------------------- 1 | add_module( 2 | zlib 3 | EXT_DEPENDENCIES zlib 4 | ) 5 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Environment and parameters 4 | 5 | mode=${1:-build} 6 | config=${2:-dev} # Configuration is development by default 7 | (uname -s | grep -iqE "mingw|cygwin|msys|windows") && windows=true || windows=false 8 | 9 | # Stats action 10 | 11 | if [ $mode = "stats" ] ; then 12 | printf "Core file count: " 13 | find src/* -type f | grep -E "\.(h|hpp|cpp|inl|def)$" | wc -l 14 | printf "Core line count: " 15 | find src/* -type f | grep -E "\.(h|hpp|cpp|inl|def)$" | xargs cat | wc -l 16 | printf "Module count: " 17 | find mod/* -maxdepth 0 -type d | wc -l 18 | printf "Module line count: " 19 | find mod/* -type f | grep -E "\.(h|hpp|cpp|inl|def)$" | xargs cat | wc -l 20 | exit 0 21 | fi 22 | 23 | # Configuration 24 | 25 | case $config in 26 | "dbg") 27 | exe="sample_dbg" 28 | config=Debug 29 | ;; 30 | "dev") 31 | exe="sample_dev" 32 | config=RelWithDebInfo 33 | ;; 34 | "rls") 35 | exe="sample" 36 | config=Release 37 | ;; 38 | *) 39 | echo "Unknown configuration: $config" 40 | exit 1; 41 | ;; 42 | esac 43 | 44 | mkdir -p bld 45 | if (cd bld && cmake -DCMAKE_BUILD_TYPE=$config ..) ; then # Run CMake 46 | if [ $mode = "open" ] ; then 47 | if $windows; then 48 | start ./bld/L.sln 49 | exit 0 50 | fi 51 | fi 52 | 53 | cmake --build bld --config $config 54 | 55 | success=$? 56 | 57 | if [ $success = 0 ] && [ $mode = "run" ] ; then 58 | shift 2 59 | (cd smp && ./$exe $*) # Execute program 60 | success=$? 61 | fi 62 | 63 | exit $success 64 | else # CMake failure 65 | exit 1 66 | fi 67 | -------------------------------------------------------------------------------- /smp/README.md: -------------------------------------------------------------------------------- 1 | # Sample 2 | 3 | ## Controls 4 | 5 | - `WASD`/`ZQSD` to move the camera 6 | - `Left-shift` to slow movement 7 | - Mouse to rotate 8 | - `Left-click` to throw cubes 9 | - `B` to play/stop Bach (ogg) 10 | - `G` to play/stop a guitar sound (wav) 11 | - `M` to play/stop Mozart (midi) 12 | - `C` to toggle cel-shading 13 | - `F5` to recreate the scene from script 14 | 15 | ### ImGui 16 | 17 | You can access ImGui windows via `Ctrl+F10` (which toggles the menu bar). 18 | 19 | You can also access the ImGui terminal via `Ctrl+F12`. 20 | 21 | ## Sources 22 | 23 | The smartphone, bush and jerrican models and textures are from [Marjolaine Paz](https://twitter.com/Linheha). 24 | 25 | The Damaged Helmet is from glTF sample models, by [theblueturtle_](https://sketchfab.com/theblueturtle_) under Creative Commons Attribution Non-commercial. 26 | 27 | The guitar sound is from [Glycocalix](https://twitter.com/glyc0calix). 28 | 29 | The Cello Suite No.1 in G Major Prelude (Johann Sebastian Bach) recording is by [Thomas Auner](http://www.thomas-auner.com/), under Creative Commons Attribution Non-commercial 3.0. 30 | 31 | The skybox is from someone on the internet called `The Mighty Pete`. 32 | -------------------------------------------------------------------------------- /smp/audio/bach.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/audio/bach.ogg -------------------------------------------------------------------------------- /smp/audio/guitar.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/audio/guitar.wav -------------------------------------------------------------------------------- /smp/audio/mozart.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/audio/mozart.mid -------------------------------------------------------------------------------- /smp/material/DamagedHelmet.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/material/DamagedHelmet.glb -------------------------------------------------------------------------------- /smp/material/Fox.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/material/Fox.glb -------------------------------------------------------------------------------- /smp/material/box.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/color.frag") 2 | (self.shader 'vertex "shader/color.vert") 3 | (self.mesh "mesh/cube.ls?fmt=pn") 4 | (self.color 'color "white") 5 | -------------------------------------------------------------------------------- /smp/material/bush.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/staticmesh.frag") 2 | (self.shader 'vertex "shader/staticmesh.vert") 3 | (self.mesh "mesh/bush.obj?fmt=pnu") 4 | (self.texture 'tex "texture/bush.png") 5 | (self.texture 'mat_tex "texture/default_mat.png") 6 | -------------------------------------------------------------------------------- /smp/material/dirlight.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/dirlight.frag") 2 | (self.shader 'vertex "shader/fullscreen.vert") 3 | (self.render_pass 'light) 4 | (self.vertex_count 3) 5 | (self.scalar 'intensity 1) 6 | (self.color 'color "white") 7 | -------------------------------------------------------------------------------- /smp/material/dirlight_cel.ls: -------------------------------------------------------------------------------- 1 | (self.parent "material/dirlight.ls") 2 | (self.shader 'fragment "shader/dirlight_cel.frag") 3 | -------------------------------------------------------------------------------- /smp/material/jerrican.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/staticmesh.frag") 2 | (self.shader 'vertex "shader/staticmesh.vert") 3 | (self.mesh "mesh/jerrican.obj?fmt=pnu") 4 | (self.texture 'tex "texture/jerrican.png") 5 | (self.texture 'mat_tex "texture/jerrican_mat.png") 6 | -------------------------------------------------------------------------------- /smp/material/outline.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/outline.frag") 2 | (self.shader 'vertex "shader/fullscreen.vert") 3 | (self.render_pass 'light) 4 | (self.vertex_count 3) 5 | (self.scalar 'thickness 1) 6 | -------------------------------------------------------------------------------- /smp/material/pixel_text.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/font.frag") 2 | (self.shader 'vertex "shader/font.vert") 3 | (self.render_pass 'present) 4 | (self.font ".pixel") 5 | (self.color 'color "white") 6 | -------------------------------------------------------------------------------- /smp/material/pointlight.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/pointlight.frag") 2 | (self.shader 'vertex "shader/color.vert") 3 | (self.mesh "mesh/sphere.ls?fmt=pn") 4 | (self.cull_mode 'front) 5 | (self.depth_func 'greater) 6 | (self.render_pass 'light) 7 | (self.scalar 'intensity 1) 8 | (self.vector 'color "white") 9 | -------------------------------------------------------------------------------- /smp/material/pointlight_cel.ls: -------------------------------------------------------------------------------- 1 | (self.parent "material/pointlight.ls") 2 | (self.shader 'fragment "shader/pointlight_cel.frag") 3 | -------------------------------------------------------------------------------- /smp/material/sky.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/sky.frag") 2 | (self.shader 'vertex "shader/sky.vert") 3 | (self.mesh "mesh/sphere.ls?fmt=n") 4 | (self.cull_mode 'front) 5 | (self.texture 'cubemap "texture/skybox.png") 6 | -------------------------------------------------------------------------------- /smp/material/smartphone.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/staticmesh.frag") 2 | (self.shader 'vertex "shader/staticmesh.vert") 3 | (self.mesh "mesh/smartphone.obj?fmt=pnu") 4 | (self.texture 'tex "texture/smartphone.png") 5 | (self.texture 'mat_tex "texture/smartphone_mat.png") 6 | -------------------------------------------------------------------------------- /smp/material/sphere.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/color.frag") 2 | (self.shader 'vertex "shader/color.vert") 3 | (self.mesh "mesh/sphere.ls?fmt=pn") 4 | (self.vector 'color "white") 5 | -------------------------------------------------------------------------------- /smp/material/sphere_light.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/color_light.frag") 2 | (self.shader 'vertex "shader/color.vert") 3 | (self.render_pass 'light) 4 | (self.mesh "mesh/sphere.ls?fmt=pn") 5 | (self.vector 'color "white") 6 | -------------------------------------------------------------------------------- /smp/material/sprite.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/sprite.frag") 2 | (self.shader 'vertex "shader/sprite.vert") 3 | (self.vertex_count 6) 4 | (self.vector 'uv (vec 0 1 0 1)) 5 | -------------------------------------------------------------------------------- /smp/material/ssao.ls: -------------------------------------------------------------------------------- 1 | (self.shader 'fragment "shader/ssao.frag") 2 | (self.shader 'vertex "shader/fullscreen.vert") 3 | (self.render_pass 'light) 4 | (self.vertex_count 3) 5 | (self.vector 'color "white") 6 | (self.scalar 'radius 1) 7 | -------------------------------------------------------------------------------- /smp/material/terrain.ls: -------------------------------------------------------------------------------- 1 | (local size 128) 2 | (self.shader 'fragment "shader/terrain.frag") 3 | (self.shader 'vertex "shader/terrain.vert") 4 | (self.vertex_count (* size size 6)) 5 | (self.texture 'height_tex (+ ".stb_perlin?type=ridge&span=3&octaves=5&lacunarity=2.3&gain=0.35&size=" size)) 6 | (self.texture 'color_tex ".stb_perlin?type=turbulence&octaves=4&span=8&wrap=8&size=1024") 7 | (self.scalar 'size size) 8 | -------------------------------------------------------------------------------- /smp/mesh/cube.ls: -------------------------------------------------------------------------------- 1 | (local m self) 2 | (local face (fn p0 p1 p2 p3 n (do 3 | (m.push_position p0) 4 | (m.push_normal n) 5 | (m.push_position p1) 6 | (m.push_normal n) 7 | (m.push_position p2) 8 | (m.push_normal n) 9 | 10 | (m.push_position p0) 11 | (m.push_normal n) 12 | (m.push_position p2) 13 | (m.push_normal n) 14 | (m.push_position p3) 15 | (m.push_normal n) 16 | ))) 17 | 18 | (face (vec -1 -1 -1) (vec -1 -1 1) (vec -1 1 1) (vec -1 1 -1) (vec -1 0 0)) ; Left 19 | (face (vec 1 -1 -1) (vec 1 1 -1) (vec 1 1 1) (vec 1 -1 1) (vec 1 0 0)) ; Right 20 | (face (vec -1 -1 -1) (vec 1 -1 -1) (vec 1 -1 1) (vec -1 -1 1) (vec 0 -1 0)) ; Back 21 | (face (vec -1 1 -1) (vec -1 1 1) (vec 1 1 1) (vec 1 1 -1) (vec 0 1 0)) ; Front 22 | (face (vec -1 -1 -1) (vec -1 1 -1) (vec 1 1 -1) (vec 1 -1 -1) (vec 0 0 -1)) ; Bottom 23 | (face (vec -1 -1 1) (vec 1 -1 1) (vec 1 1 1) (vec -1 1 1) (vec 0 0 1)) ; Top 24 | -------------------------------------------------------------------------------- /smp/mesh/sphere.ls: -------------------------------------------------------------------------------- 1 | (local m self) 2 | (local div 4) 3 | (local div2 (* div div)) 4 | 5 | (local push_pos (fn p (do 6 | (set p (normalize p)) 7 | (m.push_position p) 8 | (m.push_normal p) 9 | ))) 10 | 11 | (local subface (fn p0 p1 p2 p3 (do 12 | (push_pos p0) 13 | (push_pos p1) 14 | (push_pos p2) 15 | 16 | (push_pos p0) 17 | (push_pos p2) 18 | (push_pos p3) 19 | ))) 20 | 21 | (local face (fn o xa ya (do 22 | (local i 0) 23 | (local xad (/ xa div)) 24 | (local yad (/ ya div)) 25 | (while (< i div2) (do 26 | (local x0i (floor (/ i div))) 27 | (local y0i (floor (% i div))) 28 | (local x1i (+ x0i 1)) 29 | (local y1i (+ y0i 1)) 30 | (local x0 (* x0i xad)) 31 | (local y0 (* y0i yad)) 32 | (local x1 (* x1i xad)) 33 | (local y1 (* y1i yad)) 34 | (subface (+ o x0 y0) (+ o x1 y0) (+ o x1 y1) (+ o x0 y1)) 35 | (+= i 1) 36 | )) 37 | ))) 38 | 39 | (face (vec -1 -1 -1) (vec 0 0 2) (vec 0 2 0)) ; Left 40 | (face (vec 1 -1 -1) (vec 0 2 0) (vec 0 0 2)) ; Right 41 | (face (vec -1 -1 -1) (vec 2 0 0) (vec 0 0 2)) ; Back 42 | (face (vec -1 1 -1) (vec 0 0 2) (vec 2 0 0)) ; Front 43 | (face (vec -1 -1 -1) (vec 0 2 0) (vec 2 0 0)) ; Bottom 44 | (face (vec -1 -1 1) (vec 2 0 0) (vec 0 2 0)) ; Top 45 | -------------------------------------------------------------------------------- /smp/project.cmake: -------------------------------------------------------------------------------- 1 | add_project( 2 | sample 3 | SCRIPT_INIT_FILE script/ini.ls 4 | # This project purposefully depends on a lot of modules because it tries to showcase as many of them as possible 5 | MOD_DEPENDENCIES 6 | alsa # Audio on Linux 7 | assimp # .glb files 8 | audio_win # Audio on Windows 9 | cro_mipmap # Generate mipmaps for textures 10 | glslang 11 | imgui_console 12 | imgui_game_platform 13 | imgui_input 14 | imgui_resources 15 | lasm # script/proxy.lasm 16 | ls # Most scripts 17 | lz # Custom compression algorithm 18 | mesh_format 19 | mid # audio/mozart.mid 20 | midi_win # Playing MIDI events on Windows 21 | pixel_font # For the frame counter 22 | rawinput 23 | script_material 24 | script_mesh # mesh/*.ls 25 | script_optimize 26 | script_texture 27 | shader_reflect 28 | stb_dxt 29 | stb_image # texture/*.png 30 | stb_perlin # Terrain primitive 31 | stb_truetype 32 | stb_vorbis # audio/bach.ogg 33 | wav # audio/guitar.wav 34 | wavefront_obj # mesh/*.obj 35 | win32 36 | xinput_unix 37 | xinput_win 38 | xlib 39 | zlib 40 | 41 | # OpenGL and Vulkan have optional dependencies on win32 and xlib, for now it's better to put it at the end 42 | # TODO: later optional dependencies should be re-evaluated at the end 43 | opengl 44 | vulkan 45 | ) 46 | -------------------------------------------------------------------------------- /smp/script/ini.ls: -------------------------------------------------------------------------------- 1 | (setting 'fullscreen 0) 2 | (setting 'resolution_x 1024) 3 | (setting 'resolution_y 768) 4 | (setting 'resizable_window 1) 5 | (setting 'render_collider 0) 6 | (setting 'render_skeletal_animator 0) 7 | (engine_clear_and_read "script/proxy.lasm") 8 | -------------------------------------------------------------------------------- /smp/script/proxy.lasm: -------------------------------------------------------------------------------- 1 | loadglobal 2 engine_clear_and_read 2 | loadconst 4 "script/startup.ls" 3 | call 2 1 4 | -------------------------------------------------------------------------------- /smp/script/sink.ls: -------------------------------------------------------------------------------- 1 | ; Big low collider that destroys everything to avoid ever falling garbage 2 | 3 | (set self.start (fn (do 4 | (self.entity.require_transform|.move (vec 0 0 -128)) 5 | (self.entity.require_collider|.box (vec 4096 4096 64)) 6 | ))) 7 | 8 | (set self.event (fn e (do 9 | (if (= e.type 'Collision) (entity_destroy (e.other.entity))) 10 | ))) 11 | -------------------------------------------------------------------------------- /smp/script/startup.ls: -------------------------------------------------------------------------------- 1 | (set rand_range (fn min max (+ min (* (- max min) (rand))))) 2 | (set rand_color (fn (color (rand) (rand) (rand)))) 3 | 4 | (engine_gravity (vec 0 0 -9.8)) 5 | ;(engine_gravity (vec 0 0 0)) 6 | ;(engine_timescale 0.1) 7 | (entity_make|.add_script|.load "script/camera.ls") 8 | (entity_make "scene"|.add_group|.level_script "script/scene.ls") 9 | 10 | (set mozart_source (entity_make|.require_midi_source)) 11 | (mozart_source.sequence "audio/mozart.mid") 12 | 13 | (set guitar_source (entity_make|.require_audio_source)) 14 | (guitar_source.stream "audio/guitar.wav") 15 | 16 | (set bach_source (entity_make|.require_audio_source)) 17 | (bach_source.stream "audio/bach.ogg") 18 | -------------------------------------------------------------------------------- /smp/shader/alpha_lib.glsl: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | float gold_noise(in vec2 coordinate, in float seed) { 4 | float noise = fract(tan(distance(coordinate * (seed + PHI * 0.1f), vec2(PHI * 0.1f, PI * 0.1f))) * SQ2 * 10000.f); 5 | return isnan(noise) ? 0.f : noise; 6 | } 7 | float frag_noise() { 8 | return gold_noise(gl_FragCoord.xy, frame % 4); 9 | } 10 | bool alpha(float a) { 11 | return a < clamp(frag_noise(), 0.01f, 0.99f); 12 | } 13 | -------------------------------------------------------------------------------- /smp/shader/color.frag: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | layout(binding = 1) uniform Parameters { 4 | vec4 color; 5 | }; 6 | 7 | layout(location = 0) in vec3 fnormal; 8 | layout(location = 0) out vec4 ocolor; 9 | layout(location = 1) out vec4 onormal; 10 | 11 | void main() { 12 | if(alpha(color.a)) { 13 | discard; 14 | } 15 | ocolor.rgb = linearize(color.rgb); 16 | ocolor.a = 0.f; /* Metalness */ 17 | onormal.xy = encodeNormal(fnormal); 18 | onormal.z = 0.8f; /* Roughness */ 19 | onormal.w = 0.f; /* Emission */ 20 | } 21 | -------------------------------------------------------------------------------- /smp/shader/color.vert: -------------------------------------------------------------------------------- 1 | layout(location = 0) in vec3 vposition; 2 | layout(location = 1) in vec3 vnormal; 3 | 4 | layout(location = 0) out vec3 fnormal; 5 | 6 | void main() { 7 | fnormal = normalize(mat3(model) * vnormal); 8 | gl_Position = viewProj * model * vec4(vposition, 1.f); 9 | } 10 | -------------------------------------------------------------------------------- /smp/shader/color_light.frag: -------------------------------------------------------------------------------- 1 | layout(binding = 1) uniform Parameters { 2 | vec4 color; 3 | }; 4 | 5 | layout(location = 0) out vec4 ocolor; 6 | 7 | void main() { 8 | ocolor = color; 9 | } 10 | -------------------------------------------------------------------------------- /smp/shader/constants.glsl: -------------------------------------------------------------------------------- 1 | const float PI = 3.14159265359f; 2 | const float PHI = 1.61803398874989484820459; 3 | const float SQ2 = 1.41421356237309504880169; 4 | -------------------------------------------------------------------------------- /smp/shader/dirlight.frag: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | layout(location = 0) out vec4 fragcolor; 4 | 5 | layout(binding = 1) uniform Parameters { 6 | vec4 color; 7 | float intensity; 8 | }; 9 | 10 | layout(binding = 2) uniform sampler2D color_buffer; 11 | layout(binding = 3) uniform sampler2D normal_buffer; 12 | layout(binding = 4) uniform sampler2D depth_buffer; 13 | 14 | void main() { 15 | GBufferSample gbuffer = sample_gbuffer(color_buffer, normal_buffer, depth_buffer); 16 | vec3 world_dir = mat3(model) * vec3(0,1,0); 17 | vec3 to_light_dir = normalize(-world_dir); 18 | vec3 view_dir = normalize(eye.xyz - gbuffer.position); 19 | vec3 halfway = normalize(view_dir+to_light_dir); 20 | vec3 radiance = color.rgb*intensity; 21 | vec3 F0 = mix(vec3(0.04f),gbuffer.color,gbuffer.metalness); 22 | vec3 F = fresnel_schlick(max(dot(halfway,view_dir),0.f),F0); 23 | float NDF = distribution_GGX(gbuffer.normal,halfway,gbuffer.roughness); 24 | float G = geometry_smith(gbuffer.normal,view_dir,to_light_dir,gbuffer.roughness); 25 | vec3 spec = specular(NDF,G,F,gbuffer.normal,view_dir,to_light_dir); 26 | vec3 diff = (vec3(1.0)-F) * (1.f-gbuffer.metalness) * gbuffer.color; 27 | float NdotL = max(dot(gbuffer.normal, to_light_dir), 0.0); 28 | fragcolor.rgb = (diff / PI + spec) * radiance * NdotL; 29 | fragcolor.a = 1.f; 30 | } 31 | -------------------------------------------------------------------------------- /smp/shader/dirlight_cel.frag: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | layout(location = 0) out vec4 fragcolor; 4 | 5 | layout(binding = 1) uniform Parameters { 6 | vec4 color; 7 | float intensity; 8 | }; 9 | 10 | layout(binding = 2) uniform sampler2D color_buffer; 11 | layout(binding = 3) uniform sampler2D normal_buffer; 12 | layout(binding = 4) uniform sampler2D depth_buffer; 13 | 14 | void main() { 15 | GBufferSample gbuffer = sample_gbuffer(color_buffer, normal_buffer, depth_buffer); 16 | vec3 world_dir = mat3(model) * vec3(0,1,0); 17 | vec3 to_light_dir = normalize(-world_dir); 18 | vec3 light_color = color.rgb * intensity; 19 | fragcolor = cel_shading(gbuffer, light_color, to_light_dir, 0.f); 20 | } 21 | -------------------------------------------------------------------------------- /smp/shader/font.frag: -------------------------------------------------------------------------------- 1 | layout(location = 0) in vec2 ftexcoords; 2 | 3 | layout(location = 0) out vec4 ocolor; 4 | 5 | layout(binding = 1) uniform Parameters { 6 | vec4 color; 7 | }; 8 | layout(binding = 2) uniform sampler2D atlas; 9 | 10 | void main() { 11 | ocolor = color; 12 | const float dist = texture(atlas, ftexcoords).r; 13 | const vec2 tex_size = textureSize(atlas, 0); 14 | const float range = dFdx(ftexcoords.x)*tex_size.x*0.015f; // Change to adjust crispness 15 | const float thickness_border = 0.05f; 16 | const float thickness = 0.5f; 17 | const float total_thickness = thickness + thickness_border; 18 | ocolor.rgb *= smoothstep(range, 0.f, dist-thickness+range*0.5f); 19 | ocolor.a *= smoothstep(range, 0.f, dist-total_thickness+range*0.5f); 20 | } 21 | -------------------------------------------------------------------------------- /smp/shader/font.vert: -------------------------------------------------------------------------------- 1 | layout(location = 0) in vec2 vpositionfont; // Shitty names until actual reflection 2 | layout(location = 1) in vec2 vtexcoordsfont; 3 | 4 | layout(location = 0) out vec2 ftexcoords; 5 | 6 | void main() { 7 | ftexcoords = vtexcoordsfont; 8 | gl_Position = model * vec4(vpositionfont,0.f,1.f); 9 | } 10 | -------------------------------------------------------------------------------- /smp/shader/fullscreen.vert: -------------------------------------------------------------------------------- 1 | const vec2 vertices[] = vec2[](vec2(-1.f,-1.f),vec2(-1.f,3.f),vec2(3.f,-1.f)); 2 | 3 | void main() { 4 | gl_Position = vec4(vertices[gl_VertexIndex], 0.f, 1.f); 5 | } 6 | -------------------------------------------------------------------------------- /smp/shader/pointlight.frag: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | layout(location = 0) out vec4 fragcolor; 4 | 5 | layout(binding = 1) uniform Parameters { 6 | vec4 color; 7 | float intensity; 8 | }; 9 | 10 | layout(binding = 2) uniform sampler2D color_buffer; 11 | layout(binding = 3) uniform sampler2D normal_buffer; 12 | layout(binding = 4) uniform sampler2D depth_buffer; 13 | 14 | void main() { 15 | vec3 light_pos = model[3].xyz; 16 | float radius = length(model[0].xyz)*0.83; 17 | GBufferSample gbuffer = sample_gbuffer(color_buffer, normal_buffer, depth_buffer); 18 | vec3 frag_to_light = (light_pos-gbuffer.position); 19 | vec3 to_light_dir = normalize(frag_to_light); 20 | vec3 view_dir = normalize(eye.xyz - gbuffer.position); 21 | vec3 halfway = normalize(view_dir+to_light_dir); 22 | float dist = length(frag_to_light); 23 | float att = light_attenuation(dist,radius,intensity); 24 | vec3 radiance = color.rgb*att; 25 | vec3 F0 = mix(vec3(0.04f),gbuffer.color,gbuffer.metalness); 26 | vec3 F = fresnel_schlick(max(dot(halfway,view_dir),0.f),F0); 27 | float NDF = distribution_GGX(gbuffer.normal,halfway,gbuffer.roughness); 28 | float G = geometry_smith(gbuffer.normal,view_dir,to_light_dir,gbuffer.roughness); 29 | vec3 spec = specular(NDF,G,F,gbuffer.normal,view_dir,to_light_dir); 30 | vec3 diff = (vec3(1.0)-F) * (1.f-gbuffer.metalness) * gbuffer.color; 31 | float NdotL = max(dot(gbuffer.normal, to_light_dir), 0.0); 32 | fragcolor.rgb = (diff / PI + spec) * radiance * NdotL; 33 | fragcolor.a = 1.f; 34 | } 35 | -------------------------------------------------------------------------------- /smp/shader/pointlight_cel.frag: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | layout(location = 0) out vec4 fragcolor; 4 | 5 | layout(binding = 1) uniform Parameters { 6 | vec4 color; 7 | float intensity; 8 | }; 9 | 10 | layout(binding = 2) uniform sampler2D color_buffer; 11 | layout(binding = 3) uniform sampler2D normal_buffer; 12 | layout(binding = 4) uniform sampler2D depth_buffer; 13 | 14 | void main() { 15 | vec3 light_pos = model[3].xyz; 16 | float radius = length(model[0].xyz) * 0.83; 17 | GBufferSample gbuffer = sample_gbuffer(color_buffer, normal_buffer, depth_buffer); 18 | vec3 frag_to_light = light_pos - gbuffer.position; 19 | vec3 to_light_dir = normalize(frag_to_light); 20 | vec3 light_color = color.rgb * intensity; 21 | float dist = length(frag_to_light); 22 | fragcolor = cel_shading(gbuffer, light_color, to_light_dir, dist / radius); 23 | } 24 | -------------------------------------------------------------------------------- /smp/shader/present.frag: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | layout(binding = 1) uniform sampler2D light_buffer; 4 | layout(location = 0) out vec4 fragcolor; 5 | 6 | void main() { 7 | vec2 texcoords = gl_FragCoord.xy*viewport_pixel_size.zw; 8 | vec3 color = texture(light_buffer, texcoords).rgb; 9 | color = max(color, vec3(0.f)); 10 | color = pow(color, vec3(1.f/2.2f)); // Gamma correction 11 | color += frag_noise() * 0.005f; // Debanding 12 | fragcolor = vec4(color, 1.f); 13 | } 14 | -------------------------------------------------------------------------------- /smp/shader/quad.vert: -------------------------------------------------------------------------------- 1 | layout(location = 0) out vec2 ftexcoords; 2 | 3 | const vec2 vertices[] = vec2[]( 4 | vec2(-1.f,-1.f), 5 | vec2(-1.f,1.f), 6 | vec2(1.f,1.f), 7 | vec2(1.f,-1.f), 8 | vec2(-1.f,-1.f), 9 | vec2(1.f,1.f) 10 | ); 11 | 12 | void main() { 13 | ftexcoords = clamp(vertices[gl_VertexIndex], 0.f, 1.f); 14 | gl_Position = model * vec4(vertices[gl_VertexIndex], 0.f, 1.f); 15 | } 16 | -------------------------------------------------------------------------------- /smp/shader/sky.frag: -------------------------------------------------------------------------------- 1 | layout(location = 0) in vec3 fnormal; 2 | 3 | layout(location = 0) out vec4 ocolor; 4 | layout(location = 1) out vec4 onormal; 5 | 6 | layout(binding = 1) uniform samplerCube cubemap; 7 | 8 | void main() { 9 | vec4 color = texture(cubemap, fnormal); 10 | ocolor.rgb = linearize(color.rgb); 11 | ocolor.a = 0.f; // Metalness 12 | onormal.xy = encodeNormal(vec3(0.f, 0.f, 1.f)); 13 | onormal.z = 0.f; // Roughness 14 | onormal.w = 1.f; // Emission 15 | } 16 | -------------------------------------------------------------------------------- /smp/shader/sky.vert: -------------------------------------------------------------------------------- 1 | layout(location = 0) in vec3 vnormal; 2 | 3 | layout(location = 0) out vec3 fnormal; 4 | 5 | void main() { 6 | fnormal = vnormal; 7 | gl_Position = viewProj * vec4(vnormal * 512.f + eye.xyz, 1.f); 8 | } 9 | -------------------------------------------------------------------------------- /smp/shader/sprite.frag: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | layout(location = 0) in vec2 ftexcoords; 4 | layout(location = 1) in vec3 fnormal; 5 | 6 | layout(location = 0) out vec4 ocolor; 7 | layout(location = 1) out vec4 onormal; 8 | 9 | layout(binding = 2) uniform sampler2D tex; 10 | 11 | void main() { 12 | vec4 color = texture(tex,ftexcoords); 13 | if(alpha(color.a)) { 14 | discard; 15 | } 16 | ocolor.rgb = linearize(color.rgb); 17 | ocolor.a = 0.f; // Metalness 18 | onormal.xy = encodeNormal(fnormal); 19 | onormal.z = 1.f; // Roughness 20 | onormal.w = 0.f; // Emission 21 | } 22 | -------------------------------------------------------------------------------- /smp/shader/sprite.vert: -------------------------------------------------------------------------------- 1 | layout(location = 0) out vec2 ftexcoords; 2 | layout(location = 1) out vec3 fnormal; 3 | 4 | layout(binding = 1) uniform Parameters { 5 | vec4 uv; 6 | }; 7 | 8 | const int[] indices = int[](1,0,2,1,2,3); 9 | const vec4 vert = vec4(-1,1,-1,1); 10 | void main() { 11 | int index = indices[gl_VertexIndex]; 12 | ftexcoords = vec2(uv[index/2],uv[1-index%2+2]); 13 | fnormal = mat3(model)*vec3(0,-1,0); 14 | gl_Position = viewProj * model * vec4(vert[index/2],0.f,vert[index%2+2],1.f); 15 | } 16 | -------------------------------------------------------------------------------- /smp/shader/staticmesh.frag: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | layout(location = 0) in vec3 fposition; 4 | layout(location = 1) in vec2 ftexcoords; 5 | layout(location = 2) in vec3 fnormal; 6 | 7 | layout(location = 0) out vec4 ocolor; 8 | layout(location = 1) out vec4 onormal; 9 | 10 | layout(binding = 1) uniform sampler2D tex; 11 | layout(binding = 2) uniform sampler2D mat_tex; 12 | 13 | vec3 derive_normal(vec3 p, vec3 n, float h){ 14 | vec3 dpdx = dFdx(p); 15 | vec3 dpdy = dFdy(p); 16 | float dhdx = dFdx(h); 17 | float dhdy = dFdy(h); 18 | vec3 r1 = cross(dpdy, n); 19 | vec3 r2 = cross(n, dpdx); 20 | vec3 g = (r1 * dhdx + r2 * dhdy) / dot(dpdx, r1); 21 | return normalize(n - g); 22 | } 23 | 24 | void main() { 25 | vec4 color = texture(tex,ftexcoords); 26 | if(alpha(color.a)) { 27 | discard; 28 | } 29 | vec4 material = texture(mat_tex,ftexcoords); 30 | ocolor.rgb = linearize(color.rgb); 31 | ocolor.a = material.y; /* Metalness */ 32 | onormal.xy = encodeNormal(derive_normal(fposition, fnormal, material.x)); 33 | onormal.z = material.z; /* Roughness */ 34 | onormal.w = material.w; /* Emission */ 35 | } 36 | -------------------------------------------------------------------------------- /smp/shader/staticmesh.vert: -------------------------------------------------------------------------------- 1 | layout(location = 0) in vec3 vposition; 2 | layout(location = 1) in vec3 vnormal; 3 | layout(location = 2) in vec2 vtexcoords; 4 | 5 | layout(location = 0) out vec3 fposition; 6 | layout(location = 1) out vec2 ftexcoords; 7 | layout(location = 2) out vec3 fnormal; 8 | 9 | void main() { 10 | ftexcoords = vtexcoords; 11 | fnormal = normalize(mat3(model) * vnormal); 12 | vec4 position = model * vec4(vposition,1.0); 13 | fposition = position.xyz; 14 | gl_Position = viewProj * position; 15 | } 16 | -------------------------------------------------------------------------------- /smp/shader/terrain.frag: -------------------------------------------------------------------------------- 1 | layout(location = 0) in vec3 ftexcoords; 2 | layout(location = 1) in vec3 fnormal; 3 | 4 | layout(location = 0) out vec4 ocolor; 5 | layout(location = 1) out vec4 onormal; 6 | 7 | layout(binding = 4) uniform sampler2D color_tex; 8 | 9 | void main() { 10 | ocolor.rgb = mix(vec3(0, 0.3, 0), vec3(0.8, 0.8, 1), ftexcoords.z); 11 | ocolor.rgb *= mix(0.75, 1.0, texture(color_tex, ftexcoords.xy * 4.f).x); 12 | ocolor.a = 0.f; // Metalness 13 | onormal.xy = encodeNormal(fnormal); 14 | onormal.z = 0.8f; // Roughness 15 | onormal.w = 0.f; // Emission 16 | } 17 | -------------------------------------------------------------------------------- /smp/shader/terrain.vert: -------------------------------------------------------------------------------- 1 | layout(location = 0) out vec3 ftexcoords; 2 | layout(location = 1) out vec3 fnormal; 3 | 4 | layout(binding = 2) uniform sampler2D height_tex; 5 | 6 | layout(binding = 3) uniform Parameters { 7 | float size; 8 | }; 9 | 10 | const ivec2[] vert = ivec2[]( 11 | ivec2(0,0), ivec2(1,0), ivec2(0,1), 12 | ivec2(1,0), ivec2(1,1), ivec2(0,1) 13 | ); 14 | 15 | float height_at(ivec2 icoords) { 16 | vec2 fcoords = vec2(icoords/size); 17 | return texture(height_tex, fcoords).r; 18 | } 19 | 20 | void main() { 21 | int size_int = int(size); 22 | int quad_id = gl_VertexIndex/6; 23 | int vert_id = gl_VertexIndex%6; 24 | 25 | ivec2 icoords = ivec2(quad_id%size_int, quad_id/size_int)+vert[vert_id]; 26 | 27 | ivec2 offsetx = ivec2(1,0); 28 | ivec2 offsety = ivec2(0,1); 29 | float height = height_at(icoords); 30 | float heightx = height_at(icoords+offsetx); 31 | float heighty = height_at(icoords+offsety); 32 | 33 | vec3 p1 = vec3(offsetx, heightx - height); 34 | vec3 p2 = vec3(offsety, heighty - height); 35 | p1.z *= 0.1; 36 | p2.z *= 0.1; 37 | vec3 normal = normalize(cross(p1, p2)); 38 | 39 | vec2 fcoords = vec2(icoords/size); 40 | ftexcoords.xy = fcoords; 41 | ftexcoords.z = height; 42 | fnormal = normalize(mat3(model) * normal); 43 | vec4 position = model * vec4(fcoords*2.f-1.f,height,1.0); 44 | gl_Position = viewProj * position; 45 | } 46 | -------------------------------------------------------------------------------- /smp/shader/texture.frag: -------------------------------------------------------------------------------- 1 | layout(location = 0) in vec2 ftexcoords; 2 | 3 | layout(location = 0) out vec4 color; 4 | 5 | layout(binding = 1) uniform sampler2D tex; 6 | 7 | void main() { 8 | color = texture(tex, ftexcoords); 9 | } 10 | -------------------------------------------------------------------------------- /smp/texture/bush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/texture/bush.png -------------------------------------------------------------------------------- /smp/texture/default_mat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/texture/default_mat.png -------------------------------------------------------------------------------- /smp/texture/jerrican.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/texture/jerrican.png -------------------------------------------------------------------------------- /smp/texture/jerrican_mat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/texture/jerrican_mat.png -------------------------------------------------------------------------------- /smp/texture/logo.ls: -------------------------------------------------------------------------------- 1 | (self.create 64 64) 2 | (local c (color "#ccc")) 3 | (self.rect 0 0 16 64 c) 4 | (self.rect 0 48 64 16 c) 5 | (self.rect 32 0 32 32 c) 6 | -------------------------------------------------------------------------------- /smp/texture/skybox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/texture/skybox.png -------------------------------------------------------------------------------- /smp/texture/smartphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/texture/smartphone.png -------------------------------------------------------------------------------- /smp/texture/smartphone_mat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/smp/texture/smartphone_mat.png -------------------------------------------------------------------------------- /src/L.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lut0pia/L/b4d70e9ee095d9f28b5ee96cbfda5e01adc796cb/src/L.ico -------------------------------------------------------------------------------- /src/audio/Audio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../time/Time.h" 6 | 7 | namespace L { 8 | namespace Audio { 9 | enum SampleFormat : uint8_t { 10 | Mono8, Mono16, 11 | Stereo8, Stereo16, 12 | }; 13 | static constexpr size_t sample_format_size_array[] = {1,2,2,4}; 14 | constexpr size_t sample_format_size(const SampleFormat& sf) { return sample_format_size_array[sf]; } 15 | static constexpr uint32_t sample_format_channels_array[] = {1,1,2,2}; 16 | constexpr uint32_t sample_format_channels(const SampleFormat& sf) { return sample_format_channels_array[sf]; } 17 | 18 | static constexpr uint32_t working_frequency = 44100; 19 | static constexpr SampleFormat working_format = Stereo16; 20 | 21 | void acquire_buffer(void*& buffer, uint32_t& frame_count); 22 | void commit_buffer(); 23 | 24 | void render(void* dst, const void* src, SampleFormat format, uint32_t sample_count, float volume[2]); 25 | bool convert_samples(void* dst, SampleFormat dst_fmt, uint32_t dst_freq, const void* src, SampleFormat src_fmt, uint32_t src_freq, uint32_t sample_count); 26 | uint32_t convert_samples_required_count(uint32_t dst_freq, uint32_t src_freq, uint32_t src_sample_count); 27 | uint32_t convert_samples_reverse_required_count(uint32_t dst_freq, uint32_t src_freq, uint32_t dst_sample_count); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/audio/AudioDecoder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AudioStream.h" 4 | #include "../container/Ref.h" 5 | #include "../engine/Resource.h" 6 | 7 | namespace L { 8 | class AudioDecoder { 9 | protected: 10 | Resource _stream; 11 | uint32_t _current_frame = 0; 12 | 13 | public: 14 | inline AudioDecoder(const Resource& stream) : _stream(stream) {} 15 | virtual ~AudioDecoder() {} 16 | 17 | virtual void render(void* buffer, uint32_t frame_count, float volume[2]) = 0; 18 | 19 | virtual bool playing() const; 20 | 21 | inline const Resource stream() const { return _stream; } 22 | 23 | typedef Ref(*Factory)(const Resource&); 24 | static void register_factory(const Symbol& format, Factory); 25 | static Ref make(const Resource&); 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/audio/AudioEngine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../component/Entity.h" 4 | 5 | namespace L { 6 | class AudioEngine { 7 | private: 8 | static AudioEngine* _instance; 9 | public: 10 | AudioEngine(); 11 | virtual ~AudioEngine() {} 12 | 13 | virtual void init() = 0; 14 | 15 | virtual void set_listener(Handle entity) = 0; 16 | virtual void post_event(const Symbol& name, Handle entity = nullptr) = 0; 17 | virtual void set_parameter(const Symbol& name, float value, Handle entity = nullptr) = 0; 18 | 19 | inline static AudioEngine* get() { return _instance; } 20 | static void init_instance(); 21 | static void script_registration(); 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/audio/AudioOutput.cpp: -------------------------------------------------------------------------------- 1 | #include "AudioOutput.h" 2 | 3 | using namespace L; 4 | 5 | static AudioOutput* ao_instance(nullptr); 6 | 7 | AudioOutput::AudioOutput() { 8 | ao_instance = this; 9 | } 10 | 11 | AudioOutput* AudioOutput::instance() { 12 | return ao_instance; 13 | } -------------------------------------------------------------------------------- /src/audio/AudioOutput.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace L { 6 | class AudioOutput { 7 | public: 8 | AudioOutput(); 9 | virtual uint32_t frame_count_ahead() = 0; 10 | virtual uint32_t frequency() = 0; 11 | virtual void write(void* buffer, uint32_t frame_count) = 0; 12 | 13 | static AudioOutput* instance(); 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/audio/AudioStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Audio.h" 4 | #include "../container/Buffer.h" 5 | #include "../text/Symbol.h" 6 | 7 | namespace L { 8 | struct AudioStream { 9 | typedef AudioStream Intermediate; 10 | 11 | Symbol format; 12 | Buffer samples; 13 | uint32_t sample_count; 14 | Audio::SampleFormat sample_format; 15 | 16 | friend inline void resource_write(Stream& s, const Intermediate& v) { s <= v.format <= v.samples <= v.sample_count <= v.sample_format; } 17 | friend inline void resource_read(Stream& s, Intermediate& v) { s >= v.format >= v.samples >= v.sample_count >= v.sample_format; } 18 | friend inline size_t resource_cpu_size(Intermediate& v) { return v.samples.size(); } 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/audio/Midi.cpp: -------------------------------------------------------------------------------- 1 | #include "Midi.h" 2 | 3 | using namespace L; 4 | 5 | static Midi* instance(nullptr); 6 | 7 | Midi::Midi() { 8 | instance = this; 9 | } 10 | void Midi::send(const MidiEvent& e) { 11 | if(instance) { 12 | instance->send_internal(e); 13 | } 14 | } 15 | void Midi::set_instrument(uint8_t channel, uint8_t instrument) { 16 | MidiEvent e; 17 | e.msg.type = MidiEvent::ProgramChange; 18 | e.msg.channel = channel; 19 | e.msg.instrument = instrument; 20 | send(e); 21 | } 22 | void Midi::play_note(uint8_t channel, uint8_t note, uint8_t velocity) { 23 | MidiEvent e; 24 | e.msg.type = MidiEvent::NoteOn; 25 | e.msg.channel = channel; 26 | e.msg.note = note; 27 | e.msg.velocity = velocity; 28 | send(e); 29 | } 30 | void Midi::stop_note(uint8_t channel, uint8_t note) { 31 | MidiEvent e; 32 | e.msg.type = MidiEvent::NoteOff; 33 | e.msg.channel = channel; 34 | e.msg.note = note; 35 | send(e); 36 | } 37 | void Midi::stop_all(uint8_t channel) { 38 | for(uint8_t t(0); t<128; t++) 39 | stop_note(channel, t); 40 | } 41 | void Midi::stop_all() { 42 | for(uint8_t c(0); c<16; c++) 43 | stop_all(c); 44 | } 45 | -------------------------------------------------------------------------------- /src/audio/Midi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace L { 6 | union MidiEvent { 7 | enum : uint8_t { 8 | NoteOff = 0x8, 9 | NoteOn = 0x9, 10 | ControllerChange = 0xb, 11 | ProgramChange = 0xc, 12 | }; 13 | uint32_t msg32; 14 | uint8_t array[4]; 15 | struct { 16 | uint8_t channel : 4; 17 | uint8_t type : 4; 18 | union { 19 | uint8_t note; 20 | uint8_t instrument; 21 | }; 22 | union { 23 | uint8_t velocity; 24 | uint8_t value; 25 | }; 26 | } msg; 27 | }; 28 | class Midi { 29 | protected: 30 | Midi(); 31 | virtual void send_internal(const MidiEvent&) = 0; 32 | public: 33 | static void send(const MidiEvent&); 34 | static void set_instrument(uint8_t channel, uint8_t instrument); 35 | static void play_note(uint8_t channel, uint8_t note, uint8_t velocity = 127); 36 | static void stop_note(uint8_t channel, uint8_t note); 37 | static void stop_all(uint8_t channel); 38 | static void stop_all(); 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /src/audio/MidiSequence.cpp: -------------------------------------------------------------------------------- 1 | #include "MidiSequence.h" 2 | 3 | using namespace L; 4 | 5 | void MidiSequence::play(uintptr_t& index, Time& time) const { 6 | while(index=delta_time) { 10 | Midi::send(e.midi_event); 11 | time -= delta_time; 12 | index++; 13 | } else break; 14 | } 15 | } -------------------------------------------------------------------------------- /src/audio/MidiSequence.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../container/Array.h" 4 | #include "Midi.h" 5 | #include "../stream/serial_bin.h" 6 | #include "../time/Time.h" 7 | 8 | namespace L { 9 | struct MidiSequence { 10 | typedef MidiSequence Intermediate; 11 | struct Event { 12 | uint32_t delta_us; 13 | MidiEvent midi_event; 14 | }; 15 | Array events; 16 | 17 | void play(uintptr_t& index, Time& time) const; // Play from index for time 18 | 19 | friend inline void resource_write(Stream& s, const Intermediate& v) { s <= v.events; } 20 | friend inline void resource_read(Stream& s, Intermediate& v) { s >= v.events; } 21 | friend inline size_t resource_cpu_size(Intermediate& v) { return get_cpu_size(v.events); } 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/component/AudioListenerComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "AudioListenerComponent.h" 2 | 3 | #include "../engine/Engine.h" 4 | 5 | using namespace L; 6 | 7 | Vector3f AudioListenerComponent::_position, AudioListenerComponent::_right, 8 | AudioListenerComponent::_forward, AudioListenerComponent::_up, 9 | AudioListenerComponent::_velocity, AudioListenerComponent::_last_position; 10 | 11 | void AudioListenerComponent::update() { 12 | _position = _transform->position(); 13 | _right = _transform->right(); 14 | _forward = _transform->forward(); 15 | _up = _transform->up(); 16 | _velocity = (_position-_last_position)*Engine::delta_seconds(); 17 | _last_position = _position; 18 | } 19 | void AudioListenerComponent::update_components() { 20 | _transform = entity()->require_component(); 21 | _last_position = _transform->position(); 22 | } 23 | void AudioListenerComponent::script_registration() { 24 | L_COMPONENT_BIND(AudioListenerComponent, "audio_listener"); 25 | } 26 | -------------------------------------------------------------------------------- /src/component/AudioListenerComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../audio/Audio.h" 4 | #include "Component.h" 5 | #include "Transform.h" 6 | 7 | namespace L { 8 | class AudioListenerComponent : public TComponent < AudioListenerComponent, ComponentFlag::Update> { 9 | protected: 10 | static Vector3f _position, _right, _forward, _up, _velocity, _last_position; 11 | Transform* _transform; 12 | public: 13 | void update(); 14 | void update_components(); 15 | static void script_registration(); 16 | 17 | inline static const Vector3f position() { return _position; } 18 | inline static const Vector3f right() { return _right; } 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/component/AudioSourceComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../audio/AudioDecoder.h" 4 | #include "../audio/AudioStream.h" 5 | #include "Component.h" 6 | #include "../engine/Resource.h" 7 | 8 | namespace L { 9 | class AudioSourceComponent : public TComponent { 11 | protected: 12 | class Transform* _transform; 13 | class ScriptComponent* _script; 14 | Resource _stream; 15 | Ref _decoder; 16 | float _volume = 1.f; 17 | bool _playing = false, _looping = false; 18 | 19 | public: 20 | void audio_render(void* frames, uint32_t frame_count); 21 | 22 | void update_components() override; 23 | static void script_registration(); 24 | 25 | inline void stream(const char* filepath) { _stream = filepath; } 26 | inline void looping(bool should_loop) { _looping = should_loop; } 27 | inline void volume(float v) { _volume = v; } 28 | inline void play() { _decoder = nullptr; _playing = true; } 29 | inline void stop() { _playing = false; } 30 | inline bool playing() const { return _playing; } 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/component/Collider.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Component.h" 4 | #include "../container/IntervalTree.h" 5 | 6 | namespace L { 7 | class Collider : public TComponent { 8 | public: 9 | static Interval3fTree tree; 10 | Interval3fTree::Node* _node; 11 | class Transform* _transform; 12 | class RigidBody* _rigidbody; 13 | class ScriptComponent* _script; 14 | Vector3f _center, _radius; 15 | Interval3f _bounding_box; 16 | enum { 17 | Box, Sphere 18 | } _type; 19 | struct Collision { 20 | bool colliding; 21 | Vector3f point, normal; 22 | float overlap; 23 | }; 24 | public: 25 | Collider(); 26 | ~Collider(); 27 | 28 | virtual void update_components() override; 29 | static void script_registration(); 30 | 31 | static void custom_sub_update_all(); 32 | void center(const Vector3f& center); 33 | void box(const Vector3f& radius); 34 | void sphere(float radius); 35 | void update_bounding_box(); 36 | bool raycast_single(const Vector3f& origin, const Vector3f& direction, float& t) const; 37 | Matrix33f inertia_tensor() const; 38 | void render(const Camera& camera); 39 | static bool check_collision(const Collider& a, const Collider& b, Collision&); 40 | static Collider* raycast(const Vector3f& origin, Vector3f direction, float& t); 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /src/component/GUIComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Component.h" 4 | #include "../rendering/Material.h" 5 | #include "../engine/Resource.h" 6 | 7 | namespace L { 8 | class GUIComponent : public TComponent { 10 | protected: 11 | Camera* _camera; 12 | Material _material; 13 | Vector2i _offset = 0; 14 | Vector2f _viewport_anchor = 0.f; 15 | Vector2f _anchor = 0.f; 16 | Vector2f _scale = 1.f; 17 | public: 18 | virtual void update_components() override; 19 | static void script_registration(); 20 | 21 | void gui(const Camera&); 22 | 23 | inline Material& material() { return _material; } 24 | inline void offset(const Vector2i& offset) { _offset = offset; } 25 | inline void viewport_anchor(const Vector2f& viewport_anchor) { _viewport_anchor = viewport_anchor; } 26 | inline void anchor(const Vector2f& anchor) { _anchor = anchor; } 27 | inline void scale(const Vector2f& scale) { _scale = scale; } 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /src/component/GroupComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Component.h" 4 | #include "../engine/Resource.h" 5 | 6 | namespace L { 7 | class GroupComponent : public TComponent { 9 | protected: 10 | Array> _entities; 11 | Resource _level_script; 12 | void* _level_script_value = nullptr; 13 | 14 | public: 15 | ~GroupComponent(); 16 | void update(); 17 | static void script_registration(); 18 | 19 | void link(Handle); 20 | void unlink(Handle); 21 | void unlink_all(); 22 | 23 | inline const Array>& entities() const { return _entities; } 24 | inline void level_script(const char* filepath) { _level_script = filepath; } 25 | void reload_level_script(); 26 | 27 | static void notify_entity_created(Handle entity); 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /src/component/HierarchyComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "HierarchyComponent.h" 2 | 3 | using namespace L; 4 | 5 | void HierarchyComponent::late_update() { 6 | if(_parent) { 7 | _transform->position(_parent->position() + _parent->rotation().rotate(_translation)); 8 | _transform->rotation(_parent->rotation() * _rotation); 9 | } 10 | } 11 | void HierarchyComponent::update_components() { 12 | _transform = entity()->require_component(); 13 | } 14 | void HierarchyComponent::script_registration() { 15 | L_COMPONENT_BIND(HierarchyComponent, "hierarchy"); 16 | L_SCRIPT_METHOD(HierarchyComponent, "parent", 1, parent(c.param(0).get>())); 17 | L_SCRIPT_METHOD(HierarchyComponent, "translation", 1, translation(c.param(0).get())); 18 | L_SCRIPT_METHOD(HierarchyComponent, "translate", 1, translate(c.param(0).get())); 19 | L_SCRIPT_METHOD(HierarchyComponent, "rotation", 2, rotation(c.param(0).get())); 20 | L_SCRIPT_METHOD(HierarchyComponent, "rotate", 1, rotate(c.param(0).get())); 21 | L_SCRIPT_METHOD(HierarchyComponent, "rotate_absolute", 1, rotate_absolute(c.param(0).get())); 22 | } 23 | -------------------------------------------------------------------------------- /src/component/HierarchyComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Transform.h" 4 | 5 | namespace L { 6 | class HierarchyComponent : public TComponent { 8 | protected: 9 | Transform *_parent, *_transform; 10 | Vector3f _translation; 11 | Quatf _rotation; 12 | public: 13 | inline HierarchyComponent() : _parent(nullptr), _translation(0.f) {} 14 | 15 | void late_update(); 16 | void update_components(); 17 | static void script_registration(); 18 | 19 | inline void parent(Transform* t) { _parent = t; } 20 | 21 | inline void translation(const Vector3f& t) { _translation = t; } 22 | inline void translate(const Vector3f& t) { _translation += t; } 23 | 24 | inline void rotation(const Quatf& r) { _rotation = r; } 25 | inline void rotate(const Quatf& q) { _rotation = _rotation * q; } 26 | inline void rotate_absolute(const Quatf& q) { _rotation = q * _rotation; } 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /src/component/InputComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "InputComponent.h" 2 | 3 | using namespace L; 4 | 5 | void InputComponent::script_registration() { 6 | InputContext::script_registration(); 7 | 8 | L_COMPONENT_BIND(InputComponent, "input"); 9 | L_SCRIPT_RETURN_METHOD(InputComponent, "context", 0, _context.handle()); 10 | } 11 | -------------------------------------------------------------------------------- /src/component/InputComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Component.h" 4 | #include "../input/InputContext.h" 5 | 6 | namespace L { 7 | class InputComponent : public TComponent { 8 | protected: 9 | InputContext _context; 10 | public: 11 | static void script_registration(); 12 | inline Handle context() const { return _context.handle(); } 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/component/MidiSourceComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "MidiSourceComponent.h" 2 | 3 | #include "../engine/Engine.h" 4 | #include "../engine/Resource.inl" 5 | 6 | using namespace L; 7 | 8 | void MidiSourceComponent::script_registration() { 9 | L_COMPONENT_BIND(MidiSourceComponent, "midi_source"); 10 | L_SCRIPT_METHOD(MidiSourceComponent, "sequence", 1, sequence(c.param(0).get())); 11 | L_SCRIPT_METHOD(MidiSourceComponent, "looping", 1, looping(c.param(0).get())); 12 | L_SCRIPT_METHOD(MidiSourceComponent, "play", 0, play()); 13 | L_SCRIPT_METHOD(MidiSourceComponent, "stop", 0, stop()); 14 | L_SCRIPT_RETURN_METHOD(MidiSourceComponent, "is_playing", 0, playing()); 15 | } 16 | 17 | void MidiSourceComponent::update() { 18 | if(_playing) { 19 | const MidiSequence* sequence = _sequence.try_load(); 20 | if(sequence == nullptr) { 21 | return; 22 | } 23 | 24 | _play_time += Engine::delta_time(); 25 | sequence->play(_play_index, _play_time); 26 | if(_loop && _play_index >= sequence->events.size()) { 27 | _play_index = 0; 28 | } 29 | } 30 | } 31 | void MidiSourceComponent::play() { 32 | _play_index = 0; 33 | _play_time = 0; 34 | _playing = true; 35 | } 36 | void MidiSourceComponent::stop() { 37 | _playing = false; 38 | Midi::stop_all(); 39 | } 40 | -------------------------------------------------------------------------------- /src/component/MidiSourceComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../audio/MidiSequence.h" 4 | #include "../engine/Resource.h" 5 | #include "Component.h" 6 | 7 | namespace L { 8 | class MidiSourceComponent : public TComponent { 10 | protected: 11 | Resource _sequence; 12 | uintptr_t _play_index; 13 | Time _play_time; 14 | bool _loop, _playing; 15 | public: 16 | static void script_registration(); 17 | 18 | void update(); 19 | void play(); 20 | void stop(); 21 | 22 | inline void sequence(const char* filepath) { _sequence = filepath; } 23 | inline void looping(bool loop) { _loop = loop; } 24 | inline bool playing() const { return _playing; } 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /src/component/NameComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "NameComponent.h" 2 | 3 | using namespace L; 4 | 5 | Table NameComponent::_components; 6 | 7 | void NameComponent::script_registration() { 8 | L_COMPONENT_BIND(NameComponent, "name"); 9 | L_SCRIPT_METHOD(NameComponent, "set", 1, set_name(c.param(0).get())); 10 | L_SCRIPT_METHOD(NameComponent, "get", 0, get_name()); 11 | } 12 | 13 | NameComponent* NameComponent::find(const Symbol& name) { 14 | if(NameComponent** name_component = _components.find(name)) 15 | return *name_component; 16 | else 17 | return nullptr; 18 | } 19 | -------------------------------------------------------------------------------- /src/component/NameComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Component.h" 4 | #include "../math/Rand.h" 5 | #include "../text/Symbol.h" 6 | 7 | namespace L { 8 | class NameComponent : public TComponent { 9 | protected: 10 | static Table _components; 11 | Symbol _name; 12 | public: 13 | inline NameComponent() { set_name(ntos<16>(Rand::next(), sizeof(uint64_t)*2)); } 14 | inline ~NameComponent() { _components.remove(_name); } 15 | 16 | static void script_registration(); 17 | 18 | inline void set_name(const Symbol& name) { 19 | _components.remove(_name); 20 | if(_components.find(name)) { 21 | error("Name already in use"); 22 | } else { 23 | _name = name; 24 | _components[_name] = this; 25 | } 26 | } 27 | inline const Symbol& get_name() const { return _name; } 28 | 29 | static NameComponent* find(const Symbol&); 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/component/PostProcessComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "PostProcessComponent.h" 2 | 3 | #include "../engine/Resource.inl" 4 | 5 | using namespace L; 6 | 7 | void PostProcessComponent::script_registration() { 8 | L_COMPONENT_BIND(PostProcessComponent, "post_process"); 9 | L_SCRIPT_RETURN_METHOD(PostProcessComponent, "material", 0, material().handle()); 10 | } 11 | 12 | void PostProcessComponent::render(const Camera& camera, const RenderPassImpl* render_pass) { 13 | _material.update(); 14 | if(_material.valid_for_render_pass(render_pass)) { 15 | _material.draw(camera, render_pass); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/component/PostProcessComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Component.h" 4 | #include "../rendering/Material.h" 5 | #include "../engine/Resource.h" 6 | 7 | namespace L { 8 | class PostProcessComponent : public TComponent { 9 | protected: 10 | Material _material; 11 | public: 12 | static void script_registration(); 13 | 14 | void render(const Camera& camera, const RenderPassImpl* render_pass); 15 | 16 | inline Material& material() { return _material; } 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/component/Primitive.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Transform.h" 4 | #include "../engine/CullVolume.h" 5 | #include "../rendering/Material.h" 6 | #include "../engine/Resource.h" 7 | 8 | namespace L { 9 | class Primitive : public TComponent { 11 | protected: 12 | Transform* _transform; 13 | CullVolume _cull_volume; 14 | Interval3f _bounds; 15 | Material _material; 16 | Vector3f _scale = 1.f; 17 | public: 18 | virtual void update_components() override; 19 | static void script_registration(); 20 | 21 | void render(const Camera& camera, const RenderPassImpl* render_pass); 22 | 23 | inline void material(const char* filename) { _material.parent(filename); } 24 | inline Material& material() { return _material; } 25 | inline void scale(const Vector3f& s) { _scale = s; } 26 | 27 | static void custom_late_update_all(); 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /src/component/ScriptComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Component.h" 4 | #include "../input/Device.h" 5 | #include "../script/ScriptContext.h" 6 | #include "../engine/Resource.h" 7 | 8 | namespace L { 9 | class ScriptComponent : public TComponent { 11 | protected: 12 | ScriptContext _context; 13 | Resource _script; 14 | bool _started : 1; 15 | public: 16 | ScriptComponent() : _started(false) {} 17 | virtual void update_components() override; 18 | static void script_registration(); 19 | 20 | void load(const char* filename); 21 | void start(); 22 | void update(); 23 | void late_update(); 24 | void event(const Ref>&); 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /src/component/SkeletalAnimatorComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Primitive.h" 4 | #include "../rendering/Animation.h" 5 | 6 | namespace L { 7 | class SkeletalAnimatorComponent : public TComponent { 9 | protected: 10 | Transform* _transform = nullptr; 11 | Primitive* _primitive = nullptr; 12 | Resource _skeleton; 13 | Resource _animation; 14 | Array _local_pose; 15 | Array _global_pose; 16 | Array _skin; 17 | float _time = 0.f; 18 | 19 | public: 20 | void late_update(); 21 | void update_components(); 22 | static void script_registration(); 23 | 24 | inline void skeleton(const char* filename) { _skeleton = filename; } 25 | inline void animation(const char* filename) { _animation = filename; } 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/component/Transform.cpp: -------------------------------------------------------------------------------- 1 | #include "Transform.h" 2 | 3 | using namespace L; 4 | 5 | void Transform::script_registration() { 6 | L_COMPONENT_BIND(Transform, "transform"); 7 | L_SCRIPT_RETURN_METHOD(Transform, "get_position", 0, position()); 8 | L_SCRIPT_RETURN_METHOD(Transform, "right", 0, right()); 9 | L_SCRIPT_RETURN_METHOD(Transform, "forward", 0, forward()); 10 | L_SCRIPT_RETURN_METHOD(Transform, "up", 0, up()); 11 | L_SCRIPT_RETURN_METHOD(Transform, "to_absolute", 1, to_absolute(c.param(0))); 12 | L_SCRIPT_METHOD(Transform, "set_position", 1, position(c.param(0).get())); 13 | L_SCRIPT_METHOD(Transform, "set_rotation", 1, rotation(c.param(0).get())); 14 | L_SCRIPT_METHOD(Transform, "move", 1, move(c.param(0).get())); 15 | L_SCRIPT_METHOD(Transform, "move_absolute", 1, move_absolute(c.param(0).get())); 16 | L_SCRIPT_METHOD(Transform, "rotate", 1, rotate(c.param(0).get())); 17 | L_SCRIPT_METHOD(Transform, "rotate_absolute", 1, rotate_absolute(c.param(0).get())); 18 | } 19 | -------------------------------------------------------------------------------- /src/component/Transform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Component.h" 4 | #include "../math/geometry.h" 5 | #include "../math/Matrix.h" 6 | #include "../math/Quaternion.h" 7 | #include "../math/Vector.h" 8 | 9 | namespace L { 10 | class Transform : public TComponent { 11 | private: 12 | Vector3f _position; 13 | Quatf _rotation; 14 | public: 15 | inline Transform() : _position(0.f, 0.f, 0.f) {} 16 | 17 | static void script_registration(); 18 | 19 | inline Vector3f to_absolute(const Vector3f& v) const { return position()+_rotation.rotate(v); } 20 | inline Vector3f from_absolute(const Vector3f& v) const { return _rotation.inverse().rotate(v-position()); } 21 | inline void rotate(const Quatf& q) { _rotation = _rotation * q; } 22 | inline void rotate_absolute(const Quatf& q) { _rotation = q * _rotation; } 23 | inline void move(const Vector3f& d) { _position += _rotation.rotate(d); } 24 | inline void move_absolute(const Vector3f& v) { _position += v; } 25 | 26 | inline void position(const Vector3f& p) { _position = p; } 27 | inline const Vector3f& position() const { return _position; } 28 | inline void rotation(const Quatf& r) { _rotation = r; } 29 | inline const Quatf& rotation() const { return _rotation; } 30 | inline Vector3f right() const { return rotation().rotate(Vector3f(1.f, 0.f, 0.f)); } 31 | inline Vector3f forward() const { return rotation().rotate(Vector3f(0.f, 1.f, 0.f)); } 32 | inline Vector3f up() const { return rotation().rotate(Vector3f(0.f, 0.f, 1.f)); } 33 | inline Matrix44f matrix() const { return sqt_to_mat(rotation(), position()); } 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /src/container/Archive.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../parallelism/Lock.h" 4 | #include "../text/String.h" 5 | #include "../hash.h" 6 | 7 | namespace L { 8 | class Archive { 9 | public: 10 | struct Entry { 11 | uint32_t hash; 12 | uint32_t position; 13 | uint32_t size; 14 | inline operator bool() const { return size > 0; } 15 | }; 16 | static const size_t table_size_bytes = 1 << 16; // 64KB 17 | static const size_t table_entry_count = table_size_bytes / sizeof(Entry); 18 | protected: 19 | String _path; 20 | Entry* _entries; 21 | Lock _lock; 22 | 23 | public: 24 | Archive(const char* path); 25 | ~Archive(); 26 | inline Entry& find(const char* key) { return find(hash(key)); } 27 | Entry& find(uint32_t key_hash); 28 | void store(const char* key, const void* data, size_t size); 29 | void load(Entry, void*); 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/container/Bitfield.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace L { 4 | template 5 | class Bitfield { 6 | protected: 7 | static constexpr size_t N = S / 32 + 1; 8 | uint32_t _data[N]; 9 | 10 | public: 11 | constexpr Bitfield() = default; 12 | constexpr Bitfield(uint32_t d) : _data {d} {} 13 | 14 | inline Bitfield& operator&=(const Bitfield& o) { for(uintptr_t i = 0; i < N; i++) { _data[i] &= o._data[i]; } return *this; } 15 | inline Bitfield& operator|=(const Bitfield& o) { for(uintptr_t i = 0; i < N; i++) { _data[i] |= o._data[i]; } return *this; } 16 | inline Bitfield& operator^=(const Bitfield& o) { for(uintptr_t i = 0; i < N; i++) { _data[i] ^= o._data[i]; } return *this; } 17 | 18 | inline bool operator[](uintptr_t i) const { return (_data[i / 32] & (1 << (i % 32))) != 0; } 19 | 20 | inline void set(uintptr_t i) { _data[i / 32] |= (1 << (i % 32)); } 21 | inline void unset(uintptr_t i) { _data[i / 32] &= ~(1 << (i % 32)); } 22 | inline void clear(uint8_t v = 0) { memset(_data, v, sizeof(_data)); } 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /src/container/IterablePool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Array.h" 4 | #include "Pool.h" 5 | 6 | namespace L { 7 | template 8 | class IterablePool { 9 | protected: 10 | Array _objects; 11 | Pool _pool; 12 | 13 | public: 14 | T* allocate() { 15 | T* object(_pool.allocate()); 16 | _objects.push(object); 17 | return object; 18 | } 19 | void deallocate(T* p) { 20 | _pool.deallocate(p); 21 | if(const T* const * o = _objects.find(p)) { 22 | _objects.erase_fast(o - (const T* const *)_objects.begin()); 23 | } 24 | } 25 | const Array& objects() const { return _objects; } 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/container/KeyValue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../stream/Stream.h" 4 | #include "../hash.h" 5 | 6 | namespace L { 7 | template 8 | class KeyValue { 9 | private: 10 | K _key; 11 | V _value; 12 | public: 13 | KeyValue(const K& key = K(), const V& value = V()) : _key(key), _value(value) {} 14 | inline bool operator<(const KeyValue& other) const { return key()(const KeyValue& other) const { return other.key()() const { return &_value; } 21 | inline V* operator->() { return &_value; } 22 | inline const V* operator*() const { return &_value; } 23 | inline V* operator*() { return &_value; } 24 | 25 | friend inline Stream& operator<<(Stream& s, const KeyValue& v) { return s << v._key << ':' << v._value; } 26 | friend inline Stream& operator<(Stream& s, const KeyValue& v) { return s < v._key < v._value; } 27 | friend inline Stream& operator>(Stream& s, KeyValue& v) { return s > v._key > v._value; } 28 | friend inline Stream& operator<=(Stream& s, const KeyValue& v) { return s <= v._key <= v._value; } 29 | friend inline Stream& operator>=(Stream& s, KeyValue& v) { return s >= v._key >= v._value; } 30 | 31 | friend inline uint32_t hash(const KeyValue& v) { return hash(v.key(), v.value()); } 32 | }; 33 | template 34 | inline KeyValue key_value(const K& k, const V& v) { 35 | return KeyValue(k, v); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/container/Queue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../dev/debug.h" 4 | #include "../math/math.h" 5 | 6 | namespace L { 7 | template 8 | class Queue { 9 | private: 10 | T _array[n] = {}; 11 | intptr_t _w = 0; 12 | intptr_t _r = 0; 13 | 14 | public: 15 | constexpr Queue() {} 16 | inline intptr_t index(intptr_t i) const { return pmod(i, n); } 17 | inline bool full() const {return _w==index(_r-1);} 18 | inline bool empty() const {return _w==_r;} 19 | int size() const {return ((_r<=_w)?(_w-_r):(n-(_r-_w)));} 20 | void push(const T& e) { 21 | if(full()) error("Cannot push because static ring is full."); 22 | _array[_w] = e; 23 | _w = index(_w+1); 24 | } 25 | void pop() { 26 | if(empty()) error("Cannot pop because static ring is empty."); 27 | _r = index(_r+1); 28 | } 29 | const T& top() const { 30 | if(empty()) error("Cannot read because static ring is empty."); 31 | return _array[_r]; 32 | } 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/container/StaticStack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../dev/debug.h" 7 | 8 | namespace L { 9 | template 10 | class StaticStack { 11 | private: 12 | uint8_t _array[n*sizeof(T)]; 13 | uintptr_t _size; 14 | 15 | public: 16 | constexpr StaticStack() : _array(), _size(0) {} 17 | inline ~StaticStack() { while(!empty()) pop(); } 18 | template 19 | inline void push(Args&&... args) { 20 | L_ASSERT(_size0); 26 | top().~T(); 27 | _size--; 28 | } 29 | inline T& top(uintptr_t i = 0) { return *((T*)_array+(_size-i-1)); } 30 | inline const T& top(uintptr_t i = 0) const { return *((T*)_array+(_size-i-1)); } 31 | inline T& bottom(uintptr_t i = 0) { return *((T*)_array+i); } 32 | inline const T& bottom(uintptr_t i = 0) const { return *((T*)_array+i); } 33 | inline T& operator[](uintptr_t i) { return top(i); } 34 | inline size_t size() const { return _size; } 35 | inline void size(size_t s) { 36 | while(ssize()) push(); 38 | } 39 | inline bool empty() const { return size()==0; } 40 | inline void clear() { size(0); } 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /src/dev/debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define L_ASSERT(...) { if(!(__VA_ARGS__)) L::error("Assertion failure: %s",#__VA_ARGS__); } 7 | #define L_ASSERT_MSG(exp, ...) { if(!(exp)) L::error("Assertion failure: " __VA_ARGS__); } 8 | 9 | namespace L { 10 | enum class DataBreakpointType : uint8_t { 11 | ReadOrWritten, 12 | Written, 13 | Executed, 14 | }; 15 | 16 | void init_logging(); 17 | 18 | void error(const char* msg, ...); // Fatal, dumps callstack 19 | void warning(const char* msg, ...); // Non-fatal, no callstack 20 | void log(const char* msg, ...); // Simple log 21 | void verbose(const char* msg, ...); // Silent log unless -v or --verbose 22 | 23 | // va_list versions 24 | void verror(const char* msg, va_list); 25 | void vwarning(const char* msg, va_list); 26 | void vlog(const char* msg, va_list); 27 | void vverbose(const char* msg, va_list); 28 | 29 | // System-dependent 30 | void debugbreak(); 31 | void dump_stack(FILE* stream); 32 | bool set_data_breakpoint(const void* ptr, size_t size, DataBreakpointType type = DataBreakpointType::Written); 33 | bool unset_data_breakpoint(const void* ptr); 34 | } 35 | -------------------------------------------------------------------------------- /src/dev/debug_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "debug.h" 2 | 3 | #include 4 | 5 | using namespace L; 6 | 7 | void L::dump_stack(FILE*) { 8 | 9 | } 10 | 11 | void L::debugbreak() { 12 | raise(SIGTRAP); 13 | } 14 | 15 | bool L::set_data_breakpoint(const void* ptr, size_t size, L::DataBreakpointType type) { 16 | return false; 17 | } 18 | bool L::unset_data_breakpoint(const void* ptr) { 19 | return false; 20 | } 21 | -------------------------------------------------------------------------------- /src/dev/test.cpp: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | #include "../container/Array.h" 4 | #include "../system/Arguments.h" 5 | 6 | using namespace L; 7 | 8 | static Array tests; 9 | 10 | void L::add_test(const Test& test) { 11 | tests.push(test); 12 | } 13 | 14 | int L::run_all_tests() { 15 | uint32_t failures = 0; 16 | for(const Test& test : tests) { 17 | log("Running test '%s'", test.name); 18 | if(!test.func()) { 19 | warning("Test '%s' failed", test.name); 20 | failures += 1; 21 | } 22 | } 23 | 24 | if(failures > 0) { 25 | warning("%d/%d tests failed", failures, tests.size()); 26 | return 1; 27 | } else { 28 | log("All %d tests ran successfully", tests.size()); 29 | return 0; 30 | } 31 | } -------------------------------------------------------------------------------- /src/dev/test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace L { 4 | using TestFunc = bool(); 5 | 6 | struct Test { 7 | const char* name; 8 | TestFunc* func; 9 | }; 10 | 11 | void add_test(const Test& test); 12 | 13 | int run_all_tests(); 14 | } 15 | -------------------------------------------------------------------------------- /src/engine/CullVolume.cpp: -------------------------------------------------------------------------------- 1 | #include "CullVolume.h" 2 | 3 | #include "../component/Camera.h" 4 | #include "../dev/profiling.h" 5 | 6 | using namespace L; 7 | 8 | Interval3fTree CullVolume::_tree; 9 | 10 | void CullVolume::cull(const Camera& camera) { 11 | L_SCOPE_MARKER("Culling"); 12 | Vector4f planes[6]; 13 | camera.frustum_planes(planes); 14 | Array stack, invisible; 15 | if(_tree.root()) 16 | stack.push(_tree.root()); 17 | { 18 | L_SCOPE_MARKER("Mark visible"); 19 | while(!stack.empty()) { 20 | const Node* node(stack.back()); 21 | stack.pop(); 22 | 23 | // Compute visibility 24 | const Interval3f& bounds(node->key()); 25 | bool visible(true); 26 | for(uintptr_t i(0); i<6; i++) { 27 | const Vector4f& plane(planes[i]); 28 | if((max(bounds.min().x()*plane.x(), bounds.max().x()*plane.x()) 29 | +max(bounds.min().y()*plane.y(), bounds.max().y()*plane.y()) 30 | +max(bounds.min().z()*plane.z(), bounds.max().z()*plane.z()))+plane.w() < 0.f) { 31 | visible = false; 32 | break; 33 | } 34 | } 35 | 36 | if(visible) { 37 | if(node->branch()) { 38 | stack.push(node->left()); 39 | stack.push(node->right()); 40 | } else 41 | node->value()->_visible = true; 42 | } else invisible.push(node); 43 | } 44 | } 45 | { 46 | L_SCOPE_MARKER("Mark invisible"); 47 | while(!invisible.empty()) { 48 | const Node* node(invisible.back()); 49 | invisible.pop(); 50 | if(node->branch()) { 51 | invisible.push(node->left()); 52 | invisible.push(node->right()); 53 | } else 54 | node->value()->_visible = false; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/engine/CullVolume.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../container/IntervalTree.h" 4 | 5 | namespace L { 6 | class Camera; 7 | class CullVolume { 8 | protected: 9 | static Interval3fTree _tree; 10 | typedef Interval3fTree::Node Node; 11 | Node* _node; 12 | bool _visible; 13 | public: 14 | constexpr CullVolume() : _node(nullptr), _visible(false) {} 15 | inline ~CullVolume() { if(_node) _tree.remove(_node); } 16 | void update_bounds(const Interval3f& bounds) { 17 | if(!_node) _node = _tree.insert(bounds, this); 18 | else if(!_node->key().contains(bounds)) 19 | _tree.update(_node, bounds.extended(1.f)); 20 | } 21 | inline bool visible() const { return _visible; } 22 | 23 | static void cull(const Camera&); 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/engine/GamePlatform.cpp: -------------------------------------------------------------------------------- 1 | #include "GamePlatform.h" 2 | 3 | using namespace L; 4 | 5 | Array> game_platforms; 6 | 7 | GamePlatform::GamePlatform(const Symbol& name) 8 | : Handled(this), _name(name) { 9 | game_platforms.push(handle()); 10 | } 11 | 12 | const Array>& GamePlatform::get_game_platforms() { 13 | return game_platforms; 14 | } 15 | -------------------------------------------------------------------------------- /src/engine/GamePlatform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../container/Array.h" 4 | #include "../container/Handle.h" 5 | #include "../text/String.h" 6 | #include "../text/Symbol.h" 7 | #include "../time/Date.h" 8 | 9 | namespace L { 10 | struct GameAchievement { 11 | uint32_t index; 12 | String name; 13 | bool is_unlocked; 14 | Date unlock_time; 15 | }; 16 | 17 | class GamePlatform : Handled { 18 | protected: 19 | Symbol _name; 20 | bool _overlay_active = false; 21 | String _player_name; 22 | Array _achievements; 23 | 24 | public: 25 | GamePlatform(const Symbol& name); 26 | 27 | // Achievements 28 | virtual void unlock_achievement(const String& name) = 0; 29 | virtual void clear_achievement(const String& name) = 0; 30 | 31 | const Symbol& get_name() const { return _name; } 32 | const String& get_player_name() const { return _player_name; } 33 | const Array& get_achievements() const { return _achievements; } 34 | 35 | static const Array>& get_game_platforms(); 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /src/engine/Settings.cpp: -------------------------------------------------------------------------------- 1 | #include "Settings.h" 2 | 3 | #include "../container/Table.h" 4 | 5 | using namespace L; 6 | 7 | struct Setting { 8 | int _int; 9 | float _float; 10 | String _string; 11 | }; 12 | 13 | static Table settings; 14 | 15 | static inline bool get_setting(const Symbol& name, Setting*& out_setting) { 16 | Setting*& setting = settings[name]; 17 | out_setting = setting; 18 | if(setting==nullptr) { 19 | setting = Memory::new_type(); 20 | out_setting = setting; 21 | return true; 22 | } 23 | return false; 24 | } 25 | 26 | void Settings::set(const Symbol& name, const Var& value) { 27 | Setting* setting; 28 | get_setting(name, setting); 29 | setting->_int = value.get(); 30 | setting->_float = value.get(); 31 | setting->_string = value.get(); 32 | } 33 | const int& Settings::get_int(const Symbol& name, int default_value) { 34 | Setting* setting; 35 | if(get_setting(name, setting)) 36 | set(name, default_value); 37 | return setting->_int; 38 | } 39 | const float& Settings::get_float(const Symbol& name, float default_value) { 40 | Setting* setting; 41 | if(get_setting(name, setting)) 42 | set(name, default_value); 43 | return setting->_float; 44 | } 45 | const String& Settings::get_string(const Symbol& name, const String& default_value) { 46 | Setting* setting; 47 | if(get_setting(name, setting)) 48 | set(name, default_value); 49 | return setting->_string; 50 | } 51 | -------------------------------------------------------------------------------- /src/engine/Settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../dynamic/Variable.h" 4 | #include "../text/String.h" 5 | 6 | namespace L { 7 | namespace Settings { 8 | void set(const Symbol&, const Var&); 9 | const int& get_int(const Symbol&, int default_value = 0); 10 | const float& get_float(const Symbol&, float default_value = 0.f); 11 | const String& get_string(const Symbol&, const String& default_value = String()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/engine/debug_draw.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../math/Vector.h" 4 | #include "../rendering/Color.h" 5 | #include "../time/Time.h" 6 | 7 | namespace L { 8 | void init_debug_draw(); 9 | void debug_draw_line(const Vector3f& a, const Vector3f& b, const Color& color); 10 | } 11 | -------------------------------------------------------------------------------- /src/hash.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace L { 7 | inline uint32_t fnv1a(const char* str) { 8 | uint32_t wtr(2166136261); 9 | while(*str) { 10 | wtr ^= *str; 11 | wtr *= 16777619; 12 | str++; 13 | } 14 | return wtr; 15 | } 16 | inline uint32_t fnv1a(const char* data, size_t size) { 17 | uint32_t wtr(2166136261); 18 | while(size--) { 19 | wtr ^= *data; 20 | wtr *= 16777619; 21 | data++; 22 | } 23 | return wtr; 24 | } 25 | constexpr uint32_t FNV1A(const char* str, uint32_t r) { return (*str) ? FNV1A(str + 1, (r ^ *str) * 16777619) : r; } 26 | constexpr uint32_t FNV1A(const char* str) { return FNV1A(str, 2166136261); } 27 | 28 | template inline uint32_t hash(const T& v) { return fnv1a((const char*)&v, sizeof(v)); } 29 | inline uint32_t hash(const char* str) { return fnv1a(str); } 30 | inline uint32_t hash(uint32_t v) { return v + 1; } 31 | inline uint32_t hash() { return 2166136261; } 32 | 33 | template inline void hash_combine(uint32_t& h, const T& v) { 34 | h ^= hash(v) + 0x9e3779b9 + (h << 6) + (h >> 2); 35 | } 36 | 37 | template inline uint32_t hash(const T& v, A&&... args) { 38 | uint32_t h = hash(args...); 39 | hash_combine(h, v); 40 | return h; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/input/Device.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../container/Array.h" 4 | #include "../container/Bitfield.h" 5 | #include "../container/Handle.h" 6 | #include "../text/Symbol.h" 7 | 8 | namespace L { 9 | class Device : public Handled { 10 | public: 11 | enum class Button : uint8_t { 12 | #define DB(button) button, 13 | #include "device_buttons.def" 14 | #undef DB 15 | Last, 16 | }; 17 | enum class Axis : uint8_t { 18 | #define DA(axis) axis, 19 | #include "device_axes.def" 20 | #undef DA 21 | Last, 22 | }; 23 | struct Event { 24 | const Device* device; 25 | Button button; 26 | bool pressed; 27 | }; 28 | protected: 29 | Symbol _name; 30 | Bitfield _buttons; 31 | float _axes[size_t(Axis::Last)]; 32 | float _rumble; 33 | bool _active; 34 | 35 | void set_button(Button button, bool value); 36 | 37 | static void add_device(Device*); 38 | static void add_event(Event); 39 | public: 40 | inline Device() : Handled(this), _buttons(0), _axes {}, _rumble(0.f), _active(false) { 41 | add_device(this); 42 | } 43 | inline float axis(Axis axis) const { return _axes[size_t(axis)]; } 44 | inline bool button(Button button) const { return _buttons[uintptr_t(button)]; } 45 | inline bool active() const { return _active; } 46 | 47 | static const Array& devices(); 48 | static bool new_event(Event&); 49 | 50 | static float any_axis(Axis axis); 51 | static bool any_button(Button button); 52 | 53 | static Symbol button_to_symbol(Button); 54 | static Button symbol_to_button(Symbol); 55 | 56 | static Symbol axis_to_symbol(Axis); 57 | static Axis symbol_to_axis(Symbol); 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /src/input/device_axes.def: -------------------------------------------------------------------------------- 1 | // Mouse axes 2 | DA(MouseX) DA(MouseY) 3 | DA(MouseDX) DA(MouseDY) DA(MouseWheel) 4 | 5 | // Gamepad axes 6 | DA(GamepadLeftStickX) DA(GamepadLeftStickY) 7 | DA(GamepadRightStickX) DA(GamepadRightStickY) 8 | DA(GamepadLeftTrigger) DA(GamepadRightTrigger) 9 | -------------------------------------------------------------------------------- /src/input/device_buttons.def: -------------------------------------------------------------------------------- 1 | // Keyboard buttons 2 | DB(A) DB(B) DB(C) DB(D) DB(E) DB(F) DB(G) DB(H) DB(I) DB(J) DB(K) DB(L) DB(M) 3 | DB(N) DB(O) DB(P) DB(Q) DB(R) DB(S) DB(T) DB(U) DB(V) DB(W) DB(X) DB(Y) DB(Z) 4 | DB(Backspace) DB(Tab) DB(Enter) DB(Pause) DB(Caps) DB(Escape) DB(Space) 5 | DB(LeftShift) DB(RightShift) DB(LeftCtrl) DB(RightCtrl) DB(LeftAlt) DB(RightAlt) 6 | DB(Left) DB(Right) DB(Up) DB(Down) 7 | DB(Insert) DB(Delete) DB(Home) DB(End) DB(PageUp) DB(PageDown) 8 | DB(NumLock) DB(Num0) DB(Num1) DB(Num2) DB(Num3) DB(Num4) DB(Num5) DB(Num6) DB(Num7) DB(Num8) DB(Num9) 9 | DB(F1) DB(F2) DB(F3) DB(F4) DB(F5) DB(F6) DB(F7) DB(F8) DB(F9) DB(F10) DB(F11) DB(F12) 10 | 11 | // Mouse buttons 12 | DB(MouseLeft) DB(MouseRight) DB(MouseMiddle) 13 | 14 | // Gamepad buttons 15 | DB(GamepadLeftStick) DB(GamepadRightStick) 16 | DB(GamepadFaceBottom) DB(GamepadFaceRight) DB(GamepadFaceLeft) DB(GamepadFaceTop) 17 | DB(GamepadLeftShoulder) DB(GamepadRightShoulder) 18 | DB(GamepadLeftTrigger) DB(GamepadRightTrigger) 19 | -------------------------------------------------------------------------------- /src/math/Rand.cpp: -------------------------------------------------------------------------------- 1 | #include "Rand.h" 2 | 3 | #include 4 | 5 | using namespace L; 6 | 7 | constexpr uint64_t a = 2862933555777941757LL, b = 3037000493LL; 8 | static uint64_t last = time(nullptr); 9 | 10 | uint64_t Rand::next() { 11 | return last = last*a+b; 12 | } 13 | uint8_t Rand::next_byte() { 14 | return uint8_t(next()>>48); 15 | } 16 | float Rand::next_float() { 17 | return next() / float(UINT64_MAX); 18 | } 19 | 20 | uint64_t Rand::next(uint64_t max) { 21 | return next() % max; 22 | } 23 | uint64_t Rand::next(uint64_t min, uint64_t max) { 24 | return (next(max - min + 1)) + min; 25 | } 26 | int Rand::next(int min, int max) { 27 | return ((next()>>32)%(max-min+1))+min; 28 | } 29 | float Rand::next(float min, float max) { 30 | return (next_float()*(max-min))+min; 31 | } 32 | void Rand::fill(uint8_t* dst, size_t size) { 33 | while(size>0) { 34 | *dst++ = next_byte(); 35 | size--; 36 | } 37 | } 38 | 39 | float Rand::gauss(uint32_t i) { 40 | float wtr(0); 41 | for(uint32_t j(0); j thres) { 50 | wtr++; 51 | } 52 | return wtr; 53 | } else { 54 | return 0; 55 | } 56 | } 57 | 58 | uint64_t Rand::get_state() { 59 | return last; 60 | } 61 | void Rand::set_state(uint64_t s) { 62 | last = s; 63 | } -------------------------------------------------------------------------------- /src/math/Rand.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace L { 7 | class Rand { 8 | public: 9 | static uint64_t next(); 10 | static uint8_t next_byte(); 11 | static float next_float(); 12 | 13 | static uint64_t next(uint64_t max); // Returns a random unsigned integer between 0 and max excluded 14 | static uint64_t next(uint64_t min, uint64_t max); // Returns a random unsigned integer between min and max included 15 | static int next(int min, int max); // Returns a random integer between min and max 16 | static float next(float min, float max); // Returns a random float between min and max 17 | static void fill(uint8_t*,size_t); 18 | template 19 | inline static T next() { 20 | uint8_t wtr[sizeof(T)]; 21 | fill(wtr,sizeof(T)); 22 | return *((T*)&wtr); 23 | } 24 | 25 | static float gauss(uint32_t); 26 | static uint64_t next_exp(uint64_t ave); // Random exp with an average n 27 | 28 | static uint64_t get_state(); 29 | static void set_state(uint64_t s); 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/math/geometry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Interval.h" 4 | #include "Quaternion.h" 5 | #include "Matrix.h" 6 | #include "Vector.h" 7 | 8 | namespace L{ 9 | bool line_line_intersect(const Vector3f& p1,const Vector3f& p2, 10 | const Vector3f& p3,const Vector3f& p4, 11 | Vector3f* a,Vector3f* b); 12 | bool ray_plane_intersect(const Vector3f& center, const Vector3f& normal, const Vector3f& origin, const Vector3f& direction, float& t); 13 | bool ray_sphere_intersect(const Vector3f& center,float radius,const Vector3f& origin,const Vector3f& direction,float& t); 14 | bool ray_box_intersect(const Interval3f& box,const Vector3f& origin,const Vector3f& direction,float& t,const Vector3f& inv_dir); 15 | inline bool ray_box_intersect(const Interval3f& box,const Vector3f& origin,const Vector3f& direction,float& t){ 16 | return ray_box_intersect(box,origin,direction,t,Vector3f(1.f/direction.x(),1.f/direction.y(),1.f/direction.z())); 17 | } 18 | 19 | Matrix44f sqt_to_mat(const Quatf& q, const Vector3f& t = 0.f, float scale = 1.f); 20 | Matrix33f quat_to_mat(const Quatf& q); 21 | Matrix44f rotation_matrix(const Vector3f& axis, float angle); 22 | Matrix44f translation_matrix(const Vector3f& vector); 23 | Matrix44f orientation_matrix(const Vector3f& newx, const Vector3f& newy, const Vector3f& newz); 24 | Matrix44f scale_matrix(const Vector3f& axes); 25 | 26 | Quatf mat_to_quat(const Matrix44f& m); 27 | Quatf euler_radians(float x, float y, float z); 28 | Quatf euler_degrees(float x, float y, float z); 29 | } 30 | -------------------------------------------------------------------------------- /src/network/Network.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* Windows libraries : 4 | ** - ws2_32 5 | */ 6 | 7 | #include "../text/String.h" 8 | 9 | #include "../macros.h" 10 | #if L_WINDOWS 11 | typedef int socklen_t; 12 | #include 13 | #include 14 | #elif L_LINUX 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #define closesocket(sock) close(sock) 22 | typedef int SOCKET; 23 | typedef struct sockaddr_in SOCKADDR_IN; 24 | typedef struct sockaddr SOCKADDR; 25 | #endif 26 | #ifndef INVALID_SOCKET 27 | #define INVALID_SOCKET (-1) 28 | #endif 29 | 30 | namespace L { 31 | namespace Network { 32 | // System-specific 33 | void init(); 34 | int error_code(); 35 | bool would_block(); 36 | void make_non_blocking(SOCKET); 37 | 38 | // Generic 39 | SOCKET connect_to(const char* ip, short port); 40 | SOCKET connect_to(uint32_t addr, short port); 41 | int recv(SOCKET, char* buffer, size_t size); 42 | bool send(SOCKET, const char* buffer, size_t size); 43 | uint32_t dns_lookup(const char* host); 44 | 45 | // HTTP 46 | String http_request(const String& url); 47 | void http_download(const char* url, const char* name); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/network/Network_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "Network.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace L; 7 | 8 | void Network::init() {} 9 | int Network::error_code() { return errno; } 10 | bool Network::would_block() { 11 | int err(error_code()); 12 | return err == EWOULDBLOCK || err == EAGAIN; 13 | } 14 | void Network::make_non_blocking(SOCKET sd) { 15 | fcntl(sd, F_SETFL, O_NONBLOCK); 16 | } 17 | -------------------------------------------------------------------------------- /src/network/Network_win.cpp: -------------------------------------------------------------------------------- 1 | #include "Network.h" 2 | 3 | using namespace L; 4 | 5 | void Network::init() { 6 | static WSADATA WSAData; 7 | WSAStartup(MAKEWORD(2, 0), &WSAData); 8 | } 9 | int Network::error_code() { return WSAGetLastError(); } 10 | bool Network::would_block() { return error_code() == WSAEWOULDBLOCK; } 11 | void Network::make_non_blocking(SOCKET sd) { 12 | static u_long mode(1); 13 | int error_code; 14 | if((error_code = ioctlsocket(sd, FIONBIO, &mode)) != NO_ERROR) 15 | error("ioctlsocket error: %d", error_code); 16 | } 17 | -------------------------------------------------------------------------------- /src/network/Server.cpp: -------------------------------------------------------------------------------- 1 | #include "Server.h" 2 | 3 | using namespace L; 4 | using namespace Network; 5 | 6 | #define far 7 | #define near 8 | 9 | Server::Server(short port) { 10 | if((_sd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) 11 | error("Server socket error %d", error_code()); 12 | 13 | { // Set reuseaddr 14 | char optval = '1'; 15 | setsockopt(_sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); 16 | } 17 | 18 | make_non_blocking(_sd); 19 | 20 | { 21 | SOCKADDR_IN sin; 22 | memset(&sin, 0, sizeof sin); 23 | sin.sin_addr.s_addr = INADDR_ANY; 24 | sin.sin_family = AF_INET; 25 | sin.sin_port = htons(port); 26 | 27 | if(bind(_sd, (SOCKADDR*)&sin, sizeof(sin))) 28 | error("Server bind error %d", error_code()); 29 | } 30 | 31 | if(listen(_sd, 16) == -1) 32 | error("Server listen error %d", error_code()); 33 | 34 | FD_ZERO(&_listen_fds); 35 | FD_SET(_sd, &_listen_fds); 36 | } 37 | Server::~Server() { 38 | closesocket(_sd); 39 | } 40 | bool Server::new_client(SOCKET& sd) { 41 | static timeval tv{}; 42 | fd_set fds(_listen_fds); 43 | 44 | if(select(int(_sd + 1), &fds, nullptr, nullptr, &tv) == -1) 45 | error("Server select error %d", ::error_code()); 46 | 47 | if(FD_ISSET(_sd, &fds)) { 48 | struct sockaddr_storage their_addr; 49 | socklen_t sin_size(sizeof(their_addr)); 50 | 51 | if((sd = accept(_sd, (struct sockaddr *)&their_addr, &sin_size)) == SOCKET(-1)) 52 | error("Server accept error %d", ::error_code()); 53 | 54 | make_non_blocking(sd); 55 | 56 | return true; 57 | } else return false; 58 | } 59 | -------------------------------------------------------------------------------- /src/network/Server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Network.h" 4 | 5 | namespace L { 6 | class Server { 7 | protected: 8 | SOCKET _sd; 9 | fd_set _listen_fds; 10 | public: 11 | Server(short port); 12 | ~Server(); 13 | bool new_client(SOCKET&); 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/objects.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "math/math.h" 6 | 7 | namespace L { 8 | template 9 | inline void copy(T* dst, const T* src, size_t count) { 10 | while(count--) 11 | new(dst++) T(*src++); 12 | } 13 | template 14 | void swap(T& a, T& b) { 15 | char tmp[sizeof(T)]; 16 | memcpy(tmp,&a,sizeof(T)); 17 | memcpy((void*)&a,&b,sizeof(T)); 18 | memcpy((void*)&b,tmp,sizeof(T)); 19 | } 20 | 21 | template 22 | inline void swap(T* a, T* b, size_t count) {swap((char*)a,(char*)b,count*sizeof(T));} 23 | template<> 24 | inline void swap(char* a, char* b, size_t count) { 25 | char buffer[16384]; 26 | if(a==b) return; 27 | while(count>0) { 28 | size_t bufsize(min(min(count,(size_t)abs((intptr_t)a-(intptr_t)b)),(size_t)16384)); 29 | memcpy(buffer,a,bufsize); 30 | memcpy(a,b,bufsize); 31 | memcpy(b,buffer,bufsize); 32 | a = a+bufsize; 33 | b = b+bufsize; 34 | count -= bufsize; 35 | } 36 | } 37 | 38 | template inline size_t get_cpu_size(const T& v) { return sizeof(v); } 39 | } 40 | -------------------------------------------------------------------------------- /src/parallelism/Lock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "TaskSystem.h" 6 | 7 | #define L_SCOPED_LOCK(lock) L::ScopedLock LOCK__##__LINE__(lock); 8 | 9 | namespace L { 10 | class Lock { 11 | protected: 12 | std::atomic _locked; 13 | 14 | public: 15 | constexpr Lock(bool locked = false) 16 | : _locked(locked) {} 17 | inline bool try_lock() { 18 | bool expected = false; 19 | return _locked.compare_exchange_strong(expected, true); 20 | } 21 | inline void lock() { 22 | TaskSystem::yield_until([](void* data) { return ((Lock*)data)->try_lock(); }, this); 23 | } 24 | inline void unlock() { _locked = 0; } 25 | }; 26 | 27 | class ScopedLock { 28 | protected: 29 | Lock& _lock; 30 | 31 | public: 32 | inline ScopedLock(Lock& lock) 33 | : _lock(lock) { _lock.lock(); } 34 | inline ~ScopedLock() { _lock.unlock(); } 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /src/parallelism/Mutex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../macros.h" 4 | 5 | namespace L { 6 | class Mutex { 7 | L_NOCOPY(Mutex) 8 | protected: 9 | void* _data; 10 | public: 11 | Mutex(); 12 | ~Mutex(); 13 | bool try_lock(); 14 | void lock(); 15 | void unlock(); 16 | }; 17 | 18 | class ScopedMutex { 19 | protected: 20 | Mutex& _mutex; 21 | public: 22 | inline ScopedMutex(Mutex& mutex) :_mutex(mutex) { _mutex.lock(); } 23 | inline ~ScopedMutex() { _mutex.unlock(); } 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/parallelism/Mutex_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "Mutex.h" 2 | 3 | #include 4 | #include "../system/Memory.h" 5 | 6 | using namespace L; 7 | 8 | #define _handle ((pthread_mutex_t*)_data) 9 | 10 | Mutex::Mutex() { 11 | _data = Memory::new_type(); 12 | pthread_mutex_init(_handle, nullptr); 13 | } 14 | Mutex::~Mutex() { 15 | pthread_mutex_destroy(_handle); 16 | Memory::delete_type(_handle); 17 | } 18 | bool Mutex::try_lock() { 19 | return !pthread_mutex_trylock(_handle); 20 | } 21 | void Mutex::lock() { 22 | pthread_mutex_lock(_handle); 23 | } 24 | void Mutex::unlock() { 25 | pthread_mutex_unlock(_handle); 26 | } 27 | -------------------------------------------------------------------------------- /src/parallelism/Mutex_win.cpp: -------------------------------------------------------------------------------- 1 | #include "Mutex.h" 2 | 3 | #include 4 | #include "../system/Memory.h" 5 | 6 | using namespace L; 7 | 8 | #define _handle ((CRITICAL_SECTION*)_data) 9 | 10 | Mutex::Mutex() { 11 | _data = Memory::new_type(); 12 | InitializeCriticalSection(_handle); 13 | } 14 | Mutex::~Mutex() { 15 | DeleteCriticalSection(_handle); 16 | Memory::delete_type(_handle); 17 | } 18 | bool Mutex::try_lock() { 19 | return TryEnterCriticalSection(_handle) != FALSE; 20 | } 21 | void Mutex::lock() { 22 | EnterCriticalSection(_handle); 23 | } 24 | void Mutex::unlock() { 25 | LeaveCriticalSection(_handle); 26 | } 27 | -------------------------------------------------------------------------------- /src/parallelism/Semaphore.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../macros.h" 5 | 6 | namespace L { 7 | class Semaphore { 8 | L_NOCOPY(Semaphore) 9 | protected: 10 | void* _data; 11 | public: 12 | Semaphore(uint32_t initial_count = 0); 13 | ~Semaphore(); 14 | bool try_get(); 15 | void get(); 16 | void put(); 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/parallelism/Semaphore_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "Semaphore.h" 2 | 3 | #include 4 | #include "../system/Memory.h" 5 | 6 | using namespace L; 7 | 8 | #define _sem ((sem_t*)_data) 9 | 10 | Semaphore::Semaphore(uint32_t initial_count) { 11 | _data = Memory::new_type(); 12 | sem_init(_sem, 0, initial_count); 13 | } 14 | Semaphore::~Semaphore() { 15 | sem_destroy(_sem); 16 | Memory::delete_type(_sem); 17 | } 18 | bool Semaphore::try_get() { 19 | return sem_trywait(_sem); 20 | } 21 | void Semaphore::get() { 22 | sem_wait(_sem); 23 | } 24 | void Semaphore::put() { 25 | sem_post(_sem); 26 | } -------------------------------------------------------------------------------- /src/parallelism/Semaphore_win.cpp: -------------------------------------------------------------------------------- 1 | #include "Semaphore.h" 2 | 3 | #include 4 | #include "../dev/debug.h" 5 | 6 | using namespace L; 7 | 8 | #define _handle _data 9 | 10 | Semaphore::Semaphore(uint32_t initial_count) { 11 | _handle = CreateSemaphore(NULL, initial_count, 1 << 30, NULL); 12 | L_ASSERT(_handle != NULL); 13 | } 14 | Semaphore::~Semaphore() { 15 | CloseHandle(_handle); 16 | } 17 | bool Semaphore::try_get() { 18 | return !WaitForSingleObject(_handle, 0); 19 | } 20 | void Semaphore::get() { 21 | WaitForSingleObject(_handle, INFINITE); 22 | } 23 | void Semaphore::put() { 24 | ReleaseSemaphore(_handle, 1, NULL); 25 | } 26 | -------------------------------------------------------------------------------- /src/parallelism/TaskSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../macros.h" 5 | 6 | namespace L { 7 | namespace TaskSystem { 8 | enum Flags { 9 | NoParent = 1<<1, 10 | MainTask = 1<<2, 11 | }; 12 | typedef void(*Func)(void*); 13 | typedef bool(*CondFunc)(void*); 14 | 15 | void init(); 16 | uint32_t thread_count(); 17 | uint32_t thread_id(); 18 | uint32_t fiber_count(); 19 | uint32_t fiber_id(); 20 | void push(Func, void* = nullptr, uint32_t thread_mask = -1, uint32_t flags = 0); 21 | void yield(); 22 | void yield_until(CondFunc, void* = nullptr); 23 | void join(); 24 | void join_all(); 25 | 26 | uint32_t thread_mask(); 27 | void thread_mask(uint32_t mask); 28 | } 29 | 30 | #define L_SCOPE_THREAD_MASK(mask) L::ScopeThreadMask L_CONCAT(THREAD_MASK_,__LINE__)(mask) 31 | class ScopeThreadMask { 32 | protected: 33 | const uint32_t _original_mask; 34 | public: 35 | inline ScopeThreadMask(uint32_t mask) : _original_mask(TaskSystem::thread_mask()) { TaskSystem::thread_mask(mask); } 36 | inline ~ScopeThreadMask() { TaskSystem::thread_mask(_original_mask); } 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /src/parallelism/TaskSystem_win.cpp: -------------------------------------------------------------------------------- 1 | #include "TaskSystem.h" 2 | 3 | #include 4 | 5 | using namespace L; 6 | 7 | namespace L { 8 | void* convert_to_fiber() { 9 | return ConvertThreadToFiber(0); 10 | } 11 | void* create_fiber(void(*f)(void*), void* p) { 12 | return CreateFiber(0, f, p); 13 | } 14 | void switch_to_fiber(void* f) { 15 | SwitchToFiber(f); 16 | } 17 | void create_thread(void(*f)(void*), void* p) { 18 | CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, (LPVOID)p, 0, NULL); 19 | } 20 | uint32_t core_count() { 21 | SYSTEM_INFO system_info; 22 | GetSystemInfo(&system_info); 23 | return system_info.dwNumberOfProcessors; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/rendering/Mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../container/Array.h" 4 | #include "../container/Buffer.h" 5 | #include "../macros.h" 6 | #include "../math/Interval.h" 7 | #include "Renderer.h" 8 | 9 | namespace L { 10 | class Mesh { 11 | L_NOCOPY(Mesh) 12 | private: 13 | MeshImpl* _impl; 14 | Array _attributes; 15 | Interval3f _bounds; 16 | uint32_t _count; 17 | 18 | public: 19 | struct Intermediate { 20 | Buffer vertices, indices; 21 | Array attributes; 22 | }; 23 | inline Mesh() : _impl(nullptr) {} 24 | Mesh(const Intermediate& intermediate); 25 | Mesh(size_t count, const void* data, size_t size, const VertexAttribute* attributes, size_t acount, const uint16_t* indices = nullptr, size_t icount = 0); 26 | ~Mesh(); 27 | 28 | void load(size_t count, const void* data, size_t size, const VertexAttribute* attributes, size_t acount, const uint16_t* indices = nullptr, size_t icount = 0); 29 | 30 | inline MeshImpl* get_impl() const { return _impl; } 31 | inline const Array& attributes() const { return _attributes; } 32 | inline const Interval3f& bounds() const { return _bounds; } 33 | inline uint32_t get_count() const { return _count; } 34 | 35 | static const Mesh& quad(); 36 | static const Mesh& wire_cube(); 37 | static const Mesh& wire_sphere(); 38 | 39 | friend inline void resource_write(Stream& s, const Intermediate& v) { s <= v.vertices <= v.indices <= v.attributes; } 40 | friend inline void resource_read(Stream& s, Intermediate& v) { s >= v.vertices >= v.indices >= v.attributes; } 41 | friend inline size_t resource_gpu_size(const Intermediate& v) { return v.vertices.size() + v.indices.size(); } 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /src/rendering/Shader.cpp: -------------------------------------------------------------------------------- 1 | #include "Shader.h" 2 | 3 | using namespace L; 4 | 5 | Shader::Shader(const Intermediate& intermediate) : _stage(intermediate.stage), _bindings(intermediate.bindings) { 6 | _impl = Renderer::get()->create_shader(intermediate.stage, intermediate.binary.data(), intermediate.binary.size()); 7 | } 8 | Shader::~Shader() { 9 | Renderer::get()->destroy_shader(_impl); 10 | } 11 | -------------------------------------------------------------------------------- /src/rendering/Shader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../container/Array.h" 4 | #include "../container/Buffer.h" 5 | #include "../macros.h" 6 | #include "../text/Symbol.h" 7 | #include "Renderer.h" 8 | 9 | namespace L { 10 | class Shader { 11 | L_NOCOPY(Shader) 12 | public: 13 | struct Intermediate { 14 | Buffer binary; 15 | ShaderStage stage; 16 | Array bindings; 17 | }; 18 | protected: 19 | ShaderImpl* _impl; 20 | ShaderStage _stage; 21 | Array _bindings; 22 | public: 23 | Shader(const Intermediate& intermediate); 24 | ~Shader(); 25 | 26 | inline ShaderImpl* get_impl() const { return _impl; } 27 | inline ShaderStage stage() const { return _stage; } 28 | inline const Array& bindings() const { return _bindings; } 29 | 30 | friend inline void resource_write(Stream& s, const Intermediate& v) { s <= v.binary <= v.stage <= v.bindings; } 31 | friend inline void resource_read(Stream& s, Intermediate& v) { s >= v.binary >= v.stage >= v.bindings; } 32 | friend inline size_t resource_gpu_size(Intermediate& v) { return v.binary.size(); } 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/rendering/Texture.cpp: -------------------------------------------------------------------------------- 1 | #include "Texture.h" 2 | 3 | using namespace L; 4 | 5 | Texture::Texture(const Intermediate& intermediate) 6 | : _width(intermediate.width), _height(intermediate.height), _format(intermediate.format) { 7 | Array mips; 8 | Array sizes; 9 | for(const Buffer& mip : intermediate.mips) { 10 | mips.push(mip); 11 | sizes.push(mip.size()); 12 | } 13 | _impl = Renderer::get()->create_texture(_width, _height, _format, mips.begin(), sizes.begin(), intermediate.mips.size()); 14 | } 15 | Texture::Texture(uint32_t width, uint32_t height, RenderFormat format, const void* data, size_t size) 16 | : Texture(width, height, format, &data, &size, 1) {} 17 | Texture::Texture(uint32_t width, uint32_t height, RenderFormat format, const void** data, size_t* size, uint32_t mips) 18 | : _width(width), _height(height), _format(format) { 19 | _impl = Renderer::get()->create_texture(width, height, format, data, size, mips); 20 | } 21 | Texture::~Texture() { 22 | Renderer::get()->destroy_texture(_impl); 23 | } 24 | 25 | void Texture::load(const void* data, size_t size, Vector3i offset, Vector3i extent) { 26 | Renderer::get()->load_texture(_impl, data, size, offset, extent); 27 | } 28 | 29 | const Texture& Texture::black() { 30 | static const uint32_t black_color(0); 31 | static Texture texture(1, 1, RenderFormat::R8G8B8A8_UNorm, &black_color, sizeof(black_color)); 32 | return texture; 33 | } 34 | 35 | size_t L::resource_gpu_size(const Texture::Intermediate& v) { 36 | size_t gpu_size = 0; 37 | for(const Buffer& mip : v.mips) { 38 | gpu_size += mip.size(); 39 | } 40 | return gpu_size; 41 | } 42 | -------------------------------------------------------------------------------- /src/rendering/Texture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../container/Array.h" 4 | #include "../container/Buffer.h" 5 | #include "../macros.h" 6 | #include "../math/Vector.h" 7 | #include "Renderer.h" 8 | 9 | namespace L { 10 | class Texture { 11 | L_NOCOPY(Texture) 12 | protected: 13 | uint32_t _width, _height; 14 | RenderFormat _format; 15 | TextureImpl* _impl; 16 | 17 | public: 18 | struct Intermediate { 19 | Array mips; 20 | uint32_t width, height; 21 | RenderFormat format; 22 | }; 23 | Texture(const Intermediate& intermediate); 24 | Texture(uint32_t width, uint32_t height, RenderFormat format = RenderFormat::R8G8B8A8_UNorm, const void* data = nullptr, size_t size = 0); 25 | Texture(uint32_t width, uint32_t height, RenderFormat format, const void** data, size_t* size, uint32_t mips); 26 | ~Texture(); 27 | inline void load(const void* data, size_t size) { load(data, size, {}, Vector3i{int32_t(_width), int32_t(_height), 1}); } 28 | void load(const void* data, size_t size, Vector3i offset, Vector3i extent); 29 | 30 | inline TextureImpl* get_impl() const { return _impl; } 31 | inline uint32_t width() const { return _width; } 32 | inline uint32_t height() const { return _height; } 33 | inline RenderFormat format() const { return _format; } 34 | 35 | static const Texture& black(); 36 | 37 | friend inline void resource_write(Stream& s, const Intermediate& v) { s <= v.mips <= v.width <= v.height <= v.format; } 38 | friend inline void resource_read(Stream& s, Intermediate& v) { s >= v.mips >= v.width >= v.height >= v.format; } 39 | }; 40 | size_t resource_gpu_size(const Texture::Intermediate& v); 41 | } 42 | -------------------------------------------------------------------------------- /src/rendering/UniformBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "UniformBuffer.h" 2 | 3 | using namespace L; 4 | 5 | UniformBuffer::UniformBuffer(size_t size) : _size(size) { 6 | _impl = Renderer::get()->create_uniform_buffer(size); 7 | } 8 | UniformBuffer::~UniformBuffer() { 9 | Renderer::get()->destroy_uniform_buffer(_impl); 10 | } 11 | 12 | void UniformBuffer::load(const void* src, size_t size, size_t offset) { 13 | Renderer::get()->load_uniform_buffer(_impl, src, size, offset); 14 | } 15 | -------------------------------------------------------------------------------- /src/rendering/UniformBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Renderer.h" 4 | #include "../macros.h" 5 | 6 | namespace L { 7 | class UniformBuffer { 8 | L_NOCOPY(UniformBuffer) 9 | protected: 10 | UniformBufferImpl* _impl; 11 | size_t _size; 12 | public: 13 | UniformBuffer(size_t size); 14 | ~UniformBuffer(); 15 | 16 | inline void load(const void* data) { load(data, _size); } 17 | void load(const void* data, size_t size, size_t offset = 0); 18 | template void load_item(const T& datum, size_t offset = 0) { load(&datum, sizeof(T), offset); } 19 | 20 | inline UniformBufferImpl* get_impl() const { return _impl; } 21 | inline size_t size() const { return _size; } 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/resource.rc: -------------------------------------------------------------------------------- 1 | 101 ICON "L.ico" 2 | -------------------------------------------------------------------------------- /src/script/ScriptGlobal.cpp: -------------------------------------------------------------------------------- 1 | #include "ScriptGlobal.h" 2 | 3 | #include "../container/Pool.h" 4 | #include "../container/Table.h" 5 | #include "../parallelism/Lock.h" 6 | 7 | using namespace L; 8 | 9 | static Pool slots; 10 | static Table slots_by_name; 11 | static Lock slots_lock; 12 | 13 | ScriptGlobal::ScriptGlobal(const Symbol& name) { 14 | L_SCOPED_LOCK(slots_lock); 15 | if(Slot** found = slots_by_name.find(name)) { 16 | _slot = *found; 17 | } else { 18 | slots_by_name[name] = _slot = slots.construct(); 19 | _slot->name = name; 20 | } 21 | } 22 | 23 | Array ScriptGlobal::get_all_names() { 24 | L_SCOPED_LOCK(slots_lock); 25 | Array names; 26 | for(const auto& slot : slots_by_name) { 27 | names.push(slot.key()); 28 | } 29 | return names; 30 | } 31 | 32 | Stream& L::operator<=(Stream& s, const ScriptGlobal& v) { 33 | return s <= v._slot->name; 34 | } 35 | Stream& L::operator>=(Stream& s, ScriptGlobal& v) { 36 | Symbol name; 37 | s >= name; 38 | v = ScriptGlobal(name); 39 | return s; 40 | } 41 | -------------------------------------------------------------------------------- /src/script/ScriptGlobal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../container/Array.h" 4 | #include "../dynamic/Variable.h" 5 | #include "../text/Symbol.h" 6 | 7 | namespace L { 8 | class ScriptGlobal { 9 | public: 10 | struct Slot { 11 | Symbol name; 12 | Var value; 13 | }; 14 | 15 | protected: 16 | Slot* _slot; 17 | 18 | public: 19 | constexpr ScriptGlobal() : _slot(nullptr) {} 20 | ScriptGlobal(const Symbol& name); 21 | 22 | inline const Symbol& name() const { return _slot->name; } 23 | inline Var& value() { return _slot->value; } 24 | inline Var& operator=(const Var& value) { return _slot->value = value; } 25 | 26 | static Array get_all_names(); 27 | 28 | friend Stream& operator<=(Stream&, const ScriptGlobal&); 29 | friend Stream& operator>=(Stream&, ScriptGlobal&); 30 | }; 31 | 32 | Stream& operator<=(Stream&, const ScriptGlobal&); 33 | Stream& operator>=(Stream&, ScriptGlobal&); 34 | } 35 | -------------------------------------------------------------------------------- /src/stream/AsyncFileStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "DirectStream.h" 4 | #include "../macros.h" 5 | 6 | namespace L { 7 | class AsyncFileStream : public DirectStream { 8 | protected: 9 | void* _data; 10 | public: 11 | AsyncFileStream(const char* filepath, const char* mode); 12 | ~AsyncFileStream(); 13 | 14 | size_t write(const void* data, size_t size) override; 15 | size_t read(void* data, size_t size) override; 16 | bool end() override; 17 | 18 | uintptr_t tell() override; 19 | void seek(uintptr_t i) override; 20 | size_t size() override; 21 | 22 | operator bool() const; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /src/stream/BufferStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "DirectStream.h" 4 | 5 | namespace L { 6 | class BufferStream : public DirectStream { 7 | protected: 8 | char *_start, *_cur, *_end; 9 | public: 10 | inline BufferStream(char* start, size_t size) : _start(start), _cur(start), _end(start+size) {} 11 | inline BufferStream(char* start, char* end) : _start(start), _cur(start), _end(end) {} 12 | inline size_t write(const void* data, size_t size) override { 13 | size = min(size, (uintptr_t)_cur-(uintptr_t)_end); 14 | if(size) { 15 | memcpy(_cur, data, size); 16 | _cur += size; 17 | } 18 | return size; 19 | } 20 | inline size_t read(void* data, size_t size) override { 21 | size = min(size, (uintptr_t)_end-(uintptr_t)_cur); 22 | if(size) { 23 | memcpy(data, _cur, size); 24 | _cur += size; 25 | } 26 | _cur += (_cur==_end); // Indicate end of stream 27 | return size; 28 | } 29 | inline char get() override { return (_cur<_end) ? *_cur++ : (_cur++, EOF); } 30 | inline void put(char c) override { if(_cur<_end) *_cur++ = c; } 31 | inline bool end() override { return _cur>_end; } 32 | 33 | inline char peek() override { return *_cur; } 34 | inline void seek(uintptr_t i) override { _cur = _start+i; } 35 | inline uintptr_t tell() override { return _cur-_start; } 36 | inline size_t size() override { return _end-_start; } 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /src/stream/CFileStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "DirectStream.h" 5 | 6 | namespace L { 7 | class CFileStream : public DirectStream { 8 | protected: 9 | FILE* _fd; 10 | public: 11 | inline CFileStream(FILE* fd = ::tmpfile()) : _fd(fd) {} 12 | inline CFileStream(const char* filepath, const char* mode) : _fd(fopen(filepath, mode)) {} 13 | inline ~CFileStream() { if(_fd)fclose(_fd); } 14 | 15 | inline size_t write(const void* data, size_t size) override { return fwrite(data, 1, size, _fd); } 16 | inline size_t read(void* data, size_t size) override { return fread(data, 1, size, _fd); } 17 | inline char get() override { return char(fgetc(_fd)); } 18 | inline void put(char c) override { fputc(c, _fd); } 19 | inline bool end() override { return feof(_fd)!=0; } 20 | 21 | inline char peek() override { char c(char(fgetc(_fd))); ungetc(c, _fd); return c; } 22 | inline void rewind() override { ::rewind(_fd); } 23 | inline uintptr_t tell() override { return ::ftell(_fd); } 24 | inline void seek(uintptr_t i) override { ::fseek(_fd, long(i), SEEK_SET); } 25 | inline size_t size() override { 26 | uintptr_t o(tell()); 27 | ::fseek(_fd, 0, SEEK_END); 28 | uintptr_t r(tell()); 29 | seek(o); 30 | return r; 31 | } 32 | inline void flush() { fflush(_fd); } 33 | 34 | operator bool() const { return _fd != nullptr; } 35 | }; 36 | static CFileStream in(stdin), out(stdout), err(stderr); 37 | } 38 | -------------------------------------------------------------------------------- /src/stream/DirectStream.cpp: -------------------------------------------------------------------------------- 1 | #include "DirectStream.h" 2 | 3 | #include "../container/Buffer.h" 4 | 5 | using namespace L; 6 | 7 | Buffer DirectStream::read_into_buffer() { 8 | Buffer buffer(size()); 9 | seek(0); 10 | read(buffer, buffer.size()); 11 | return buffer; 12 | } 13 | -------------------------------------------------------------------------------- /src/stream/DirectStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Stream.h" 4 | 5 | namespace L { 6 | class DirectStream : public Stream { 7 | public: 8 | virtual size_t peek_read(void* data, size_t size) { 9 | uintptr_t pos(tell()); 10 | size_t r(read(data, size)); 11 | seek(pos); 12 | return r; 13 | } 14 | virtual char peek() = 0; 15 | virtual void rewind() { seek(0); } 16 | virtual void seek(uintptr_t) = 0; 17 | virtual uintptr_t tell() = 0; 18 | virtual size_t size() = 0; 19 | 20 | virtual class Buffer read_into_buffer(); 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/stream/NetStream.cpp: -------------------------------------------------------------------------------- 1 | #include "NetStream.h" 2 | 3 | using namespace L; 4 | 5 | #include "../network/Network.h" 6 | 7 | size_t NetStream::write(const void* data, size_t size) { 8 | return Network::send(_sd, (const char*)data, size); 9 | } 10 | size_t NetStream::read(void* data, size_t size) { 11 | return ::recv(_sd, (char*)data, int(size), 0); 12 | } 13 | -------------------------------------------------------------------------------- /src/stream/NetStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Stream.h" 4 | #include "../network/Network.h" 5 | 6 | namespace L { 7 | class NetStream : public Stream { 8 | protected: 9 | SOCKET _sd; 10 | public: 11 | NetStream(SOCKET sd) : _sd(sd) {} 12 | size_t write(const void* data, size_t size); 13 | size_t read(void* data, size_t size); 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/stream/Stream.cpp: -------------------------------------------------------------------------------- 1 | #include "Stream.h" 2 | 3 | #include "../dev/debug.h" 4 | 5 | using namespace L; 6 | 7 | const char* Stream::line() { 8 | static char buffer[4096]; 9 | line(buffer, sizeof(buffer)); 10 | return buffer; 11 | } 12 | void Stream::line(char* buffer, size_t size){ 13 | char* w(buffer); 14 | char* buffer_end(buffer+size); 15 | while((*w = get())!='\n' && *w!='\r' && !end()) { // Not end of line or file 16 | if(w>buffer || !isspace(*w)) 17 | if(++w == buffer_end) 18 | error("Buffer was too small"); 19 | } 20 | *w = '\0'; // Null-end string 21 | } 22 | const char* Stream::word() { 23 | static char buffer[1024]; 24 | char* w(buffer); 25 | while(!end()) { 26 | *w = get(); 27 | if(isspace(*w)) { 28 | if(w>buffer) // Already have characters in buffer 29 | break; // Word is over 30 | } else w++; 31 | } 32 | *w = '\0'; // Null-end string 33 | return buffer; 34 | } 35 | const char* Stream::bufferize(size_t* size) { 36 | static char buffer[4096]; 37 | char* w(buffer); 38 | while(!end() && w 24 | String to_string(const T& v) { 25 | StringStream ss; 26 | ss << v; 27 | return ss.string(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/stream/serial_bin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../dev/debug.h" 4 | #include "Stream.h" 5 | 6 | namespace L { 7 | template inline Stream& operator<=(Stream& s, const T& v) { s.write(&v, sizeof(v)); return s; } 8 | template inline Stream& operator>=(Stream& s, T& v) { s.read(&v, sizeof(v)); return s; } 9 | } 10 | -------------------------------------------------------------------------------- /src/stream/serial_text.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../dev/debug.h" 4 | #include "Stream.h" 5 | 6 | namespace L { 7 | template inline Stream& operator<(Stream& s, const T&) { error("Unimplemented text out"); return s; } 8 | template inline Stream& operator>(Stream& s, T&) { error("Unimplemented text in"); return s; } 9 | 10 | #define L_SERIAL_NUMERIC(type)\ 11 | inline Stream& operator<(Stream& s, type v) { return s << ntos<10,type>(v) << '\n'; }\ 12 | inline Stream& operator>(Stream& s, type& v) { v = ston<10, type>(s.word()); return s; }\ 13 | 14 | L_SERIAL_NUMERIC(int); 15 | L_SERIAL_NUMERIC(unsigned int); 16 | L_SERIAL_NUMERIC(long long); 17 | L_SERIAL_NUMERIC(unsigned long long); 18 | L_SERIAL_NUMERIC(float); 19 | L_SERIAL_NUMERIC(double); 20 | #undef L_SERIAL_NUMERIC 21 | 22 | inline Stream& operator<(Stream& s, bool v) { return s << (v ? '1' : '0') << '\n'; } 23 | inline Stream& operator>(Stream& s, bool& v) { v = (!strcmp(s.word(), "1")); return s; } 24 | } 25 | -------------------------------------------------------------------------------- /src/system/Arguments.cpp: -------------------------------------------------------------------------------- 1 | #include "Arguments.h" 2 | 3 | #include "../container/Table.h" 4 | #include "../text/String.h" 5 | 6 | using namespace L; 7 | 8 | static Table> arguments; 9 | 10 | void Arguments::init(int argc, const char* argv[]) { 11 | Symbol last_key; 12 | for(intptr_t i = 1; i < argc; i++) { 13 | const char* arg = argv[i]; 14 | if(!strncmp(arg, "--", 2)) { // --key 15 | arg += 2; 16 | } else if(!strncmp(arg, "-", 1)) { // -key 17 | arg += 1; 18 | } else if(last_key) { // Value for last key 19 | arguments[last_key].push(arg); 20 | continue; 21 | } else { 22 | warning("Command line value '%s' has no key", arg); 23 | continue; 24 | } 25 | 26 | // Key or key=values 27 | if(const char* delim = strchr(arg, '=')) { 28 | Array& values = arguments[last_key = Symbol(arg, delim - arg)]; 29 | delim += 1; 30 | while(const char* next_delim = strchr(delim, ',')) { 31 | values.push(Symbol(delim, next_delim - delim)); 32 | delim = next_delim + 1; 33 | } 34 | values.push(delim); 35 | } else { 36 | arguments[last_key = arg]; 37 | } 38 | } 39 | } 40 | 41 | bool Arguments::has(const Symbol& key) { 42 | return arguments.find(key) != nullptr; 43 | } 44 | Symbol Arguments::get(const Symbol& key) { 45 | if(Array* values = arguments.find(key)) { 46 | return (*values)[0]; 47 | } else { 48 | return Symbol(); 49 | } 50 | } 51 | void Arguments::get(const Symbol& key, Array& values) { 52 | if(Array* values_found = arguments.find(key)) { 53 | values = *values_found; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/system/Arguments.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../container/Array.h" 4 | #include "../text/Symbol.h" 5 | 6 | namespace L { 7 | namespace Arguments { 8 | void init(int argc, const char* argv[]); 9 | 10 | bool has(const Symbol& key); 11 | Symbol get(const Symbol& key); 12 | void get(const Symbol& key, Array& values); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/system/File.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../text/String.h" 4 | #include "../time/Date.h" 5 | #include "System.h" 6 | 7 | namespace L { 8 | class File { 9 | protected: 10 | String _path; 11 | public: 12 | inline File(const char* path) : _path(path) {} 13 | inline bool operator<(const File& other) const { return _path < other._path; } 14 | 15 | inline String name() const { return System::pathFile(_path); } 16 | inline String dir() const { return System::pathDirectory(_path); } 17 | inline String ext() const { return _path.begin()+_path.find_last('.')+1; } 18 | inline const String& path() const { return _path; } 19 | 20 | bool exists() const; 21 | void make() const; 22 | 23 | static bool mtime(const char* path, Date&); 24 | static Array list(const char* path); 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /src/system/FileWatch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../container/Array.h" 4 | #include "../text/String.h" 5 | 6 | namespace L { 7 | class FileWatch { 8 | protected: 9 | String _root; 10 | Array _changes; 11 | void* _pimpl; 12 | 13 | public: 14 | FileWatch(const char* root_path); 15 | ~FileWatch(); 16 | void update(); 17 | 18 | inline const Array& get_changes() const { return _changes; } 19 | inline void clear() { _changes.clear(); } 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/system/File_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "File.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace L; 7 | 8 | bool File::exists() const { 9 | return access(_path, F_OK) == 0; 10 | } 11 | void File::make() const { 12 | if(!exists()) 13 | System::call("mkdir \""+_path+"\""); 14 | } 15 | bool File::mtime(const char* path, Date& date) { 16 | struct stat buf; 17 | if(!stat(path, &buf)) { 18 | date = time_t(buf.st_mtim.tv_sec); 19 | return true; 20 | } else return false; 21 | } 22 | Array File::list(const char* path) { 23 | String output; 24 | System::call(String("find ")+path+" -printf \"%p\\n\"", output); 25 | return output.explode('\n'); 26 | } 27 | -------------------------------------------------------------------------------- /src/system/File_win.cpp: -------------------------------------------------------------------------------- 1 | #include "File.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace L; 7 | 8 | bool File::exists() const { 9 | return (GetFileAttributes(_path) != INVALID_FILE_ATTRIBUTES); 10 | } 11 | void File::make() const { 12 | if(!exists()) 13 | System::call("mkdir \""+_path+"\""); 14 | } 15 | bool File::mtime(const char* path, Date& date) { 16 | struct _stat buf; 17 | if(!_stat(path, &buf)) { 18 | date = time_t(buf.st_mtime); 19 | return true; 20 | } else return false; 21 | } 22 | Array File::list(const char* path) { 23 | Array wtr; 24 | HANDLE handle; 25 | WIN32_FIND_DATA find_data; 26 | handle = FindFirstFile(path, &find_data); 27 | if(handle != INVALID_HANDLE_VALUE) { 28 | do { 29 | wtr.push(find_data.cFileName); 30 | } while(FindNextFile(handle, &find_data)); 31 | FindClose(handle); 32 | } 33 | return wtr; 34 | } 35 | -------------------------------------------------------------------------------- /src/system/Memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../dev/debug.h" 6 | 7 | namespace L { 8 | class Memory { 9 | public: 10 | template static T* new_type(Args&&... args) { return new(alloc_type())T(args...); } 11 | template static T* alloc_type(size_t count = 1) { return (T*)alloc(sizeof(T)*count); } 12 | template static T* alloc_type_zero(size_t count = 1) { return (T*)alloc_zero(sizeof(T)*count); } 13 | static void* alloc(size_t); 14 | static void* alloc_zero(size_t); // Allocates and zero-fill block 15 | static void* realloc(void*, size_t oldsize, size_t newsize); 16 | template static void delete_type(T* p) { p->~T(); free_type(p); } 17 | template static void free_type(T* p, size_t count = 1) { free(p, sizeof(T)*count); } 18 | static void free(void*, size_t); 19 | 20 | static void* virtual_alloc(size_t); 21 | static void virtual_free(void*, size_t); 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/system/Memory_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "Memory.h" 2 | 3 | #include 4 | 5 | using namespace L; 6 | 7 | void* Memory::virtual_alloc(size_t size) { 8 | return mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 9 | } 10 | void Memory::virtual_free(void* ptr, size_t size) { 11 | munmap(ptr, size); 12 | } 13 | -------------------------------------------------------------------------------- /src/system/Memory_win.cpp: -------------------------------------------------------------------------------- 1 | #include "Memory.h" 2 | 3 | #include 4 | 5 | using namespace L; 6 | 7 | void* Memory::virtual_alloc(size_t size) { 8 | void* ptr = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 9 | #if L_USE_DEBUG_ALLOC 10 | SYSTEM_INFO si; 11 | GetSystemInfo(&si); 12 | // Put the allocation at the end of the page boundary 13 | const size_t remainder = size % si.dwPageSize; 14 | ptr = (uint8_t*)ptr + (remainder ? si.dwPageSize - remainder : 0); 15 | // Allocate a "no access" page right after the allocation 16 | VirtualAlloc((uint8_t*)ptr + size, si.dwPageSize, MEM_RESERVE, PAGE_NOACCESS); 17 | #endif 18 | return ptr; 19 | } 20 | void Memory::virtual_free(void* ptr, size_t) { 21 | BOOL success = VirtualFree(ptr, 0, MEM_RELEASE); 22 | L_ASSERT(success); 23 | } 24 | -------------------------------------------------------------------------------- /src/system/System.cpp: -------------------------------------------------------------------------------- 1 | #include "System.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace L; 7 | using namespace System; 8 | 9 | #if L_WINDOWS 10 | #define popen _popen 11 | #define pclose _pclose 12 | #endif 13 | 14 | int System::call(const char* cmd, String& output) { 15 | output.clear(); 16 | FILE* pipe(popen(cmd, "r")); 17 | if(pipe) { 18 | char buffer[512]; 19 | while(!feof(pipe)) { 20 | if(size_t count = fread(buffer, 1, sizeof(buffer), pipe)) { 21 | size_t old_size(output.size()); 22 | output.size(old_size+count); 23 | memcpy(output+old_size, buffer, count); 24 | } 25 | } 26 | return pclose(pipe); 27 | } else error("Couldn't open pipe in System"); 28 | return -1; 29 | } 30 | int System::call(const char* cmd) { 31 | return system(cmd); 32 | } 33 | void System::sleep(int milliseconds) { 34 | sleep(Time(0,milliseconds)); 35 | } 36 | String System::pathDirectory(const String& path) { 37 | return path.substr(0,1+path.find_last(slash)); 38 | } 39 | String System::pathFile(const String& path) { 40 | return path.substr(1+path.find_last(slash)); 41 | } 42 | -------------------------------------------------------------------------------- /src/system/System.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../macros.h" 4 | #include "../text/String.h" 5 | #include "../time/Time.h" 6 | #include "../math/Vector.h" 7 | 8 | namespace L { 9 | namespace System { 10 | int call(const char*, String& output); // Makes a system call and fills output 11 | int call(const char*); // Only makes a system call 12 | void sleep(int milliseconds); 13 | void sleep(const Time&); 14 | String pwd(); 15 | 16 | String formatPath(String); 17 | String pathDirectory(const String&); 18 | String pathFile(const String&); 19 | 20 | #if L_WINDOWS 21 | const char slash = '\\'; 22 | #elif L_LINUX 23 | const char slash = '/'; 24 | #endif 25 | 26 | inline void openURL(const String& url) { 27 | #if L_WINDOWS 28 | call("start "+url); 29 | #elif L_LINUX 30 | call("xdg-open "+url); 31 | #endif 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/system/System_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "System.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace L; 8 | using namespace System; 9 | 10 | void System::sleep(const Time& t) { 11 | usleep(t.microseconds()); 12 | } 13 | String System::pwd() { 14 | String wtr; 15 | call("pwd", wtr); 16 | wtr[wtr.size()-1] = '/'; // Because there's a \n at the end 17 | return wtr; 18 | } 19 | 20 | String System::formatPath(String path) { 21 | if(!path.size() || path[0u]!='/') 22 | path = System::pwd()+path; 23 | return path; 24 | } 25 | -------------------------------------------------------------------------------- /src/system/System_win.cpp: -------------------------------------------------------------------------------- 1 | #include "System.h" 2 | 3 | #include 4 | 5 | using namespace L; 6 | using namespace System; 7 | 8 | void System::sleep(const Time& t) { 9 | Sleep(DWORD(t.milliseconds())); 10 | } 11 | String System::pwd() { 12 | String wtr; 13 | call("cd", wtr); 14 | wtr[wtr.size()-1] = slash; // Because there's a \n at the end 15 | return wtr; 16 | } 17 | String System::formatPath(String path) { 18 | // TODO: All paths should use / (at least in frontend) for consistency 19 | if(path != "\\" && (path.size()<2 || path[1]!=':')) 20 | path = System::pwd()+path; 21 | path.replace_all("\\", "/"); 22 | return path; 23 | } 24 | -------------------------------------------------------------------------------- /src/system/Window.cpp: -------------------------------------------------------------------------------- 1 | #include "Window.h" 2 | 3 | #include "System.h" 4 | 5 | using namespace L; 6 | 7 | Window* Window::_instance(nullptr); 8 | 9 | Window::Window() { 10 | _instance = this; 11 | } 12 | void Window::open_fullscreen(const char* title, uint32_t flags) { 13 | open(title, _screen_width, _screen_height, borderless | flags); 14 | } 15 | -------------------------------------------------------------------------------- /src/system/intrinsics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #if _MSC_VER 6 | #include 7 | #endif 8 | 9 | namespace L { 10 | inline uint32_t bsr(uint32_t v) { 11 | #if _MSC_VER 12 | unsigned long wtr; 13 | _BitScanReverse(&wtr,v); 14 | return wtr; 15 | #elif __GNUC__ 16 | return sizeof(v)*8-__builtin_clz(v); 17 | #endif 18 | } 19 | 20 | inline uint32_t bsr(uint64_t v){ 21 | #if _MSC_VER 22 | unsigned long wtr; 23 | _BitScanReverse64(&wtr, v); 24 | return wtr; 25 | #elif __GNUC__ 26 | return sizeof(v)*8-__builtin_clzll(v); 27 | #endif 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/text/Symbol.cpp: -------------------------------------------------------------------------------- 1 | #include "Symbol.h" 2 | 3 | #include "../container/Table.h" 4 | #include "../dev/debug.h" 5 | #include "../parallelism/Lock.h" 6 | #include "../stream/serial_bin.h" 7 | #include "../system/Memory.h" 8 | #include "../macros.h" 9 | 10 | using namespace L; 11 | 12 | static const size_t blob_size = 2*1024*1024; 13 | static Table _symbols; 14 | static char *_blob_next, *_blob_end; 15 | static Lock symbol_lock; 16 | 17 | Symbol::Symbol(const char* str, size_t length) { 18 | L_SCOPED_LOCK(symbol_lock); 19 | const uint32_t hash(fnv1a(str, length)); 20 | if(const char** found = _symbols.find(hash)) 21 | _string = *found; 22 | else { 23 | if(size_t(_blob_end)-size_t(_blob_next)<=(length+1)) { 24 | _blob_next = (char*)Memory::virtual_alloc(blob_size); 25 | _blob_end = _blob_next+blob_size; 26 | } 27 | memcpy(_blob_next, str, length); 28 | _blob_next[length] = '\0'; 29 | _string = _blob_next; 30 | _symbols[hash] = _string; 31 | _blob_next += length+1; 32 | } 33 | } 34 | 35 | Stream& L::operator<=(Stream& s, const Symbol& v) { 36 | const uint16_t len(uint16_t(v._string ? strlen(v) : 0)); 37 | s <= len; 38 | if(len>0) { 39 | s.write(v, len); 40 | } 41 | return s; 42 | } 43 | Stream& L::operator>=(Stream& s, Symbol& v) { 44 | char buffer[256]; 45 | uint16_t len; 46 | s >= len; 47 | if(len>0) { 48 | s.read(buffer, len); 49 | v = Symbol(buffer, len); 50 | } else { 51 | v = Symbol(); 52 | } 53 | return s; 54 | } 55 | -------------------------------------------------------------------------------- /src/text/Symbol.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../stream/Stream.h" 4 | 5 | namespace L { 6 | //! String interning mechanism 7 | //! Should be thread-safe 8 | class Symbol { 9 | private: 10 | const char* _string; 11 | public: 12 | constexpr Symbol() : _string(nullptr) {} 13 | inline Symbol(const char* str) : Symbol(str, strlen(str)) {} 14 | Symbol(const char* str, size_t length); 15 | inline bool operator==(const Symbol& other) const { return _string==other._string; } 16 | inline bool operator!=(const Symbol& other) const { return _string!=other._string; } 17 | inline bool operator<(const Symbol& other) const { return strcmp(_string, other._string)<0; } 18 | inline operator const char*() const { return _string; } 19 | inline explicit operator bool() const { return _string!=nullptr; } 20 | friend inline Stream& operator<<(Stream& s, const Symbol& sym) { return s << sym._string; } 21 | friend inline Stream& operator<(Stream& s, const Symbol& sym) { return s << sym._string << '\n'; } 22 | friend inline Stream& operator>(Stream& s, Symbol& sym) { sym = s.word(); return s; } 23 | friend Stream& operator<=(Stream& s, const Symbol& v); 24 | friend Stream& operator>=(Stream& s, Symbol& v); 25 | friend inline uint32_t hash(const Symbol& sym) { return uint32_t(uintptr_t(sym._string)); } 26 | }; 27 | 28 | Stream& operator<=(Stream& s, const Symbol& v); 29 | Stream& operator>=(Stream& s, Symbol& v); 30 | } 31 | -------------------------------------------------------------------------------- /src/text/compression.cpp: -------------------------------------------------------------------------------- 1 | #include "compression.h" 2 | 3 | using namespace L; 4 | 5 | static const Symbol empty_symbol = "", none_symbol = "none"; 6 | static Array compressions{ 7 | Compression{ 8 | "none", 9 | [](const void* data, size_t size, Stream& out_stream) { out_stream.write(data, size); }, 10 | [](const void* data, size_t size) { return Buffer(data, size); }, 11 | }}; 12 | 13 | void L::register_compression(const Compression& compression) { 14 | compressions.push(compression); 15 | } 16 | const Compression& L::get_compression(const Symbol& name) { 17 | for(const Compression& compression : compressions) { 18 | if(compression.name == name || (L_USE_COMPRESSION && name == empty_symbol && compression.name != none_symbol)) { 19 | return compression; 20 | } 21 | } 22 | return get_compression("none"); 23 | } 24 | const Array& L::get_compressions() { 25 | return compressions; 26 | } 27 | -------------------------------------------------------------------------------- /src/text/compression.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../container/Array.h" 4 | #include "../container/Buffer.h" 5 | #include "../stream/Stream.h" 6 | #include "../text/Symbol.h" 7 | 8 | namespace L { 9 | typedef void CompressFunc(const void* data, size_t size, Stream& out_stream); 10 | typedef Buffer DecompressFunc(const void* data, size_t size); 11 | struct Compression { 12 | Symbol name; 13 | CompressFunc* compress; 14 | DecompressFunc* decompress; 15 | }; 16 | void register_compression(const Compression&); 17 | const Compression& get_compression(const Symbol& name = ""); 18 | const Array& get_compressions(); 19 | } 20 | -------------------------------------------------------------------------------- /src/text/encoding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "String.h" 4 | #include "../container/Array.h" 5 | 6 | namespace L { 7 | // Conversions from utf8 8 | uint32_t utf8_to_utf32(const char*& str); // Returns code point for pointed character and increments pointer to next character 9 | uint32_t utf8_to_utf32(const char* str, int* size); // Returns first utf32 char from utf8 string and puts its byte size in size 10 | Array utf8_to_utf32_array(const char* str); 11 | 12 | // Conversions to utf8 13 | String ansi_to_utf8(String); // Convert ANSI characters to utf8 14 | const char* utf16_to_utf8(uint16_t); // Returns utf8 string from utf16 char 15 | const char* utf32_to_utf8(uint32_t); // Returns utf8 string from utf32 char 16 | 17 | String url_encode(const String&); 18 | String url_decode(const String&); 19 | } 20 | -------------------------------------------------------------------------------- /src/text/format.cpp: -------------------------------------------------------------------------------- 1 | #include "format.h" 2 | 3 | using namespace L; 4 | 5 | String L::format_memory_amount(size_t bytes) { 6 | const char* suffixes[] = { 7 | "B", 8 | "KB", 9 | "MB", 10 | "GB", 11 | "TB", 12 | "PB", 13 | "EB", 14 | "ZB", 15 | }; 16 | 17 | uintptr_t suffix_index = 0; 18 | while(bytes >= (1ull << 11)) { 19 | bytes >>= 10; 20 | suffix_index += 1; 21 | } 22 | 23 | return String(ntos(bytes)) + suffixes[suffix_index]; 24 | } -------------------------------------------------------------------------------- /src/text/format.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "String.h" 4 | 5 | namespace L { 6 | String format_memory_amount(size_t bytes); 7 | } 8 | -------------------------------------------------------------------------------- /src/time/Date.cpp: -------------------------------------------------------------------------------- 1 | #include "Date.h" 2 | 3 | using namespace L; 4 | 5 | Stream& L::operator<<(Stream& s, const Date& v) { 6 | struct tm* tm = localtime(&v._time); 7 | 8 | s << (tm->tm_year+1900); 9 | s << '-' << ntos(tm->tm_mon, 2); 10 | s << '-' << ntos(tm->tm_mday, 2); 11 | s << ' ' << ntos(tm->tm_hour, 2); 12 | s << ':' << ntos(tm->tm_min, 2); 13 | s << ':' << ntos(tm->tm_sec, 2); 14 | return s; 15 | } 16 | -------------------------------------------------------------------------------- /src/time/Date.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../stream/Stream.h" 5 | 6 | namespace L { 7 | class Date { 8 | protected: 9 | time_t _time; 10 | public: 11 | inline Date() = default; 12 | constexpr Date(time_t t) : _time(t) {} 13 | inline bool operator<(const Date& other) const { return difftime(_time, other._time) < 0.f; } 14 | 15 | inline uint32_t year() const { return localtime(&_time)->tm_year + 1900; } 16 | inline uint32_t month() const { return localtime(&_time)->tm_mon; } 17 | inline uint32_t day() const { return localtime(&_time)->tm_mday; } 18 | inline uint32_t hour() const { return localtime(&_time)->tm_hour; } 19 | inline uint32_t minute() const { return localtime(&_time)->tm_min; } 20 | inline uint32_t second() const { return localtime(&_time)->tm_sec; } 21 | inline time_t get_time() const { return _time; } 22 | 23 | inline static Date now() { return time(nullptr); } 24 | 25 | friend Stream& operator<<(Stream& s, const Date& v); 26 | }; 27 | Stream& operator<<(Stream& s, const Date& v); 28 | } 29 | -------------------------------------------------------------------------------- /src/time/ScopedTimer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Time.h" 4 | 5 | namespace L { 6 | class ScopedTimer { 7 | protected: 8 | Time _start; 9 | Time& _counter; 10 | public: 11 | inline ScopedTimer(Time& counter) : _start(Time::now()), _counter(counter) {} 12 | inline ~ScopedTimer() { _counter += Time::now()-_start; } 13 | }; 14 | } -------------------------------------------------------------------------------- /src/time/Time.cpp: -------------------------------------------------------------------------------- 1 | #include "Time.h" 2 | 3 | #include "../text/String.h" 4 | 5 | using namespace L; 6 | 7 | Stream& L::operator<<(Stream &s,const Time& v) { 8 | int c(-1); 9 | int64_t us(v.microseconds()); 10 | if(us<0) { 11 | us = -us; 12 | s << '-'; 13 | } 14 | long long days(us/86400000000LL); 15 | if(days) { s << days << 'd'; c++; } 16 | long long hours((us/3600000000LL)%24LL); 17 | if(hours) { s << ntos<10>(hours,2) << 'h'; if(++c) return s; } 18 | long long mins((us/60000000LL)%60LL); 19 | if(mins) { s << ntos<10>(mins,2) << 'm'; if(++c) return s; } 20 | long long secs((us/1000000LL)%60LL); 21 | if(secs) { s << ntos<10>(secs,2) << 's'; if(++c) return s; } 22 | long long msecs((us/1000LL)%1000LL); 23 | if(msecs) { s << ntos<10>(msecs,3) << "ms"; if(++c) return s; } 24 | long long usecs(us%1000LL); 25 | if(usecs || c<0) { s << ntos<10>(usecs,3) << "us"; if(++c) return s; } 26 | return s; 27 | } 28 | -------------------------------------------------------------------------------- /src/time/Time_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "Time.h" 2 | 3 | #include 4 | 5 | using namespace L; 6 | 7 | Time Time::now() { 8 | struct timeval tv; 9 | gettimeofday(&tv,nullptr); 10 | return Time(tv.tv_usec,0,tv.tv_sec); 11 | } 12 | -------------------------------------------------------------------------------- /src/time/Time_win.cpp: -------------------------------------------------------------------------------- 1 | #include "Time.h" 2 | 3 | #include 4 | 5 | using namespace L; 6 | 7 | static struct WinTimeMult { 8 | double value; 9 | WinTimeMult() { 10 | LARGE_INTEGER freq; 11 | QueryPerformanceFrequency((LARGE_INTEGER*)&freq); 12 | value = 1.0/(double(freq.QuadPart)/1000000.0); 13 | } 14 | } win_time_mult; 15 | 16 | Time Time::now() { 17 | int64_t counter; 18 | QueryPerformanceCounter((LARGE_INTEGER*)&counter); 19 | return Time(int64_t(counter * win_time_mult.value)); 20 | } 21 | -------------------------------------------------------------------------------- /src/time/Timer.cpp: -------------------------------------------------------------------------------- 1 | #include "Timer.h" 2 | 3 | using namespace L; 4 | 5 | Timer::Timer() : _last(Time::now()), _paused(false) {} 6 | void Timer::setoff() { 7 | _last = Time::now(); 8 | } 9 | Time Timer::frame() { 10 | if(!_paused) { 11 | Time now(Time::now()); 12 | Time wtr(now-_last); 13 | _last = now; 14 | return wtr; 15 | } else return 0; 16 | } 17 | Time Timer::since() const { 18 | return Time::now()-_last; 19 | } 20 | bool Timer::every(const Time& span) { 21 | Time now(Time::now()); 22 | if(_last