24 Commits

Author SHA1 Message Date
9b173c64a6 add pkg-config fallback and imported target to sdl find module 2023-10-31 17:06:11 +01:00
3a885ee250 update entt to v3.12.2 2023-09-07 01:51:33 +02:00
00e48f9967 update spdlog to v1.12.0 2023-09-05 11:56:50 +02:00
c791f4c6a1 fix print formatter 2023-09-04 23:46:12 +02:00
7a3823db78 update ImGui to v1.89.9
and reenable obsolte bc of text editor (temp, will be replaced)
2023-09-04 20:57:00 +02:00
1722f61250 negative_bloom 2023-05-11 02:12:05 +02:00
0abb860185 update tracy to v0.9.1 2023-03-05 00:11:16 +01:00
22dc949cc5 update stb to latest, reenable perlin noise 2023-03-05 00:04:31 +01:00
196ea7b93b update imgui to v1.89.3 2023-03-04 23:47:18 +01:00
f655da82d5 silence more conversion warnings 2023-03-04 19:38:13 +01:00
d672f8a52c update github ci emscripten to 3.1.32 2023-03-04 19:14:26 +01:00
6df865de3e fix warning for release builds for opengl es / webgl 2023-03-04 18:57:44 +01:00
e9c62f9201 add small helper to scalar range 2023-03-04 02:35:06 +01:00
7bce78167b mark data const in net interface 2022-12-07 18:42:11 +01:00
a45da5c2b0 remove questionable assert in s6zer 2022-12-07 18:40:12 +01:00
4ab1d99529 add color component as s6zer, will do more later 2022-12-07 00:35:25 +01:00
f27300a8fa add new serializer based on bitpacking
it has the important stuff, but still misses conviniences like buffers
and optimizations like varints.
only works for little endian but theoretically only needs endian
detection to be able to support bigendian
2022-12-07 00:35:25 +01:00
8d24976a13 entt update to v3.11.1 2022-12-03 20:26:24 +01:00
8036fdf2a9 constexpr range 2022-12-02 00:59:09 +01:00
5148ea7217 componets json with defaults, minor formatting 2022-11-26 13:48:52 +01:00
ab0e5afb94 add ordered_json variants for reading files 2022-11-24 20:50:02 +01:00
191e9f6b44 ico for exe 2022-11-24 20:44:13 +01:00
86c52c4fac add sound sfxr loaders 2022-11-18 22:32:10 +01:00
0c1a98cfd5 fix opengl shader mismatch when linking on intel 2022-11-15 20:22:41 +01:00
71 changed files with 1730 additions and 220 deletions

View File

@ -9,12 +9,12 @@ on:
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Debug
EM_VERSION: 2.0.24
EM_VERSION: 3.1.32
EM_CACHE_FOLDER: 'emsdk-cache'
jobs:
linux:
timeout-minutes: 10
timeout-minutes: 15
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
# You can convert this to a matrix build if you need cross-platform coverage.
@ -26,8 +26,6 @@ jobs:
with:
submodules: recursive
# TODO: cache
- name: Install Dependencies
run: sudo apt update && sudo apt -y install libsdl2-dev xserver-xorg-video-dummy
@ -62,8 +60,6 @@ jobs:
with:
submodules: recursive
# TODO: cache
- name: Install Dependencies
run: sudo apt update && sudo apt -y install libsdl2-dev
@ -102,9 +98,6 @@ jobs:
with:
submodules: recursive
#- name: Install Dependencies
#run: sudo apt update && sudo apt -y install libsdl2-dev
- name: Setup emsdk
uses: mymindstorm/setup-emsdk@v11
with:
@ -134,8 +127,6 @@ jobs:
with:
submodules: recursive
# TODO: cache
- name: Install Dependencies
run: brew install sdl2
@ -156,7 +147,6 @@ jobs:
submodules: recursive
# TODO: cache
- name: Install Dependencies
run: vcpkg install sdl2[core,vulkan]:x64-windows

28
.vimspector.json Normal file
View File

@ -0,0 +1,28 @@
{
"configurations": {
"run_ctest_native": {
"default": true,
"adapter": "CodeLLDB",
"configuration": {
"request": "launch",
"stopOnEntry": true,
"console": "integratedTerminal",
"program": "ctest",
"cwd": "${workspaceRoot}/build"
}
},
"run_native": {
"adapter": "CodeLLDB",
"variables": {
"Executable": "s6zer_test"
},
"configuration": {
"request": "launch",
"stopOnEntry": true,
"console": "integratedTerminal",
"program": "${workspaceRoot}/build/bin/${Executable}",
"cwd": "${workspaceRoot}/build"
}
}
}
}

View File

@ -105,7 +105,7 @@
if(NOT EMSCRIPTEN)
FIND_PATH(SDL2_INCLUDE_DIR SDL.h
FIND_PATH(SDL2_INCLUDE_DIR_TEMP SDL.h
HINTS
$ENV{SDL2}
PATH_SUFFIXES include/SDL2 include SDL2
@ -153,7 +153,7 @@ ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8)
ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8)
IF(NOT SDL2_BUILDING_LIBRARY)
IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
IF(NOT "${SDL2_INCLUDE_DIR_TEMP}" MATCHES ".framework")
# Non-OS X framework versions expect you to also dynamically link to
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
# seem to provide SDL2main for compatibility even though they don't
@ -189,7 +189,7 @@ IF(NOT SDL2_BUILDING_LIBRARY)
/opt
)
ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8)
ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
ENDIF(NOT "${SDL2_INCLUDE_DIR_TEMP}" MATCHES ".framework")
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# SDL2 may require threads on your system.
@ -208,58 +208,67 @@ IF(MINGW)
ENDIF(MINGW)
SET(SDL2_FOUND "NO")
IF(SDL2_LIBRARY_TEMP)
# For SDL2main
IF(NOT SDL2_BUILDING_LIBRARY)
IF(SDL2MAIN_LIBRARY)
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(SDL2MAIN_LIBRARY)
ENDIF(NOT SDL2_BUILDING_LIBRARY)
IF(SDL2_LIBRARY_TEMP)
# For SDL2main
IF(NOT SDL2_BUILDING_LIBRARY)
IF(SDL2MAIN_LIBRARY)
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(SDL2MAIN_LIBRARY)
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
# CMake doesn't display the -framework Cocoa string in the UI even
# though it actually is there if I modify a pre-used variable.
# I think it has something to do with the CACHE STRING.
# So I use a temporary variable until the end so I can set the
# "real" variable in one-shot.
IF(APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
ENDIF(APPLE)
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
# CMake doesn't display the -framework Cocoa string in the UI even
# though it actually is there if I modify a pre-used variable.
# I think it has something to do with the CACHE STRING.
# So I use a temporary variable until the end so I can set the
# "real" variable in one-shot.
IF(APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
ENDIF(APPLE)
# For threads, as mentioned Apple doesn't need this.
# In fact, there seems to be a problem if I used the Threads package
# and try using this line, so I'm just skipping it entirely for OS X.
IF(NOT APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
ENDIF(NOT APPLE)
# For threads, as mentioned Apple doesn't need this.
# In fact, there seems to be a problem if I used the Threads package
# and try using this line, so I'm just skipping it entirely for OS X.
IF(NOT APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
ENDIF(NOT APPLE)
# For MinGW library
IF(MINGW)
SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(MINGW)
# For MinGW library
IF(MINGW)
SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(MINGW)
# Set the final string here so the GUI reflects the final state.
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
# Set the final string here so the GUI reflects the final state.
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
############add_library(SDL UNKNOWN IMPORTED)
#target_link_libraries(SDL INTERFACE ${SDL2_LIBRARY})
#target_include_directories(SDL INTERFACE ${SDL2_INCLUDE_DIR})
#set_target_properties(SDL PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES "${SDL2_LIBRARY}")
set(SDL2_INCLUDE_DIR ${SDL2_INCLUDE_DIR_TEMP} CACHE STRING "Where the SDL2 Headers can be found")
SET(SDL2_INCLUDE_DIR_TEMP "${SDL2_INCLUDE_DIR_TEMP}" CACHE INTERNAL "")
#set_target_properties(SDL PROPERTIES
#INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}")
SET(SDL2_FOUND "YES")
else() # SDL2_LIBRARY_TEMP
# try to pkg-config fallback
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(PKG_C_SDL2 QUIET sdl2)
if (PKG_C_SDL2_FOUND)
SET(SDL2_LIBRARY_TEMP ${PKG_C_SDL2_LIBRARIES})
SET(SDL2_INCLUDE_DIR_TEMP ${PKG_C_SDL2_INCLUDE_DIRS})
#set_target_properties(SDL PROPERTIES
#IMPORTED_LINK_INTERFACE_LANGUAGES "C"
#IMPORTED_LINK_INTERFACE_LIBRARIES "${SDL2_LIBRARY}"
#LINK_INTERFACE_LIBRARIES "${SDL2_LIBRARY}")
# Set the final string here so the GUI reflects the final state.
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
#IMPORTED_LOCATION "${SDL2_LIBRARY}")
set(SDL2_INCLUDE_DIR ${SDL2_INCLUDE_DIR_TEMP} CACHE STRING "Where the SDL2 Headers can be found")
SET(SDL2_INCLUDE_DIR_TEMP "${SDL2_INCLUDE_DIR_TEMP}" CACHE INTERNAL "")
#message("II set include dir to ${SDL2_INCLUDE_DIR}")
SET(SDL2_FOUND "YES")
SET(SDL2_FOUND "YES")
endif()
endif()
ENDIF(SDL2_LIBRARY_TEMP)
else() #emsripten
@ -288,4 +297,11 @@ INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
if (SDL2_FOUND)
if (NOT TARGET SDL2::SDL2)
add_library(SDL2::SDL2 INTERFACE IMPORTED)
target_include_directories(SDL2::SDL2 INTERFACE ${SDL2_INCLUDE_DIR})
target_link_libraries(SDL2::SDL2 INTERFACE ${SDL2_LIBRARY})
endif()
endif()

2
external/entt vendored

View File

@ -2,43 +2,31 @@ cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
project(imgui C CXX)
set(CPP_FILES
add_library(imgui
"imgui/imgui.h"
"imgui/imgui.cpp"
"imgui/imgui_draw.cpp"
"imgui/imgui_widgets.cpp"
"imgui/imgui_tables.cpp"
"imgui/imgui_demo.cpp"
"imgui/misc/cpp/imgui_stdlib.cpp"
"imgui_plot_var.cpp"
#"imgui_impl_sdl_gl3.cpp" # very old
#"imgui_impl_sdl.cpp" # old
#"imgui_impl_opengl3.cpp" # old
"imgui/backends/imgui_impl_sdl.cpp"
"imgui/backends/imgui_impl_opengl3.cpp"
)
set(HPP_FILES
"imgui/imgui.h"
"imgui/imstb_rectpack.h"
"imgui/imstb_textedit.h"
"imgui/imstb_truetype.h"
"imgui/misc/cpp/imgui_stdlib.h"
"imgui/misc/cpp/imgui_stdlib.cpp"
"imgui_plot_var.hpp"
"imgui_plot_var.cpp"
#"imgui_impl_sdl_gl3.h" # very old
#"imgui_impl_sdl.h" # old
#"imgui_impl_opengl3.h" # old
"imgui/backends/imgui_impl_sdl.h"
# TODO: seperate backends into libs
"imgui/backends/imgui_impl_sdl2.h"
"imgui/backends/imgui_impl_sdl2.cpp"
"imgui/backends/imgui_impl_opengl3.h"
"imgui/backends/imgui_impl_opengl3.cpp"
)
add_library(imgui ${CPP_FILES} ${HPP_FILES})
target_compile_features(imgui PUBLIC cxx_std_11)
if(MM_OPENGL_3_GLES)
@ -53,7 +41,7 @@ target_include_directories(imgui PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
#target_include_directories(imgui PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/imgui")
target_include_directories(imgui PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/imgui") # im sad
target_compile_definitions(imgui PUBLIC IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1)
#target_compile_definitions(imgui PUBLIC IMGUI_DISABLE_OBSOLETE_FUNCTIONS=1) # more sad
if(EMSCRIPTEN)
target_compile_options(imgui PUBLIC -sUSE_SDL=2)

View File

@ -11,9 +11,8 @@ target_link_libraries(stb_image stb)
add_library(stb_image_write "stb/stb_image_write.h" "stb_image_write.cpp")
target_link_libraries(stb_image_write stb)
# lel TODO: add back in when patent expires
#add_library(stb_perlin "stb/stb_perlin.h" "stb_perlin.cpp")
#target_link_libraries(stb_perlin stb)
add_library(stb_perlin "stb/stb_perlin.h" "stb_perlin.cpp")
target_link_libraries(stb_perlin stb)
add_library(stb_rect_pack "stb/stb_rect_pack.h" "stb_rect_pack.cpp")
target_link_libraries(stb_rect_pack stb)

View File

@ -10,6 +10,8 @@ if(NOT EMSCRIPTEN)
"${CMAKE_CURRENT_LIST_DIR}/tracy/public/TracyClient.cpp"
)
option(TRACY_ENABLE "Enable tracy profiling" OFF)
if(TRACY_ENABLE)
target_compile_definitions(tracy_client PUBLIC TRACY_ENABLE)
#target_compile_definitions(tracy_client PUBLIC TRACY_NO_SYSTEM_TRACING)

View File

@ -5,6 +5,7 @@ project(framework)
add_subdirectory(engine)
add_subdirectory(logger)
add_subdirectory(resource_manager)
add_subdirectory(s6zer)
add_subdirectory(common_components)
add_subdirectory(std_utils)
add_subdirectory(random)

View File

@ -4,6 +4,8 @@ project(common_components CXX)
add_library(common_components INTERFACE)
add_library(MM::common_components ALIAS common_components)
target_include_directories(common_components INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(common_components INTERFACE
@ -13,8 +15,23 @@ target_link_libraries(common_components INTERFACE
##########################
add_library(common_components_serialize_s6zer INTERFACE)
add_library(MM::common_components_serialize_s6zer ALIAS common_components_serialize_s6zer)
target_include_directories(common_components_serialize_s6zer INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(common_components_serialize_s6zer INTERFACE
common_components
s6zer
)
##########################
add_library(common_components_serialize_json INTERFACE)
add_library(MM::common_components_serialize_json ALIAS common_components_serialize_json)
target_include_directories(common_components_serialize_json INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(common_components_serialize_json INTERFACE

View File

@ -4,7 +4,7 @@
namespace MM::Components {
struct Name {
static const size_t max_str_len = 64;
static const size_t max_str_len {64u};
std::string str;
};
}

View File

@ -4,7 +4,7 @@ namespace MM::Components {
// used to lift 2D into 3D space. like a z-index in css/svg
struct Position2D_ZOffset {
float z_offset = 500.f; // default camera allows values to be between 0 and 1000
float z_offset {500.f}; // default camera allows values to be between 0 and 1000
};
} // MM::Components

View File

@ -7,6 +7,6 @@
#include "./json_glm.hpp"
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Color, color)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Color, color)
} // MM::Components

View File

@ -9,12 +9,12 @@
namespace glm {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(vec2, x, y)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(vec3, x, y, z)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(vec4, x, y, z, w)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(vec2, x, y)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(vec3, x, y, z)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(vec4, x, y, z, w)
//NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(mat4x4, [0], y, z, w)
inline void to_json(nlohmann::json& nlohmann_json_j, const mat4x4& nlohmann_json_t) {
inline void to_json(nlohmann::json& nlohmann_json_j, const mat4x4& nlohmann_json_t) {
// TODO: make 2d array?
nlohmann_json_j = nlohmann::json::array_t{};
nlohmann_json_j[0] = nlohmann_json_t[0];
@ -22,7 +22,7 @@ namespace glm {
nlohmann_json_j[2] = nlohmann_json_t[2];
nlohmann_json_j[3] = nlohmann_json_t[3];
}
inline void from_json(const nlohmann::json& nlohmann_json_j, mat4x4& nlohmann_json_t) {
inline void from_json(const nlohmann::json& nlohmann_json_j, mat4x4& nlohmann_json_t) {
if (!nlohmann_json_j.is_array()) {
//throw nlohmann::json::type_error::create(0, "", nlohmann_json_j);
assert(false && "expected array");

View File

@ -5,6 +5,7 @@
#include <mm/components/name.hpp>
namespace MM::Components {
// TODO: manual with str len limit
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Name, str)
} // MM::Components

View File

@ -7,6 +7,6 @@
#include "./json_glm.hpp"
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Position2D, pos)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Position2D, pos)
} // MM::Components

View File

@ -7,6 +7,6 @@
#include "./json_glm.hpp"
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Position2D_ZOffset, z_offset)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Position2D_ZOffset, z_offset)
} // MM::Components

View File

@ -7,6 +7,6 @@
#include "./json_glm.hpp"
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Position3D, pos)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Position3D, pos)
} // MM::Components

View File

@ -7,6 +7,6 @@
#include "./json_glm.hpp"
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Rotation2D, rot)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Rotation2D, rot)
} // MM::Components

View File

@ -7,6 +7,6 @@
#include "./json_glm.hpp"
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Scale2D, scale)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Scale2D, scale)
} // MM::Components

View File

@ -7,6 +7,6 @@
#include "./json_glm.hpp"
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Transform4x4, trans)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Transform4x4, trans)
} // MM::Components

View File

@ -7,6 +7,6 @@
#include "./json_glm.hpp"
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Velocity2DPosition, pos_vel)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Velocity2DPosition, pos_vel)
} // MM::Components

View File

@ -7,6 +7,6 @@
#include "./json_glm.hpp"
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Velocity2DPositionIntent, intent)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Velocity2DPositionIntent, intent)
} // MM::Components

View File

@ -7,6 +7,6 @@
#include "./json_glm.hpp"
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Velocity2DRotation, rot_vel)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Velocity2DRotation, rot_vel)
} // MM::Components

View File

@ -5,6 +5,6 @@
#include <mm/components/view_dir2d.hpp>
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ViewDir2D, dir)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(ViewDir2D, dir)
} // MM::Components

View File

@ -5,6 +5,6 @@
#include <mm/components/view_dir3d.hpp>
namespace MM::Components {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ViewDir3D, yaw, pitch, roll)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(ViewDir3D, yaw, pitch, roll)
} // MM::Components

View File

@ -0,0 +1,17 @@
#pragma once
#include <mm/s6zer/serialize.hpp>
#include <mm/components/color.hpp>
namespace MM::Components {
MM_DEFINE_SERIALIZE(Color,
MM_S6ZER_BAIL(stream.serializeFloat(data.color.r))
MM_S6ZER_BAIL(stream.serializeFloat(data.color.g))
MM_S6ZER_BAIL(stream.serializeFloat(data.color.b))
MM_S6ZER_BAIL(stream.serializeFloat(data.color.a))
)
} // MM::Components

View File

@ -3,7 +3,7 @@
namespace MM::Components {
struct ViewDir2D {
float dir = 0.f; // rad
float dir {0.f}; // rad
};
} // MM::Components

View File

@ -3,9 +3,9 @@
namespace MM::Components {
struct ViewDir3D {
float yaw = 0.f; // rad
float pitch = 0.f; // rad
float roll = 0.f; // rad
float yaw {0.f}; // rad
float pitch {0.f}; // rad
float roll {0.f}; // rad
};
} // MM::Components

View File

@ -7,10 +7,25 @@ target_include_directories(common_component_json_serialization_test PRIVATE ".")
target_link_libraries(common_component_json_serialization_test
common_components_serialize_json
engine
gtest_main
)
add_test(NAME common_component_json_serialization_test COMMAND common_component_json_serialization_test)
########################################
add_executable(common_component_s6zer_serialization_test
component_s6zer_serialization_test.cpp
)
target_include_directories(common_component_s6zer_serialization_test PRIVATE ".")
target_link_libraries(common_component_s6zer_serialization_test
common_components_serialize_s6zer
gtest_main
)
add_test(NAME common_component_s6zer_serialization_test COMMAND common_component_s6zer_serialization_test)

View File

@ -1,4 +1,3 @@
#include "mm/components/position2d.hpp"
#include <gtest/gtest.h>
#include <mm/components/serialize/json_name.hpp>

View File

@ -0,0 +1,289 @@
#include <gtest/gtest.h>
#include <array>
#include <mm/s6zer/serialize.hpp>
//#include <mm/components/serialize/json_name.hpp>
#include <mm/components/serialize/s6zer_color.hpp>
//#include <mm/components/serialize/json_position2d.hpp>
//#include <mm/components/serialize/json_position2d_zoffset.hpp>
//#include <mm/components/serialize/json_position3d.hpp>
//#include <mm/components/serialize/json_rotation2d.hpp>
//#include <mm/components/serialize/json_scale2d.hpp>
//#include <mm/components/serialize/json_transform4x4.hpp>
//#include <mm/components/serialize/json_velocity2d_position.hpp>
//#include <mm/components/serialize/json_velocity2d_position_intent.hpp>
//#include <mm/components/serialize/json_velocity2d_rotation.hpp>
//#include <mm/components/serialize/json_view_dir2d.hpp>
//#include <mm/components/serialize/json_view_dir3d.hpp>
#define TEST_JSON_SERL_EXPAND(x) x
#define TEST_JSON_SERL_IN_OUT(TYPE, JSON_STR, TEST_CORPUS) \
TEST(common_components_json_serialization, in_out_##TYPE) { \
MM::Components::TYPE comp; \
{ /* in */ \
auto j = nlohmann::json::parse(JSON_STR); \
comp = j; \
TEST_CORPUS \
} \
{ /* out */ \
nlohmann::json j; \
j = comp; \
ASSERT_EQ(JSON_STR, j.dump()); \
} \
}
//TEST(common_components_json_serialization, in_out_name) {
//MM::Components::Name comp;
//const char* json_test_file = "{\"str\":\"test_name\"}";
//{ // in
//auto j = nlohmann::json::parse(json_test_file);
//EXPECT_NO_THROW({
//comp = j;
//});
//ASSERT_EQ(comp.str, "test_name");
//}
//{ // out
//nlohmann::json j;
//EXPECT_NO_THROW({
//j = comp;
//});
//ASSERT_EQ(json_test_file, j.dump());
//}
//}
//TEST(common_components_json_serialization, in_out_name_fail) {
//MM::Components::Name name_comp;
//// intentional malformed json string
//const char* json_test_file = "{\"strasdf\":\"test_name\"}";
//{ // in
//auto j = nlohmann::json::parse(json_test_file);
//ASSERT_ANY_THROW({
//name_comp = j;
//});
//}
//}
// ##############################################################
//TEST_S6ZER_SERL_IN_OUT(
//Color,
//R"({"color":{"w":1337.0,"x":0.0,"y":1.0,"z":3.0}})",
//TEST_JSON_SERL_EXPAND({
//glm::vec4 comp_val(0.f, 1.f, 3.f, 1337.f);
//ASSERT_EQ(comp.color.x, comp_val.x);
//ASSERT_EQ(comp.color.y, comp_val.y);
//ASSERT_EQ(comp.color.z, comp_val.z);
//ASSERT_EQ(comp.color.w, comp_val.w);
//})
//)
TEST(common_components_s6zer_serialization, out_in_color) {
const MM::Components::Color comp_out{
{1337.f, 0.f, 1.f, 3.f}
};
std::array<uint32_t, 128> buffer;
size_t buffer_size = buffer.size()*sizeof(uint32_t);
{ // to bits
MM::s6zer::StreamWriter writer{buffer.data(), buffer_size};
ASSERT_TRUE(MM::Components::mm_serialize(writer, comp_out));
ASSERT_TRUE(writer.flush());
buffer_size = writer.bytesWritten();
}
MM::Components::Color comp_in;
{ // from bits
MM::s6zer::StreamReader reader{buffer.data(), buffer_size};
ASSERT_TRUE(MM::Components::mm_serialize(reader, comp_in));
ASSERT_EQ(reader.bytesRead(), buffer_size);
}
ASSERT_EQ(comp_out.color.x, comp_in.color.x);
ASSERT_EQ(comp_out.color.y, comp_in.color.y);
ASSERT_EQ(comp_out.color.z, comp_in.color.z);
ASSERT_EQ(comp_out.color.w, comp_in.color.w);
}
#if 0
// ##############################################################
TEST_JSON_SERL_IN_OUT(
Position2D,
R"({"pos":{"x":42.0,"y":6.0}})",
TEST_JSON_SERL_EXPAND(
ASSERT_EQ(comp.pos.x, 42.f);
ASSERT_EQ(comp.pos.y, 6.f);
)
)
// ##############################################################
TEST_JSON_SERL_IN_OUT(
Position2D_ZOffset,
R"({"z_offset":3.0})",
TEST_JSON_SERL_EXPAND(
ASSERT_EQ(comp.z_offset, 3.f);
)
)
// ##############################################################
TEST_JSON_SERL_IN_OUT(
Position3D,
R"({"pos":{"x":42.0,"y":6.0,"z":44.0}})",
TEST_JSON_SERL_EXPAND(
ASSERT_EQ(comp.pos.x, 42.f);
ASSERT_EQ(comp.pos.y, 6.f);
ASSERT_EQ(comp.pos.z, 44.f);
)
)
// ##############################################################
TEST_JSON_SERL_IN_OUT(
Rotation2D,
R"({"rot":42.0})",
TEST_JSON_SERL_EXPAND(
ASSERT_EQ(comp.rot, 42.f);
)
)
// ##############################################################
TEST_JSON_SERL_IN_OUT(
Scale2D,
R"({"scale":{"x":42.0,"y":6.0}})",
TEST_JSON_SERL_EXPAND(
ASSERT_EQ(comp.scale.x, 42.f);
ASSERT_EQ(comp.scale.y, 6.f);
)
)
// ##############################################################
TEST_JSON_SERL_IN_OUT(
Transform4x4,
R"({"trans":[{"w":0.0,"x":1.0,"y":0.0,"z":0.0},{"w":0.0,"x":0.0,"y":1.0,"z":0.0},{"w":0.0,"x":0.0,"y":0.0,"z":1.0},{"w":1.0,"x":0.0,"y":0.0,"z":0.0}]})",
TEST_JSON_SERL_EXPAND(
ASSERT_EQ(comp.trans, glm::mat4x4{1.f});
)
)
// ##############################################################
TEST_JSON_SERL_IN_OUT(
Velocity2DPosition,
R"({"pos_vel":{"x":42.0,"y":6.0}})",
TEST_JSON_SERL_EXPAND(
ASSERT_EQ(comp.pos_vel.x, 42.f);
ASSERT_EQ(comp.pos_vel.y, 6.f);
)
)
// ##############################################################
TEST_JSON_SERL_IN_OUT(
Velocity2DPositionIntent,
R"({"intent":{"x":42.0,"y":6.0}})",
TEST_JSON_SERL_EXPAND(
ASSERT_EQ(comp.intent.x, 42.f);
ASSERT_EQ(comp.intent.y, 6.f);
)
)
// ##############################################################
TEST_JSON_SERL_IN_OUT(
Velocity2DRotation,
R"({"rot_vel":42.0})",
TEST_JSON_SERL_EXPAND(
ASSERT_EQ(comp.rot_vel, 42.f);
)
)
// ##############################################################
TEST(common_components_json_serialization, in_out_view_dir2d) {
MM::Components::ViewDir2D comp;
const char* json_test_file = R"({"dir":6.0})";
{ // in
auto j = nlohmann::json::parse(json_test_file);
EXPECT_NO_THROW({
comp = j;
});
ASSERT_EQ(comp.dir, 6.f);
}
{ // out
nlohmann::json j;
EXPECT_NO_THROW({
j = comp;
});
ASSERT_EQ(json_test_file, j.dump());
}
}
// ##############################################################
TEST(common_components_json_serialization, in_out_view_dir3d) {
MM::Components::ViewDir3D comp;
const char* json_test_file = R"({"pitch":6.0,"roll":99.0,"yaw":42.0})";
{ // in
auto j = nlohmann::json::parse(json_test_file);
EXPECT_NO_THROW({
comp = j;
});
ASSERT_EQ(comp.yaw, 42.f);
ASSERT_EQ(comp.pitch, 6.f);
ASSERT_EQ(comp.roll, 99.f);
}
{ // out
nlohmann::json j;
EXPECT_NO_THROW({
j = comp;
});
ASSERT_EQ(json_test_file, j.dump());
}
}
#endif
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -50,11 +50,11 @@ namespace MM::Services {
public: // send/recv
// sends a packet of max getMaxPacketSize() bytes
virtual bool sendPacket(peer_id peer, channel_id channel, uint8_t* data, size_t data_size) = 0;
virtual bool sendPacket(peer_id peer, channel_id channel, const uint8_t* data, size_t data_size) = 0;
// sends a packet, automatically split if too big
// !! only on lossless channels
virtual bool sendPacketLarge(peer_id peer, channel_id channel, uint8_t* data, size_t data_size) = 0;
virtual bool sendPacketLarge(peer_id peer, channel_id channel, const uint8_t* data, size_t data_size) = 0;
// TODO: broadcast?
// has any?

View File

@ -316,6 +316,31 @@ nlohmann::json FilesystemService::readJson(const char* filepath) const {
return r;
}
nlohmann::ordered_json FilesystemService::readJsonOrdered(fs_file_t file) const {
if (!file)
return {};
seek(file, 0);
std::string buffer;
readString(file, buffer);
// disable exeptions
// TODO: use callback instead of readString()
return nlohmann::ordered_json::parse(buffer, nullptr, false);
}
nlohmann::ordered_json FilesystemService::readJsonOrdered(const char* filepath) const {
if (!isFile(filepath)) {
return {};
}
auto h = open(filepath, READ);
auto r = readJsonOrdered(h);
close(h);
return r;
}
bool FilesystemService::writeJson(fs_file_t file, nlohmann::json& j, const int indent, const char indent_char) const {
if (!file) {
LOG_ERROR("writing json to invalid file");

View File

@ -78,6 +78,9 @@ class FilesystemService : public Service {
nlohmann::json readJson(fs_file_t file) const;
nlohmann::json readJson(const char* filepath) const;
nlohmann::ordered_json readJsonOrdered(fs_file_t file) const;
nlohmann::ordered_json readJsonOrdered(const char* filepath) const;
bool writeJson(fs_file_t file, nlohmann::json& j, const int indent = -1, const char indent_char = ' ') const;
bool writeJson(const char* filepath, nlohmann::json& j, const int indent = -1, const char indent_char = ' ') const;

View File

@ -85,8 +85,8 @@ private:
bool entityHasComponent(Registry& registry, EntityType& entity, ComponentTypeID type_id)
{
const auto storage_it = registry.storage(type_id);
return storage_it != registry.storage().end() && storage_it->second.contains(entity);
const auto* storage_ptr = registry.storage(type_id);
return storage_ptr != nullptr && storage_ptr->contains(entity);
}
public:
@ -134,10 +134,10 @@ public:
e = registry.create();
// create a copy of an entity component by component
for (auto &&curr: registry.storage()) {
if (auto &storage = curr.second; storage.contains(old_e)) {
for(auto &&curr: registry.storage()) {
if(auto &storage = curr.second; storage.contains(old_e)) {
// TODO: do something with the return value. returns false on failure.
storage.emplace(e, storage.get(old_e));
storage.push(e, storage.value(old_e));
}
}
}
@ -237,17 +237,17 @@ public:
if (comp_list.empty()) {
ImGui::Text("Orphans:");
registry.each([&registry](auto e){
for (EntityType e : registry.template storage<EntityType>()) {
if (registry.orphan(e)) {
MM_IEEE_ENTITY_WIDGET(e, registry, false);
}
});
}
} else {
entt::basic_runtime_view<entt::basic_sparse_set<EntityType>> view{};
entt::runtime_view view{};
for (const auto type : comp_list) {
auto storage_it = registry.storage(type);
if (storage_it != registry.storage().end()) {
view.iterate(registry.storage(type)->second);
auto* storage_ptr = registry.storage(type);
if (storage_ptr != nullptr) {
view.iterate(*storage_ptr);
}
}
@ -264,17 +264,6 @@ public:
}
}
[[deprecated("Use renderEditor() instead. And manage the window yourself.")]]
void render(Registry& registry, EntityType& e)
{
if (show_window) {
if (ImGui::Begin("Entity Editor", &show_window)) {
renderEditor(registry, e);
}
ImGui::End();
}
}
// displays both, editor and list
// uses static internally, use only as a quick way to get going!
void renderSimpleCombo(Registry& registry, EntityType& e)

View File

@ -20,7 +20,7 @@ void Camera3D(MM::Scene& scene) {
ImGui::TextUnformatted("NO CAMERA!");
return;
}
auto& camera = scene.ctx().at<MM::OpenGL::Camera3D>();
auto& camera = scene.ctx().get<MM::OpenGL::Camera3D>();
static bool follow_entity = false;
static MM::Entity tracking = entt::null;

View File

@ -4,6 +4,7 @@
#include <imgui.h>
#include <nlohmann/json.hpp>
#include <imgui/misc/cpp/imgui_stdlib.h>
#include <cinttypes>
namespace MM::ImGuiWidgets {
@ -55,16 +56,16 @@ void JsonViewerSimple(const char* name, const JsonObjectType& json) {
}
break;
case JsonObjectType::value_t::number_integer:
ImGui::TextColored(int_color, "%ld", json.template get<int64_t>());
ImGui::TextColored(int_color, "%" PRId64, json.template get<int64_t>());
break;
case JsonObjectType::value_t::number_unsigned:
ImGui::TextColored(unsigned_color, "%lu", json.template get<uint64_t>());
ImGui::TextColored(unsigned_color, "%" PRIu64, json.template get<uint64_t>());
break;
case JsonObjectType::value_t::number_float:
ImGui::TextColored(float_color, "%f", json.template get<float>());
break;
case JsonObjectType::value_t::object:
ImGui::TextDisabled("{%d}", json.size());
ImGui::TextDisabled("{%zu}", json.size());
ImGui::Indent();
for (auto& [key, value] : json.items()) {
@ -74,7 +75,7 @@ void JsonViewerSimple(const char* name, const JsonObjectType& json) {
break;
case JsonObjectType::value_t::array:
ImGui::TextDisabled("[%d]", json.size());
ImGui::TextDisabled("[%zu]", json.size());
ImGui::Indent();
for (auto& [key, value] : json.items()) {
@ -103,9 +104,9 @@ void JsonViewerTree(const char* name, const JsonObjectType& json) {
ImGui::SameLine();
if (json.is_object()) {
ImGui::TextDisabled("{%d}", json.size());
ImGui::TextDisabled("{%zu}", json.size());
} else { // is_array()
ImGui::TextDisabled("[%d]", json.size());
ImGui::TextDisabled("[%zu]", json.size());
}
if (tree_open) {
@ -143,10 +144,10 @@ void JsonViewerTree(const char* name, const JsonObjectType& json) {
}
break;
case JsonObjectType::value_t::number_integer:
ImGui::TextColored(int_color, "%ld", json.template get<int64_t>());
ImGui::TextColored(int_color, "%" PRId64, json.template get<int64_t>());
break;
case JsonObjectType::value_t::number_unsigned:
ImGui::TextColored(unsigned_color, "%lu", json.template get<uint64_t>());
ImGui::TextColored(unsigned_color, "%" PRIu64, json.template get<uint64_t>());
break;
case JsonObjectType::value_t::number_float:
ImGui::TextColored(float_color, "%f", json.template get<float>());
@ -200,9 +201,9 @@ void JsonEditor(const char* name, JsonObjectType& json) {
ImGui::SameLine();
if (json.is_object()) {
ImGui::TextDisabled("{%d}", json.size());
ImGui::TextDisabled("{%zu}", json.size());
} else { // is_array()
ImGui::TextDisabled("[%d]", json.size());
ImGui::TextDisabled("[%zu]", json.size());
}
if (tree_open) {

View File

@ -1,7 +1,7 @@
#include "./imgui_s.hpp"
#include <imgui/imgui.h>
#include <imgui/backends/imgui_impl_sdl.h>
#include <imgui/backends/imgui_impl_sdl2.h>
#ifdef MM_OPENGL_3
#include <imgui/backends/imgui_impl_opengl3.h>

View File

@ -1,4 +1,5 @@
#include "./scene_tools.hpp"
#include "mm/engine_fwd.hpp"
#include <mm/engine.hpp>
@ -109,16 +110,19 @@ namespace MM::Services {
if (_show_scene_metrics) {
if (ImGui::Begin("Scene Metrics##ImGuiSceneToolsService", &_show_scene_metrics)) {
ImGui::Text("capacity: %lu", scene.capacity());
ImGui::Text("size: %lu", scene.size());
ImGui::Text("alive: %lu", scene.alive());
size_t orphans = 0;
scene.each([&orphans, &scene](auto entity) {
if (scene.orphan(entity)) {
orphans++;
ImGui::Text("capacity: %zu", scene.storage<::MM::Entity>().capacity());
ImGui::Text("size: %zu", scene.storage<::MM::Entity>().size());
ImGui::Text("alive: %zu", scene.storage<::MM::Entity>().in_use());
if (ImGui::CollapsingHeader("orphans")) {
// iterating all entities is expensive
size_t orphans = 0;
for (const auto it : scene.storage<MM::Entity>().each()) {
if (scene.orphan(std::get<0>(it))) {
orphans++;
}
}
});
ImGui::Text("orphans: %lu", orphans);
ImGui::Text("orphans: %lu", orphans);
}
}
ImGui::End();
}
@ -157,7 +161,7 @@ namespace MM::Services {
if (_show_time_delta_ctx) {
if (ImGui::Begin("Scene TimeDelta Context", &_show_time_delta_ctx)) {
if (scene.ctx().contains<MM::Components::TimeDelta>()) {
auto& td = scene.ctx().at<MM::Components::TimeDelta>();
auto& td = scene.ctx().get<MM::Components::TimeDelta>();
ImGui::Value("tickDelta", td.tickDelta);
ImGui::SliderFloat("deltaFactor", &td.deltaFactor, 0.f, 10.f, "%.5f", ImGuiSliderFlags_Logarithmic);
} else {

View File

@ -97,6 +97,7 @@ Texture::handle_t Texture::createEmptyMultiSampled(int32_t internalFormat, int32
(void)height;
(void)samples;
assert(false && "GLES has no multisampling support");
return nullptr;
#endif
}

View File

@ -29,14 +29,20 @@ void setup_bloom(
const auto bloom_internal_format = GL_RGB565; // prolly fine. NOPE its not. it causes green pixely halos
const auto bloom_format_type = GL_UNSIGNED_BYTE;
#else
//const auto bloom_internal_format = GL_RGBA16F;
const auto bloom_internal_format = GL_R11F_G11F_B10F;
const auto bloom_format_type = GL_FLOAT;
const auto bloom_format_type = GL_RGBA;
const auto bloom_internal_format = GL_RGBA16F;
//const auto bloom_internal_format = GL_R11F_G11F_B10F;
const auto bloom_data_type = GL_FLOAT;
//const auto bloom_format_type = GL_RGBA_INTEGER;
//const auto bloom_internal_format = GL_RGBA16I;
//const auto bloom_data_type = GL_SHORT;
#endif
#else
//const auto bloom_internal_format = GL_RGB16F;
const auto bloom_internal_format = GL_R11F_G11F_B10F;
const auto bloom_format_type = GL_FLOAT;
const auto bloom_format_type = GL_RGB;
const auto bloom_internal_format = GL_RGB16F; // opengl silently upgrades to RGBA
//const auto bloom_internal_format = GL_R11F_G11F_B10F; // no sign
const auto bloom_data_type = GL_FLOAT;
#endif
{ // bloom in (bloom extraction)
@ -44,7 +50,7 @@ void setup_bloom(
"bloom_in",
bloom_internal_format,
w * bloom_in_scale, h * bloom_in_scale,
GL_RGB, bloom_format_type
bloom_format_type, bloom_data_type
);
{ // filter
rm_t.get("bloom_in"_hs)->bind(0);
@ -72,7 +78,7 @@ void setup_bloom(
tex_out_id,
bloom_internal_format,
w * bloom_in_scale * glm::pow(bloom_phase_scale, i), h * bloom_in_scale * glm::pow(bloom_phase_scale, i),
GL_RGB, bloom_format_type
bloom_format_type, bloom_data_type
);
{ // filter
rm_t.get(tex_out_id)->bind(0);
@ -89,7 +95,7 @@ void setup_bloom(
tex_tmp_id,
bloom_internal_format,
w * bloom_in_scale * glm::pow(bloom_phase_scale, i), h * bloom_in_scale * glm::pow(bloom_phase_scale, i),
GL_RGB, bloom_format_type
bloom_format_type, bloom_data_type
);
{ // filter
rm_t.get(tex_tmp_id)->bind(0);

View File

@ -117,7 +117,7 @@ void BatchedSpriteSheet::render(Services::OpenGLRenderer& rs, Engine& engine) {
_vertexBuffer->bind(GL_ARRAY_BUFFER);
_vao->bind();
auto& cam = scene.ctx().at<Camera3D>();
auto& cam = scene.ctx().get<Camera3D>();
auto vp = cam.getViewProjection();
_shader->setUniformMat4f("_VP", vp);

View File

@ -106,7 +106,15 @@ void main() {
vec3 color = texture(color_tex, _uv).rgb;
// TODO: expose threshold
_out_color = max(vec3(0.0), color - vec3(1.0));
//_out_color = max(vec3(0.0), color - vec3(1.0));
//_out_color = mix(
//color, // < 0.0
//max(vec3(0.0), color - vec3(1.0)), // > 0.0
//step(vec3(0.0), color)
//);
_out_color = max(min(color, vec3(0.0)), color - vec3(1.0));
})")
}

View File

@ -141,7 +141,7 @@ void main() {
vec3 color = texture(color_tex, _uv).rgb;
vec3 bloom = texture(bloom_tex, _uv).rgb;
vec3 comp = color + bloom * vec3(bloom_factor);
vec3 comp = max(vec3(0.0), color + bloom * vec3(bloom_factor));
#if 0
const vec3 tint = vec3(1.5, 0.8, 1.1);

View File

@ -78,7 +78,7 @@ void FastSky::render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) {
_vao->bind();
{
auto& cam = scene.ctx().at<MM::OpenGL::Camera3D>();
auto& cam = scene.ctx().get<MM::OpenGL::Camera3D>();
MM::OpenGL::Camera3D tmp_cam = cam;
// create cam with y up, bc shader says so
tmp_cam.up = {0, 1, 0};
@ -95,7 +95,7 @@ void FastSky::render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) {
//}
auto* ctx_ptr = &_default_context;
if (scene.ctx().contains<FastSkyContext>()) {
ctx_ptr = &scene.ctx().at<FastSkyContext>();
ctx_ptr = &scene.ctx().get<FastSkyContext>();
}
_shader->setUniform1f("time", ctx_ptr->time);

View File

@ -138,7 +138,7 @@ void LiteParticles2D::uploadParticles(Services::OpenGLRenderer&, Scene& scene) {
return; // nothing to upload
}
auto& queue = scene.ctx().at<Components::LiteParticles2DUploadQueue>();
auto& queue = scene.ctx().get<Components::LiteParticles2DUploadQueue>();
while (!queue.queue.empty()) {
// get range
@ -200,7 +200,7 @@ void LiteParticles2D::computeParticles(Services::OpenGLRenderer&, Scene& scene)
std::chrono::duration<double, std::ratio<1, 1>> deltaTime = newNow - _last_time;
_last_time = newNow;
float time_delta = deltaTime.count() * scene.ctx().at<MM::Components::TimeDelta>().deltaFactor;
float time_delta = deltaTime.count() * scene.ctx().get<MM::Components::TimeDelta>().deltaFactor;
_time += time_delta;
_tf_shader->setUniform1f("_time_delta", time_delta);
_tf_shader->setUniform1f("_time", _time);
@ -269,7 +269,7 @@ void LiteParticles2D::renderParticles(Services::OpenGLRenderer& rs, Scene& scene
auto& rm_t = MM::ResourceManager<Texture>::ref();
rm_t.get("MM::LiteParticles2DTypes::Render"_hs)->bind(0);
Camera3D& cam = scene.ctx().at<Camera3D>();
Camera3D& cam = scene.ctx().get<Camera3D>();
_points_shader->setUniformMat4f("_vp", cam.getViewProjection());
GLint view_port[4];

View File

@ -72,7 +72,7 @@ void SimpleRect::render(Services::OpenGLRenderer& rs, Engine& engine) {
_shader->bind();
_vao->bind();
Camera3D& cam = scene.ctx().at<Camera3D>();
Camera3D& cam = scene.ctx().get<Camera3D>();
auto vp = cam.getViewProjection();
scene.view<const Components::Transform4x4>().each([this, &scene, &vp](entt::entity e, const auto& t) {

View File

@ -80,7 +80,7 @@ void SimpleSprite::render(Services::OpenGLRenderer& rs, Engine& engine) {
_vao->bind();
Camera3D& cam = scene.ctx().at<Camera3D>();
Camera3D& cam = scene.ctx().get<Camera3D>();
auto vp = cam.getViewProjection();
scene.view<const Components::Transform4x4, Components::OpenGL::Texture>().each([this, &scene, &vp](entt::entity e, const auto& t, auto& tex) {

View File

@ -81,7 +81,7 @@ void SimpleSpriteSheet::render(Services::OpenGLRenderer& rs, Engine& engine) {
_vertexBuffer->bind(GL_ARRAY_BUFFER);
_vao->bind();
Camera3D& cam = scene.ctx().at<Camera3D>();
Camera3D& cam = scene.ctx().get<Camera3D>();
auto vp = cam.getViewProjection();
scene.view<const Components::Transform4x4, SpriteSheetRenderable>().each([this, &scene, &vp](entt::entity e, const auto& t, auto& spr) {

View File

@ -96,7 +96,7 @@ void Tilemap::render(MM::Services::OpenGLRenderer& rs, MM::Engine& engine) {
_vertexBuffer->bind(GL_ARRAY_BUFFER);
_vao->bind();
MM::OpenGL::Camera3D& cam = scene.ctx().at<MM::OpenGL::Camera3D>();
MM::OpenGL::Camera3D& cam = scene.ctx().get<MM::OpenGL::Camera3D>();
auto vp = cam.getViewProjection();
_shader->setUniform3f("_ambient_color", ambient_color);
@ -150,7 +150,7 @@ layout(location = 2) in uint _atlasIndex;
//layout(location = 3) in vec3 _tColor;
//out vec4 _color;
out vec2 _tex_pos;
centroid out vec2 _tex_pos;
void main() {
//gl_Position = vec4(_WVP * vec3(_vertexPosition, 1), 1);

View File

@ -129,8 +129,9 @@ static void setup_fbos(MM::Engine& engine) {
assert(rs.targets["game_view"]);
}
static MM::Engine engine;
TEST(hdr_bloom_pipeline, it) {
MM::Engine engine;
auto& sdl_ss = engine.addService<MM::Services::SDLService>();
ASSERT_TRUE(engine.enableService<MM::Services::SDLService>());
@ -228,7 +229,7 @@ TEST(hdr_bloom_pipeline, it) {
col.color = {3.f, 3.f, 3.f, 1.f};
}
for (int i = 0; i < 10; i++) {
for (int i = 0; i < 5; i++) {
auto e = scene.create();
auto& p = scene.emplace<MM::Components::Position2D>(e);
p.pos.x = i * 9.f - 40;
@ -247,7 +248,43 @@ TEST(hdr_bloom_pipeline, it) {
col.color = {rng.zeroToOne()*2.f, rng.zeroToOne()*2.f, rng.zeroToOne()*2.f, 1.f};
}
for (int i = 5; i < 10; i++) {
auto e = scene.create();
auto& p = scene.emplace<MM::Components::Position2D>(e);
p.pos.x = i * 9.f - 40;
// zoffset is created by event
auto& s = scene.emplace<MM::Components::Scale2D>(e);
s.scale = {5,5};
scene.emplace<MM::Components::Rotation2D>(e);
auto& v = scene.emplace<MM::Components::Velocity2DRotation>(e);
v.rot_vel = i * 0.3f;
auto& col = scene.emplace<MM::Components::Color>(e);
col.color = {rng.zeroToOne()*-2.f, rng.zeroToOne()*-2.f, rng.zeroToOne()*-2.f, 1.f};
}
{ // white background for negatives
auto e = scene.create();
auto& p = scene.emplace<MM::Components::Position2D>(e);
p.pos.y = 30.f;
p.pos.x = 25.f;
auto& s = scene.emplace<MM::Components::Scale2D>(e);
s.scale = {50,150};
auto& col = scene.emplace<MM::Components::Color>(e);
col.color = {1.f, 1.f, 1.f, 1.f};
}
engine.run();
#ifndef __EMSCRIPTEN__
engine.cleanup();
#endif
}
int main(int argc, char** argv) {

View File

@ -81,7 +81,7 @@ void OrganizerSceneService::sceneFixedUpdate(Engine&) {
_accumulator -= f_delta;
continuous_counter++;
for (auto&& v : _scene->ctx().at<std::vector<entt::organizer::vertex>>()) {
for (auto&& v : _scene->ctx().get<std::vector<entt::organizer::vertex>>()) {
v.callback()(v.data(), *_scene);
}
@ -126,7 +126,8 @@ void OrganizerSceneService::updateOrganizerVertices(Scene& scene) {
scene.ctx().emplace<MM::Components::TimeDelta>();
}
SPDLOG_DEBUG("graph:\n{}", scene.ctx().at<std::vector<entt::organizer::vertex>>());
// TODO: use entt::dot instead
SPDLOG_DEBUG("graph:\n{}", scene.ctx().get<std::vector<entt::organizer::vertex>>());
}
void OrganizerSceneService::resetTime(void) {

View File

@ -7,7 +7,7 @@ namespace MM::Random {
// Seeded (Pseudo-) Random Number Generator
struct SRNG {
// make shuffle compat
// make shuffle compat
// TODO: add more type info
using result_type = uint32_t;
@ -35,7 +35,7 @@ struct SRNG {
}
bool roll(float prob) {
return zeroToOne() <= prob;
return zeroToOne() <= prob; // TODO: just < ?
}
// more advanced

View File

@ -75,13 +75,13 @@ class ResourceManager {
return reload<Loader>(entt::hashed_string{id}.value(), std::forward<Args>(args)...);
}
void discard(const res_id_type id) ENTT_NOEXCEPT {
void discard(const res_id_type id) noexcept {
if (auto it = _storage.find(id); it != _storage.end()) {
_storage.erase(it);
}
}
void discard(const char* id) ENTT_NOEXCEPT {
void discard(const char* id) noexcept {
discard(entt::hashed_string{id}.value());
}
@ -100,11 +100,11 @@ class ResourceManager {
return _storage.empty();
}
void clear(void) ENTT_NOEXCEPT {
void clear(void) noexcept {
_storage.clear();
}
bool contains(const res_id_type id) const ENTT_NOEXCEPT {
bool contains(const res_id_type id) const noexcept {
return (_storage.find(id) != _storage.cend());
}

View File

@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
project(s6zer CXX)
add_library(s6zer INTERFACE
#./src/s6zer/stream.hpp
#./src/s6zer/serialize.hpp
)
add_library(MM::s6zer ALIAS s6zer)
target_include_directories(s6zer INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_compile_features(s6zer INTERFACE cxx_std_17)
#target_link_libraries(s6zer
#INTERFACE
#)
if (BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@ -0,0 +1,33 @@
#pragma once
#include "./stream.hpp"
namespace MM::s6zer {
// serialize macros
// TODO: make use of ADL, like nlohmann::json does.
/*
defines mm_serialize functions for you.
a "stream" object is in scope (StreamWriter/StreamReader),
as well as the object of Type called "data".
eg:
MM_DEFINE_SERIALIZE(Test1,
MM_S6ZER_BAIL(stream.serializeBits(data.seq, 16))
MM_S6ZER_BAIL(stream.serializeBits(data.data1, 8))
)
*/
// TODO: refine, so we dont have to do MM_S6ZER_BAIL() everytime
#define MM_DEFINE_SERIALIZE(Type, ...) \
inline bool mm_serialize(MM::s6zer::StreamWriter& stream, const Type& data) { \
__VA_ARGS__ \
return true; \
} \
inline bool mm_serialize(MM::s6zer::StreamReader& stream, Type& data) { \
__VA_ARGS__ \
return true; \
}
} // MM::s6zer

View File

@ -0,0 +1,327 @@
#pragma once
#include <cstddef> // size_t
#include <cstdint> // uint8_t, etc
#include <type_traits>
#include <cassert>
// TODO: make asserts redefinable
namespace MM::s6zer {
// this is heavily inspired by Glenn Fiedler's (Gaffer On Games) serializers
// https://www.gafferongames.com/post/reading_and_writing_packets/
// https://www.gafferongames.com/post/serialization_strategies/
// internal helpers
namespace detail {
// TODO: ugly, replace when c++20
[[nodiscard]] constexpr size_t first_bit_set8(const uint8_t number) {
return
(number & 0b10000000) ? 8 :
(number & 0b01000000) ? 7 :
(number & 0b00100000) ? 6 :
(number & 0b00010000) ? 5 :
(number & 0b00001000) ? 4 :
(number & 0b00000100) ? 3 :
(number & 0b00000010) ? 2 :
(number & 0b00000001) ? 1 :
0
;
}
[[nodiscard]] constexpr size_t first_bit_set32(const uint32_t number) {
return
(number & 0xff000000) ? first_bit_set8((number >> 24) & 0xff) + 24 :
(number & 0x00ff0000) ? first_bit_set8((number >> 16) & 0xff) + 16 :
(number & 0x0000ff00) ? first_bit_set8((number >> 8) & 0xff) + 8 :
(number & 0x000000ff) ? first_bit_set8(number & 0xff) :
0
;
}
[[nodiscard]] constexpr uint32_t byte_swap(const uint32_t value) noexcept {
return
((value & 0xff000000) >> 24) |
((value & 0x00ff0000) >> 8) |
((value & 0x0000ff00) << 8) |
((value & 0x000000ff) << 24)
;
}
[[nodiscard]] constexpr uint16_t byte_swap(const uint16_t value) noexcept {
return
((value & 0xff00) >> 8) |
((value & 0x00ff) << 8)
;
}
[[nodiscard]] constexpr uint8_t byte_swap(const uint8_t value) noexcept {
// noop
return value;
}
template<typename T>
[[nodiscard]] constexpr const T& max(const T& a, const T& b) noexcept {
return (a < b) ? b : a;
}
} // detail
// TODO: maybe 64bit?
// TODO: is this detail?
[[nodiscard]] constexpr size_t bits_required(const uint32_t numbers) {
return detail::first_bit_set32(numbers);
}
[[nodiscard]] constexpr uint32_t serialize_byte_order(const uint32_t value) {
// TODO: only works on little endian for now
if constexpr (true) { // native is little endian
return value;
} else { // native is big endian
return detail::byte_swap(value);
}
}
// helper for fake exceptions
#ifndef MM_S6ZER_BAIL
#define MM_S6ZER_BAIL(...) { \
if (! __VA_ARGS__) { \
return false; \
} \
}
#endif
struct StreamWriter {
StreamWriter(void) = delete;
StreamWriter(uint32_t* data, size_t size) : _data(data), _data_size(size) {
assert(size != 0);
assert(size % sizeof(uint32_t) == 0);
assert(data != nullptr);
}
// do i still need them?
[[nodiscard]] static constexpr bool isWriting(void) noexcept { return true; }
[[nodiscard]] static constexpr bool isReading(void) noexcept { return false; }
[[nodiscard]] bool flush(void) noexcept {
if (_scratch_bits != 0) {
// check if space in buffer
if (_data_size < (_word_index + 1) * sizeof(uint32_t)) {
return false;
}
_data[_word_index] = serialize_byte_order(static_cast<uint32_t>(_scratch & 0xffffffff));
_scratch >>= 32; // new bits are allways unset, so we can just allways 32
// we dont like negative
_scratch_bits = detail::max(static_cast<int32_t>(_scratch_bits) - 32, 0);
_word_index++;
}
return true;
}
template<typename T>
[[nodiscard]] bool serializeBits(const T value, const size_t number_of_bits = sizeof(T)*8) noexcept {
static_assert(std::is_integral_v<T>, "type needs to be an integer");
static_assert(std::is_unsigned_v<T>, "type needs to be unsigned");
static_assert(sizeof(T) <= 4, "not yet defined for > 32bit");
assert(number_of_bits <= sizeof(T)*8);
assert(number_of_bits > 0);
// do scratching
_scratch |= static_cast<uint64_t>(value) << _scratch_bits;
_scratch_bits += number_of_bits;
_bits_written += number_of_bits;
if (_scratch_bits >= 32) {
return flush();
}
return true;
}
[[nodiscard]] bool serializeBool(const bool value) noexcept {
return serializeBits(static_cast<uint32_t>(value), 1);
}
template<typename T>
[[nodiscard]] bool serializeInt(const T value, const T min, const T max) noexcept {
static_assert(std::is_integral_v<T>, "type needs to be an integer");
static_assert(sizeof(T) <= 4, "not yet defined for > 32bit");
assert(max >= min);
assert(value >= min);
assert(value <= max);
const size_t bits = bits_required(max - min);
return serializeBits(static_cast<uint32_t>(value - min), bits);
}
[[nodiscard]] bool serializeFloat(const float value) noexcept {
// TODO: dont use loop
for (size_t i = 0; i < sizeof(float); i++) {
MM_S6ZER_BAIL(serializeBits(reinterpret_cast<const uint8_t*>(&value)[i], 8));
}
return true;
}
[[nodiscard]] bool serializeDouble(const double value) noexcept {
// TODO: dont use loop
for (size_t i = 0; i < sizeof(double); i++) {
MM_S6ZER_BAIL(serializeBits(reinterpret_cast<const uint8_t*>(&value)[i], 8));
}
return true;
}
[[nodiscard]] bool serializeFloatCompressed(const float value, const float min, const float max, const float resolution) noexcept {
assert(max >= min);
assert(value >= min);
assert(value <= max);
// TODO: handle those rounding errors
const float numbers = (max - min) / resolution;
const size_t bits = bits_required(static_cast<uint32_t>(numbers));
const uint32_t tmp_value = static_cast<uint32_t>((value - min) / resolution);
return serializeBits(tmp_value, bits);
}
[[nodiscard]] size_t bytesWritten(void) noexcept {
return (_bits_written+7) / 8;
}
uint32_t* _data {nullptr};
size_t _data_size {0};
uint64_t _scratch {0};
size_t _scratch_bits {0};
size_t _word_index {0};
size_t _bits_written {0}; // includes bits still in scratch
};
struct StreamReader {
StreamReader(void) = delete;
// !! StreamReader assumes the data buffer has whole uint32_t,
// so at the end, even though data_size might be less then 4 bytes,
// here is actually a full, empty uint32
// !! enable AddressSanitzier during development and testing
StreamReader(const uint32_t* data, size_t size) : _data(data), _data_size(size) {
assert(size != 0);
//assert(size % sizeof(uint32_t) == 0);
assert(data != nullptr);
}
// do i still need them?
[[nodiscard]] static constexpr bool isWriting(void) noexcept { return false; }
[[nodiscard]] static constexpr bool isReading(void) noexcept { return true; }
template<typename T>
[[nodiscard]] bool serializeBits(T& value, const size_t number_of_bits = sizeof(T)*8) noexcept {
static_assert(std::is_integral_v<T>, "type needs to be an integer");
static_assert(std::is_unsigned_v<T>, "type needs to be unsigned");
static_assert(sizeof(T) <= 4, "not yet defined for > 32bit");
assert(number_of_bits <= sizeof(T)*8);
assert(number_of_bits > 0);
if (_scratch_bits < number_of_bits) {
if (_bits_read + number_of_bits > _data_size*8) {
// would read past end
return false;
}
_scratch |= static_cast<uint64_t>(serialize_byte_order(_data[_word_index])) << _scratch_bits;
_word_index++;
_scratch_bits += 32;
}
value = _scratch & ((uint64_t(1) << number_of_bits) - 1);
_scratch >>= number_of_bits;
_scratch_bits -= number_of_bits;
_bits_read += number_of_bits;
return true;
}
[[nodiscard]] bool serializeBool(bool& value) noexcept {
uint32_t tmp_value {0};
MM_S6ZER_BAIL(serializeBits(tmp_value, 1));
// :)
value = tmp_value != 0;
return true;
}
template<typename T>
[[nodiscard]] bool serializeInt(T& value, const T min, const T max) noexcept {
static_assert(std::is_integral_v<T>, "type needs to be an integer");
static_assert(sizeof(T) <= 4, "not yet defined for > 32bit");
assert(max >= min);
const size_t bits = bits_required(max - min);
uint32_t tmp_val {0};
MM_S6ZER_BAIL(serializeBits(tmp_val, bits));
value = static_cast<T>(tmp_val) + min;
return true;
}
[[nodiscard]] bool serializeFloat(float& value) noexcept {
// TODO: dont use loop
for (size_t i = 0; i < sizeof(float); i++) {
MM_S6ZER_BAIL(serializeBits(reinterpret_cast<uint8_t*>(&value)[i], 8));
}
return true;
}
[[nodiscard]] bool serializeDouble(double& value) noexcept {
// TODO: dont use loop
for (size_t i = 0; i < sizeof(double); i++) {
MM_S6ZER_BAIL(serializeBits(reinterpret_cast<uint8_t*>(&value)[i], 8));
}
return true;
}
[[nodiscard]] bool serializeFloatCompressed(float& value, const float min, const float max, const float resolution) noexcept {
assert(max >= min);
// TODO: use rounding, rn it snaps (floor)
const float numbers = (max - min) / resolution;
const size_t bits = bits_required(static_cast<uint32_t>(numbers));
uint32_t tmp_value {0};
MM_S6ZER_BAIL(serializeBits(tmp_value, bits));
value = static_cast<float>(tmp_value) * resolution + min;
return true;
}
[[nodiscard]] size_t bytesRead(void) noexcept {
return (_bits_read+7) / 8;
}
const uint32_t* _data {nullptr};
size_t _data_size {0};
uint64_t _scratch {0};
size_t _scratch_bits {0};
size_t _word_index {0};
size_t _bits_read {0};
};
} // MM::s6zer

View File

@ -0,0 +1,18 @@
add_executable(s6zer_test
test.cpp
)
target_include_directories(s6zer_test PRIVATE ".")
target_compile_features(s6zer_test PRIVATE cxx_std_17)
target_link_libraries(s6zer_test
gtest_main
s6zer
random
)
add_test(NAME s6zer_test COMMAND s6zer_test)

View File

@ -0,0 +1,553 @@
#include <mm/s6zer/serialize.hpp>
#include <array>
#include <ostream>
#include <mm/random/srng.hpp>
#include <mm/scalar_range2.hpp>
#include <gtest/gtest.h>
namespace MM {
template<typename Char, typename T>
std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& out, const MM::ScalarRange2<T>& range) {
return out << "{ min: " << static_cast<int64_t>(range.min()) << ", max: " << static_cast<int64_t>(range.max()) << " }";
}
} // MM
TEST(s6zer, bits_required_static) {
static_assert(MM::s6zer::bits_required(0)== 0);
static_assert(MM::s6zer::bits_required(1)== 1);
static_assert(MM::s6zer::bits_required(2)== 2);
static_assert(MM::s6zer::bits_required(3)== 2);
static_assert(MM::s6zer::bits_required(4)== 3);
static_assert(MM::s6zer::bits_required(32)== 6);
static_assert(MM::s6zer::bits_required(0xffffffff)== 32);
static_assert(MM::s6zer::bits_required(0xffffff00)== 32);
static_assert(MM::s6zer::bits_required(0xf0000a00)== 32);
static_assert(MM::s6zer::bits_required(0x0f000000)== 28);
static_assert(MM::s6zer::bits_required(0x0000f000)== 16);
}
TEST(s6zer, byte_swap) {
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint8_t>(0x00)) == 0x00);
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint8_t>(0xff)) == 0xff);
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint8_t>(0x10)) == 0x10);
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint8_t>(0xfe)) == 0xfe);
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint16_t>(0x0000)) == 0x0000);
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint16_t>(0xffff)) == 0xffff);
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint16_t>(0x00fe)) == 0xfe00);
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint16_t>(0xfefe)) == 0xfefe);
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint32_t>(0x00000000)) == 0x00000000);
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint32_t>(0xffffffff)) == 0xffffffff);
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint32_t>(0xf0f00000)) == 0x0000f0f0);
static_assert(MM::s6zer::detail::byte_swap(static_cast<uint32_t>(0xfe0000ef)) == 0xef0000fe);
}
TEST(s6zer, stream_normalcase1) {
const uint32_t num1_orig {0b111};
const uint32_t num1_orig_bits {3};
const uint32_t num2_orig {0b1111111111};
const uint32_t num2_orig_bits {10};
const uint32_t num3_orig {0b111111111111111111111111};
const uint32_t num3_orig_bits {24};
std::array<uint32_t, 2> buffer;
size_t buffer_size = buffer.size()*sizeof(uint32_t);
{
MM::s6zer::StreamWriter writer{buffer.data(), buffer_size};
bool r = false;
ASSERT_EQ(writer._scratch, 0x0);
ASSERT_EQ(writer._scratch_bits, 0);
ASSERT_EQ(writer._word_index, 0);
ASSERT_EQ(writer._bits_written, 0);
ASSERT_EQ(writer.bytesWritten(), 0);
r = writer.serializeBits(num1_orig, num1_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(writer._scratch, 0b0000000000000000000000000000000000000000000000000000000000000'111);
ASSERT_EQ(writer._scratch_bits, 3);
ASSERT_EQ(writer._word_index, 0);
ASSERT_EQ(writer._bits_written, num1_orig_bits);
r = writer.serializeBits(num2_orig, num2_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(writer._scratch, 0b000000000000000000000000000000000000000000000000000'111'1111111111);
ASSERT_EQ(writer._scratch_bits, 3+10);
ASSERT_EQ(writer._word_index, 0);
ASSERT_EQ(writer._bits_written, num1_orig_bits+num2_orig_bits);
r = writer.serializeBits(num3_orig, num3_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(writer._scratch, 0b00000000000000000000000000000000000000000000000000000000000'11111);
ASSERT_EQ(writer._scratch_bits, (3+10+24)-32);
ASSERT_EQ(writer._word_index, 1);
ASSERT_EQ(writer._bits_written, num1_orig_bits+num2_orig_bits+num3_orig_bits);
r = writer.flush();
ASSERT_TRUE(r);
ASSERT_EQ(writer._scratch, 0);
ASSERT_EQ(writer._scratch_bits, 0);
ASSERT_EQ(writer._word_index, 2);
ASSERT_EQ(writer._bits_written, num1_orig_bits+num2_orig_bits+num3_orig_bits); // flush does not change bits written
ASSERT_EQ(writer.bytesWritten(), 5); // 4.625 , so ceil
buffer_size = writer.bytesWritten();
}
std::cout << "buffer_size: " << buffer_size << "\n";
ASSERT_EQ(buffer[0], 0xffffffff);
ASSERT_EQ(buffer[1], 0b000000000000000000000000000'11111);
{
MM::s6zer::StreamReader reader{buffer.data(), buffer_size};
bool r = false;
ASSERT_EQ(reader._scratch, 0x0);
ASSERT_EQ(reader._scratch_bits, 0);
ASSERT_EQ(reader._word_index, 0);
uint32_t num1 {0};
r = reader.serializeBits(num1, num1_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(num1, num1_orig);
ASSERT_EQ(reader._scratch, 0b00000000'00000000'00000000'00000000'000'11111111111111111111111111111);
ASSERT_EQ(reader._scratch_bits, 29);
ASSERT_EQ(reader._word_index, 1); // index refers to next dword
uint32_t num2 {0};
r = reader.serializeBits(num2, num2_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(num2, num2_orig);
ASSERT_EQ(reader._scratch, 0b00000000'00000000'00000000'00000000'000'00000'00000'1111111111111111111);
ASSERT_EQ(reader._scratch_bits, 19);
ASSERT_EQ(reader._word_index, 1); // <=32, so should not yet have read next dword
uint32_t num3 {0};
r = reader.serializeBits(num3, num3_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(num3, num3_orig);
ASSERT_EQ(reader._scratch, 0x0); // no data left
ASSERT_EQ(reader._scratch_bits, 27);
ASSERT_EQ(reader._word_index, 2);
// error case
uint32_t num4 {0};
r = reader.serializeBits(num4, 32);
ASSERT_FALSE(r);
}
}
TEST(s6zer, stream_normalcase1_1) {
const uint32_t num1_orig {0b101};
const uint32_t num1_orig_bits {3};
const uint32_t num2_orig {0b1010101010};
const uint32_t num2_orig_bits {10};
const uint32_t num3_orig {0b101010101010101010101010};
const uint32_t num3_orig_bits {24};
std::array<uint32_t, 2> buffer;
size_t buffer_size = buffer.size()*sizeof(uint32_t);
{
MM::s6zer::StreamWriter writer{buffer.data(), buffer_size};
bool r = false;
ASSERT_EQ(writer._scratch, 0x0);
ASSERT_EQ(writer._scratch_bits, 0);
ASSERT_EQ(writer._word_index, 0);
ASSERT_EQ(writer._bits_written, 0);
ASSERT_EQ(writer.bytesWritten(), 0);
r = writer.serializeBits(num1_orig, num1_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(writer._scratch, 0b0000000000000000000000000000000000000000000000000000000000000'101);
ASSERT_EQ(writer._scratch_bits, 3);
ASSERT_EQ(writer._word_index, 0);
ASSERT_EQ(writer._bits_written, num1_orig_bits);
r = writer.serializeBits(num2_orig, num2_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(writer._scratch, 0b000000000000000000000000000000000000000000000000000'1010101010'101);
ASSERT_EQ(writer._scratch_bits, 3+10);
ASSERT_EQ(writer._word_index, 0);
ASSERT_EQ(writer._bits_written, num1_orig_bits+num2_orig_bits);
r = writer.serializeBits(num3_orig, num3_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(writer._scratch, 0b00000000000000000000000000000000000000000000000000000000000'10101); // the high bits of the 24
ASSERT_EQ(writer._scratch_bits, (3+10+24)-32);
ASSERT_EQ(writer._word_index, 1);
ASSERT_EQ(writer._bits_written, num1_orig_bits+num2_orig_bits+num3_orig_bits);
r = writer.flush();
ASSERT_TRUE(r);
ASSERT_EQ(writer._scratch, 0);
ASSERT_EQ(writer._scratch_bits, 0);
ASSERT_EQ(writer._word_index, 2);
ASSERT_EQ(writer._bits_written, num1_orig_bits+num2_orig_bits+num3_orig_bits); // flush does not change bits written
ASSERT_EQ(writer.bytesWritten(), 5); // 4.625 , so ceil
buffer_size = writer.bytesWritten();
}
std::cout << "buffer_size: " << buffer_size << "\n";
ASSERT_EQ(buffer[0], 0b0101010101010101010'1010101010'101);
ASSERT_EQ(buffer[1], 0b000000000000000000000000000'10101);
{
MM::s6zer::StreamReader reader{buffer.data(), buffer_size};
bool r = false;
ASSERT_EQ(reader._scratch, 0x0);
ASSERT_EQ(reader._scratch_bits, 0);
ASSERT_EQ(reader._word_index, 0);
uint32_t num1 {0};
r = reader.serializeBits(num1, num1_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(num1, num1_orig);
ASSERT_EQ(reader._scratch, 0b00000000'00000000'00000000'00000000'000'0101010101010101010'1010101010);
ASSERT_EQ(reader._scratch_bits, 29);
ASSERT_EQ(reader._word_index, 1); // index refers to next dword
uint32_t num2 {0};
r = reader.serializeBits(num2, num2_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(num2, num2_orig);
ASSERT_EQ(reader._scratch, 0b00000000'00000000'00000000'00000000'000'00000'00000'0101010101010101010);
ASSERT_EQ(reader._scratch_bits, 19);
ASSERT_EQ(reader._word_index, 1); // <=32, so should not yet have read next dword
uint32_t num3 {0};
r = reader.serializeBits(num3, num3_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(num3, num3_orig);
ASSERT_EQ(reader._scratch, 0x0); // no data left
ASSERT_EQ(reader._scratch_bits, 27);
ASSERT_EQ(reader._word_index, 2);
// error case
uint32_t num4 {0};
r = reader.serializeBits(num4, 32);
ASSERT_FALSE(r);
}
}
TEST(s6zer, stream_normalcase2) {
// we now take each number as its maximum, synthetic for testing
const uint32_t num1_orig {17};
const uint32_t num1_orig_bits {MM::s6zer::bits_required(num1_orig)};
const uint32_t num2_orig {1};
const uint32_t num2_orig_bits {MM::s6zer::bits_required(num2_orig)};
const uint32_t num3_orig {1298989};
const uint32_t num3_orig_bits {MM::s6zer::bits_required(num3_orig)};
std::array<uint32_t, 2> buffer;
size_t buffer_size = buffer.size()*sizeof(uint32_t);
{
MM::s6zer::StreamWriter writer{buffer.data(), buffer_size};
// fewer asserts
bool r = false;
ASSERT_EQ(writer._scratch, 0x0);
ASSERT_EQ(writer._scratch_bits, 0);
ASSERT_EQ(writer._word_index, 0);
ASSERT_EQ(writer._bits_written, 0);
ASSERT_EQ(writer.bytesWritten(), 0);
r = writer.serializeBits(num1_orig, num1_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(writer._bits_written, num1_orig_bits);
r = writer.serializeBits(num2_orig, num2_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(writer._bits_written, num1_orig_bits+num2_orig_bits);
r = writer.serializeBits(num3_orig, num3_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(writer._bits_written, num1_orig_bits+num2_orig_bits+num3_orig_bits);
r = writer.flush();
ASSERT_TRUE(r);
ASSERT_EQ(writer._scratch, 0);
ASSERT_EQ(writer._scratch_bits, 0);
ASSERT_EQ(writer._bits_written, num1_orig_bits+num2_orig_bits+num3_orig_bits); // flush does not change bits written
buffer_size = writer.bytesWritten();
}
std::cout << "buffer_size: " << buffer_size << "\n";
{
MM::s6zer::StreamReader reader{buffer.data(), buffer_size};
bool r = false;
ASSERT_EQ(reader._scratch, 0x0);
ASSERT_EQ(reader._scratch_bits, 0);
ASSERT_EQ(reader._word_index, 0);
ASSERT_EQ(reader._bits_read, 0);
uint32_t num1 {0};
r = reader.serializeBits(num1, num1_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(num1, num1_orig);
uint32_t num2 {0};
r = reader.serializeBits(num2, num2_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(num2, num2_orig);
uint32_t num3 {0};
r = reader.serializeBits(num3, num3_orig_bits);
ASSERT_TRUE(r);
ASSERT_EQ(num3, num3_orig);
// error case
uint32_t num4 {0};
r = reader.serializeBits(num4, 32);
ASSERT_FALSE(r);
}
}
// emscripten cant do this
#ifndef __EMSCRIPTEN__
bool serialize_int_death_fn(void) {
std::array<uint32_t, 32> dummy_buffer;
MM::s6zer::StreamReader reader{dummy_buffer.data(), dummy_buffer.size()*sizeof(uint32_t)};
int32_t value{0};
MM_S6ZER_BAIL(reader.serializeInt(value, 20, -20)); // wrong order
return true;
}
TEST(s6zer, serialize_int_death) {
ASSERT_DEATH({
[[maybe_unused]] bool ret = serialize_int_death_fn();
}, "failed");
}
#endif
TEST(s6zer, reader_bits_bug1) {
const std::array<uint32_t, 2> buffer {
0x27'5c'19'a1,
0x00'00'3a'c3
};
const size_t buffer_size {6};
MM::s6zer::StreamReader reader{buffer.data(), buffer_size};
uint8_t value_0 {0};
ASSERT_TRUE(reader.serializeBits(value_0));
ASSERT_EQ(value_0, 0xa1);
ASSERT_EQ(reader._scratch_bits, 24);
ASSERT_EQ(reader._scratch, 0x0000000000'27'5c'19);
uint32_t value_1 {0};
ASSERT_TRUE(reader.serializeBits(value_1));
ASSERT_EQ(value_1, 0xc3'27'5c'19);
ASSERT_EQ(reader._scratch_bits, 24);
ASSERT_EQ(reader._scratch, 0x00000000000000'3a);
uint8_t value_2 {0};
ASSERT_TRUE(reader.serializeBits(value_2));
ASSERT_EQ(value_2, 0x3a);
ASSERT_EQ(reader._scratch, 0x0000000000000000);
}
struct TestStruct {
// integers bits
uint8_t u8 {0};
uint16_t u16 {0};
uint32_t u32 {0};
//uint64_t u64 {0};
bool b1 {false};
// integers ranges
uint8_t r_u8 {0};
constexpr static MM::ScalarRange2<uint8_t> r_u8_r{10, 60};
int8_t r_i8 {0};
constexpr static MM::ScalarRange2<int8_t> r_i8_r{-10, 5};
uint16_t r_u16 {0};
constexpr static MM::ScalarRange2<uint16_t> r_u16_r{1, 1026};
int16_t r_i16 {0};
constexpr static MM::ScalarRange2<int16_t> r_i16_r{-1, 1026};
uint32_t r_u32 {0};
constexpr static MM::ScalarRange2<uint32_t> r_u32_r{0, 12341234};
int32_t r_i32 {0};
constexpr static MM::ScalarRange2<int32_t> r_i32_r{-12341234, 10};
// floats
float f32 {0.f};
double f64 {0.};
// float compressed [0; 1] range
constexpr static float c0_f32_resolution = 0.001f;
constexpr static MM::ScalarRange2<float> c0_f32_r{0.f, 1.f};
float c0_f32_0 {0.f};
float c0_f32_1 {0.f};
float c0_f32_2 {0.f};
float c0_f32_3 {0.f};
// float compressed [-1; 1] range
constexpr static float c1_f32_resolution = 0.05f;
constexpr static MM::ScalarRange2<float> c1_f32_r{-1.f, 1.f};
float c1_f32_0 {0.f};
float c1_f32_1 {0.f};
float c1_f32_2 {0.f};
float c1_f32_3 {0.f};
// float compressed [-1000; 1000] range
constexpr static float c2_f32_resolution = 0.01f;
constexpr static MM::ScalarRange2<float> c2_f32_r{-1000.f, 1000.f};
float c2_f32_0 {0.f};
float c2_f32_1 {0.f};
float c2_f32_2 {0.f};
float c2_f32_3 {0.f};
};
MM_DEFINE_SERIALIZE(TestStruct,
MM_S6ZER_BAIL(stream.serializeBits(data.u8))
MM_S6ZER_BAIL(stream.serializeBits(data.u16))
MM_S6ZER_BAIL(stream.serializeBits(data.u32))
MM_S6ZER_BAIL(stream.serializeBool(data.b1))
MM_S6ZER_BAIL(stream.serializeInt(data.r_u8, data.r_u8_r.min(), data.r_u8_r.max()))
MM_S6ZER_BAIL(stream.serializeInt(data.r_i8, data.r_i8_r.min(), data.r_i8_r.max()))
MM_S6ZER_BAIL(stream.serializeInt(data.r_u16, data.r_u16_r.min(), data.r_u16_r.max()))
MM_S6ZER_BAIL(stream.serializeInt(data.r_i16, data.r_i16_r.min(), data.r_i16_r.max()))
MM_S6ZER_BAIL(stream.serializeInt(data.r_u32, data.r_u32_r.min(), data.r_u32_r.max()))
MM_S6ZER_BAIL(stream.serializeInt(data.r_i32, data.r_i32_r.min(), data.r_i32_r.max()))
MM_S6ZER_BAIL(stream.serializeFloat(data.f32))
MM_S6ZER_BAIL(stream.serializeDouble(data.f64))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c0_f32_0, data.c0_f32_r.min(), data.c0_f32_r.max(), data.c0_f32_resolution))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c0_f32_1, data.c0_f32_r.min(), data.c0_f32_r.max(), data.c0_f32_resolution))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c0_f32_2, data.c0_f32_r.min(), data.c0_f32_r.max(), data.c0_f32_resolution))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c0_f32_3, data.c0_f32_r.min(), data.c0_f32_r.max(), data.c0_f32_resolution))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c1_f32_0, data.c1_f32_r.min(), data.c1_f32_r.max(), data.c1_f32_resolution))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c1_f32_1, data.c1_f32_r.min(), data.c1_f32_r.max(), data.c1_f32_resolution))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c1_f32_2, data.c1_f32_r.min(), data.c1_f32_r.max(), data.c1_f32_resolution))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c1_f32_3, data.c1_f32_r.min(), data.c1_f32_r.max(), data.c1_f32_resolution))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c2_f32_0, data.c2_f32_r.min(), data.c2_f32_r.max(), data.c2_f32_resolution))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c2_f32_1, data.c2_f32_r.min(), data.c2_f32_r.max(), data.c2_f32_resolution))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c2_f32_2, data.c2_f32_r.min(), data.c2_f32_r.max(), data.c2_f32_resolution))
MM_S6ZER_BAIL(stream.serializeFloatCompressed(data.c2_f32_3, data.c2_f32_r.min(), data.c2_f32_r.max(), data.c2_f32_resolution))
)
TEST(s6zer, stream_normalfull) {
std::array<uint32_t, 128> buffer;
size_t buffer_size = buffer.size()*sizeof(uint32_t);
MM::Random::SRNG rng{1337, 0};
const TestStruct data_in{
static_cast<uint8_t>(rng()),
static_cast<uint16_t>(rng()),
static_cast<uint32_t>(rng()),
rng.roll(0.5f),
rng.range(TestStruct::r_u8_r),
rng.range(TestStruct::r_i8_r),
rng.range(TestStruct::r_u16_r),
rng.range(TestStruct::r_i16_r),
rng.range(TestStruct::r_u32_r),
rng.range(TestStruct::r_i32_r),
rng.negOneToOne() * 10000000.f,
rng.negOneToOne() * 10000000.,
rng.range(TestStruct::c0_f32_r),
rng.range(TestStruct::c0_f32_r),
rng.range(TestStruct::c0_f32_r),
rng.range(TestStruct::c0_f32_r),
rng.range(TestStruct::c1_f32_r),
rng.range(TestStruct::c1_f32_r),
rng.range(TestStruct::c1_f32_r),
rng.range(TestStruct::c1_f32_r),
rng.range(TestStruct::c2_f32_r),
rng.range(TestStruct::c2_f32_r),
rng.range(TestStruct::c2_f32_r),
rng.range(TestStruct::c2_f32_r),
};
std::cout << "struct size: " << sizeof(TestStruct) << "\n";
{
MM::s6zer::StreamWriter writer{buffer.data(), buffer_size};
ASSERT_TRUE(mm_serialize(writer, data_in));
ASSERT_TRUE(writer.flush());
buffer_size = writer.bytesWritten();
}
std::cout << "buffer_size: " << buffer_size << "\n";
TestStruct data_out{}; // all zero
{
MM::s6zer::StreamReader reader{buffer.data(), buffer_size};
ASSERT_TRUE(mm_serialize(reader, data_out));
ASSERT_EQ(reader._scratch, 0x0000000000000000);
}
std::cout << "buffer: ";
for (size_t i = 0; i < buffer_size; i++) {
std::cout << std::hex << static_cast<uint32_t>(reinterpret_cast<uint8_t*>(buffer.data())[i]) << "'";
}
std::cout << "\n";
//std::cout << "data_out: \n" << data_out;
ASSERT_EQ(data_in.u8, data_out.u8);
ASSERT_EQ(data_in.u16, data_out.u16);
ASSERT_EQ(data_in.u32, data_out.u32);
ASSERT_EQ(data_in.b1, data_out.b1);
ASSERT_EQ(data_in.r_u8, data_out.r_u8) << "value range: " << TestStruct::r_u8_r;
ASSERT_EQ(data_in.r_i8, data_out.r_i8) << "value range: " << TestStruct::r_i8_r;
ASSERT_EQ(data_in.r_u16, data_out.r_u16) << "value range: " << TestStruct::r_u16_r;
ASSERT_EQ(data_in.r_i16, data_out.r_i16) << "value range: " << TestStruct::r_i16_r;
ASSERT_EQ(data_in.r_u32, data_out.r_u32) << "value range: " << TestStruct::r_u32_r;
ASSERT_EQ(data_in.r_i32, data_out.r_i32) << "value range: " << TestStruct::r_i32_r;
// bit perfect copies, can have wrong results for special values <.<
ASSERT_EQ(data_in.f32, data_out.f32);
ASSERT_EQ(data_in.f64, data_out.f64);
ASSERT_NEAR(data_in.c0_f32_0, data_out.c0_f32_0, TestStruct::c0_f32_resolution);
ASSERT_NEAR(data_in.c0_f32_1, data_out.c0_f32_1, TestStruct::c0_f32_resolution);
ASSERT_NEAR(data_in.c0_f32_2, data_out.c0_f32_2, TestStruct::c0_f32_resolution);
ASSERT_NEAR(data_in.c0_f32_3, data_out.c0_f32_3, TestStruct::c0_f32_resolution);
ASSERT_NEAR(data_in.c1_f32_0, data_out.c1_f32_0, TestStruct::c1_f32_resolution);
ASSERT_NEAR(data_in.c1_f32_1, data_out.c1_f32_1, TestStruct::c1_f32_resolution);
ASSERT_NEAR(data_in.c1_f32_2, data_out.c1_f32_2, TestStruct::c1_f32_resolution);
ASSERT_NEAR(data_in.c1_f32_3, data_out.c1_f32_3, TestStruct::c1_f32_resolution);
ASSERT_NEAR(data_in.c2_f32_0, data_out.c2_f32_0, TestStruct::c2_f32_resolution);
ASSERT_NEAR(data_in.c2_f32_1, data_out.c2_f32_1, TestStruct::c2_f32_resolution);
ASSERT_NEAR(data_in.c2_f32_2, data_out.c2_f32_2, TestStruct::c2_f32_resolution);
ASSERT_NEAR(data_in.c2_f32_3, data_out.c2_f32_3, TestStruct::c2_f32_resolution);
}

View File

@ -31,9 +31,10 @@ namespace MM::Services {
SDLService::SDLService(uint32_t _sdl_init_flags) {
MM::Logger::initSectionLogger("SDLService");
//#ifdef __EMSCRIPTEN__
//_sdl_init_flags &= ~SDL_INIT_HAPTIC;
//#endif
#ifdef __EMSCRIPTEN__
_sdl_init_flags &= ~SDL_INIT_HAPTIC;
#endif
#if 1 // hack for mingw + wine
_sdl_init_flags &= ~SDL_INIT_SENSOR;
#endif

View File

@ -19,21 +19,6 @@ target_link_libraries(sound_service
###############################
add_library(filesystem_soloud_file
./src/mm/soloud_filesystem_file_impl.hpp
./src/mm/soloud_filesystem_file_impl.cpp
./src/mm/sound_loader_wav.hpp
./src/mm/sound_loader_wav.cpp
)
target_link_libraries(filesystem_soloud_file
filesystem_service
soloud
)
###############################
add_library(soloud_json
./src/mm/soloud_json.hpp
./src/mm/soloud_json.cpp
@ -46,6 +31,24 @@ target_link_libraries(soloud_json
nlohmann_json::nlohmann_json
)
###############################
add_library(filesystem_soloud_file
./src/mm/soloud_filesystem_file_impl.hpp
./src/mm/soloud_filesystem_file_impl.cpp
./src/mm/sound_loader_wav.hpp
./src/mm/sound_loader_wav.cpp
./src/mm/sound_loader_sfxr.hpp
./src/mm/sound_loader_sfxr.cpp
)
target_link_libraries(filesystem_soloud_file
filesystem_service
soloud
soloud_json
)
if (BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@ -0,0 +1,38 @@
#include "./sound_loader_sfxr.hpp"
#include <nlohmann/json.hpp>
#include "./soloud_json.hpp"
#include <mm/services/filesystem.hpp>
namespace MM {
std::shared_ptr<::SoLoud::Sfxr> SoundLoaderSfxrPreset::load(const ::SoLoud::Sfxr::SFXR_PRESETS preset, const int seed) const {
auto sfxr = std::make_shared<::SoLoud::Sfxr>();
sfxr->loadPreset(preset, seed);
return sfxr;
}
std::shared_ptr<::SoLoud::Sfxr> SoundLoaderSfxrJson::load(const nlohmann::json& j) const {
auto sfxr = std::make_shared<::SoLoud::Sfxr>();
*sfxr = j;
return sfxr;
}
std::shared_ptr<::SoLoud::Sfxr> SoundLoaderSfxrFile::load(const std::string& path, MM::Engine& engine) const {
auto& fs = engine.getService<MM::Services::FilesystemService>();
if (!fs.isFile(path.c_str())) {
// TODO: log error
return nullptr;
}
auto j = fs.readJson(path.c_str());
return SoundLoaderSfxrJson{}.load(j);
}
} // MM

View File

@ -0,0 +1,28 @@
#pragma once
#include <memory>
#include <string>
#include <soloud_sfxr.h>
#include <nlohmann/json_fwd.hpp>
namespace MM {
// fwd
class Engine;
struct SoundLoaderSfxrPreset {
std::shared_ptr<::SoLoud::Sfxr> load(const ::SoLoud::Sfxr::SFXR_PRESETS preset, const int seed) const;
};
struct SoundLoaderSfxrJson {
std::shared_ptr<::SoLoud::Sfxr> load(const nlohmann::json& j) const;
};
struct SoundLoaderSfxrFile {
std::shared_ptr<::SoLoud::Sfxr> load(const std::string& path, MM::Engine& engine) const;
};
} // MM

View File

@ -9,8 +9,10 @@ namespace MM {
std::shared_ptr<::SoLoud::Wav> SoundLoaderWavFile::load(const std::string& path, Engine& engine) const {
auto& fs = engine.getService<Services::FilesystemService>();
if (!fs.isFile(path.c_str()))
if (!fs.isFile(path.c_str())) {
// TODO: log error
return nullptr;
}
auto h = fs.open(path.c_str());
@ -19,7 +21,7 @@ std::shared_ptr<::SoLoud::Wav> SoundLoaderWavFile::load(const std::string& path,
auto ptr = std::make_shared<::SoLoud::Wav>();
auto r = ptr->loadFile(&sl_f);
if (r != ::SoLoud::SO_NO_ERROR) {
// log error
// TODO: log error
return nullptr;
}

View File

@ -5,9 +5,11 @@
#include <physfs.h>
#include <mm/soloud_filesystem_file_impl.hpp>
#include <mm/sound_loader_wav.hpp>
#include <mm/sound_loader_sfxr.hpp>
#include <mm/resource_manager.hpp>
#include <soloud_sfxr.h>
#include <soloud_wav.h>
#include <soloud_wavstream.h>
#include <soloud_monotone.h>
@ -21,7 +23,7 @@ using namespace entt::literals;
extern char* argv0;
TEST(soloud_fs_loader, basic) {
TEST(soloud_fs_loader, wav) {
MM::Engine engine;
// setup
@ -59,3 +61,38 @@ TEST(soloud_fs_loader, basic) {
rm.clear();
}
TEST(soloud_fs_loader, sfxr) {
MM::Engine engine;
// setup
auto& sound = engine.addService<MM::Services::SoundService>();
ASSERT_TRUE(engine.enableService<MM::Services::SoundService>());
engine.addService<MM::Services::FilesystemService>(argv0, "soloud_filesystem_loader_test");
ASSERT_TRUE(engine.enableService<MM::Services::FilesystemService>());
auto& rm = MM::ResourceManager<SoLoud::Sfxr>::ref();
sound.engine.setGlobalVolume(0.4f);
ASSERT_FALSE(rm.contains("test_preset"_hs));
rm.load<MM::SoundLoaderSfxrPreset>("test_preset", ::SoLoud::Sfxr::SFXR_PRESETS::EXPLOSION, 0);
ASSERT_TRUE(rm.contains("test_preset"_hs));
// TODO: add load from json
// TODO: add load from json from file
{
auto sh = rm.get("test_preset"_hs);
sound.engine.play(*sh);
while (sound.engine.getActiveVoiceCount()) {
using namespace std::chrono_literals;
std::this_thread::sleep_for(5ms);
}
}
rm.clear();
}

View File

@ -7,14 +7,14 @@ struct ScalarRange2 {
T v_min {};
T v_max {};
ScalarRange2(void) = default;
constexpr ScalarRange2(void) = default;
ScalarRange2(const T& both) noexcept {
constexpr ScalarRange2(const T& both) noexcept {
v_min = both;
v_max = both;
}
ScalarRange2(const T& min, const T& max) noexcept {
constexpr ScalarRange2(const T& min, const T& max) noexcept {
if (min <= max) {
v_min = min;
v_max = max;
@ -24,19 +24,19 @@ struct ScalarRange2 {
}
}
bool operator==(const ScalarRange2<T>& rhs) const {
constexpr bool operator==(const ScalarRange2<T>& rhs) const {
return min() == rhs.min() && max() == rhs.max();
}
bool operator!=(const ScalarRange2<T>& rhs) const {
constexpr bool operator!=(const ScalarRange2<T>& rhs) const {
return !(*this == rhs);
}
[[nodiscard]] T& min(void) { return v_min; }
[[nodiscard]] T& max(void) { return v_max; }
[[nodiscard]] constexpr T& min(void) { return v_min; }
[[nodiscard]] constexpr T& max(void) { return v_max; }
[[nodiscard]] const T& min(void) const { return v_min; }
[[nodiscard]] const T& max(void) const { return v_max; }
[[nodiscard]] constexpr const T& min(void) const { return v_min; }
[[nodiscard]] constexpr const T& max(void) const { return v_max; }
void setMin(const T& new_min) {
min() = new_min;
@ -57,9 +57,19 @@ struct ScalarRange2 {
}
}
[[nodiscard]] bool inRange(T&& value) const {
[[nodiscard]] constexpr bool inRange(T&& value) const {
return value >= min() && value <= max();
}
// lerp between min and max
[[nodiscard]] constexpr T map(const float a) const {
return min() * (1.f-a) + max() * a;
}
// reverse map
[[nodiscard]] constexpr float unmap(const T& v) const {
return (v - min()) / static_cast<float>(max() - min());
}
};
} // MM

BIN
res/mm2.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB