diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index dc1ddc9..d76e2ef 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -1,27 +1,42 @@ +#-----------------------------------------------------------------------------# +# ," /\ ", Azur: A game engine for CASIO fx-CG and PC # +# | _/__\_ | Designed by Lephe' and the Planète Casio community. # +# "._`\/'_." License: MIT # +#-----------------------------------------------------------------------------# +# Build system for third-party libraries bundled with Azur + #--- # gl3w #--- -# Use GL3W as an OpenGL loader on desktop +# Use GL3W to load the OpenGL 3.3 core profile if(AZUR_GRAPHICS_OPENGL_3_3) add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/gl3w/src/gl3w.c" COMMAND ./gl3w_gen.py WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/gl3w") + add_library(gl3w gl3w/src/gl3w.c) target_include_directories(gl3w PUBLIC gl3w/include) + set_target_properties(gl3w PROPERTIES + OUTPUT_NAME "azur_${AZUR_PLATFORM}_gl3w") + # Link with GLX for GL3W to find the extensions, and -ldl target_link_libraries(gl3w INTERFACE PkgConfig::glx -ldl) + + # Library file: libazur_*_gl3w.a + install(TARGETS gl3w DESTINATION ${LIBDIR}) + # Headers + install(DIRECTORY gl3w/include/ DESTINATION ${INCDIR}/azur/gl3w) endif() #--- # GLM #--- -# Define the header-only library -add_library(glm INTERFACE) +# TODO: Get rid of the dependency GLM by using libnum instead -# Set the include directory -target_include_directories(glm INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/glm") +# Headers +install(DIRECTORY glm/glm/ DESTINATION ${INCDIR}/azur/glm/glm) #--- # The Dear ImGui library for SDL + OpenGL3/OpenGLES2 @@ -36,7 +51,7 @@ set(SOURCES imgui/backends/imgui_impl_opengl3.cpp imgui/backends/imgui_impl_sdl.cpp) -# Use Freetype if the library is installed, or the emscripten port +# Use Freetype if the library is available; on emscripten there is a port if(AZUR_PLATFORM_EMSCRIPTEN) list(APPEND SOURCES imgui/misc/freetype/imgui_freetype.cpp) else() @@ -47,32 +62,34 @@ else() endif() add_library(imgui ${SOURCES}) +set_target_properties(imgui PROPERTIES + OUTPUT_NAME "azur_${AZUR_PLATFORM}_imgui") # Try to reduce the size of the binary code by including individual functions -# from the archive, instead of whole files +# from the archive, instead of whole files. (The interface library described in +# FindAzur.cmake sets -Wl,--gc-sections.) target_compile_options(imgui PRIVATE -ffunction-sections) -target_compile_options(imgui INTERFACE -Wl,--gc-sections) - -# Use the included ImGui loader on desktop -if(AZUR_GRAPHICS_OPENGL_3_3) - # Nothing do, loader is built-in -# Use the autonomous GLES 2.0 loader otherwise -elseif(AZUR_GRAPHICS_OPENGL_ES_2_0) - target_compile_definitions(imgui PUBLIC - -DIMGUI_IMPL_OPENGL_ES2) -endif() # FreeType2 settings -if(freetype2_FOUND) - target_compile_definitions(imgui PUBLIC -DIMGUI_ENABLE_FREETYPE) - target_include_directories(imgui PRIVATE imgui/misc/freetype) - target_link_libraries(imgui PUBLIC PkgConfig::freetype2) -elseif(AZUR_PLATFORM_EMSCRIPTEN) +if(AZUR_PLATFORM_EMSCRIPTEN) target_compile_definitions(imgui PUBLIC -DIMGUI_ENABLE_FREETYPE) target_include_directories(imgui PRIVATE imgui/misc/freetype) target_compile_options(imgui PUBLIC -sUSE_FREETYPE=1) target_link_options(imgui INTERFACE -sUSE_FREETYPE=1) +elseif(freetype2_FOUND) + target_compile_definitions(imgui PUBLIC -DIMGUI_ENABLE_FREETYPE) + target_include_directories(imgui PRIVATE imgui/misc/freetype) + target_link_libraries(imgui PUBLIC PkgConfig::freetype2) endif() # Provide include directories target_include_directories(imgui PUBLIC imgui imgui/backends) + +# Library file: libazur_*_imgui.a +install(TARGETS imgui DESTINATION ${LIBDIR}) +# Headers +install(DIRECTORY imgui/ DESTINATION ${INCDIR}/azur/imgui + FILES_MATCHING PATTERN "*.h" + PATTERN examples EXCLUDE + PATTERN docs EXCLUDE + PATTERN .github EXCLUDE) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a16997..9eda42d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,33 +1,54 @@ -cmake_minimum_required(VERSION 3.19) -project(AzurEngine VERSION 0.1) +#-----------------------------------------------------------------------------# +# ," /\ ", Azur: A game engine for CASIO fx-CG and PC # +# | _/__\_ | Designed by Lephe' and the Planète Casio community. # +# "._`\/'_." License: MIT # +#-----------------------------------------------------------------------------# +# Main build system +# +# The build system consists of this CMakeLists.txt file, the CMakeLists.txt +# files of each component folder, and importantly the FindAzur.cmake file +# which loads the library for users. +# +# We build and install third-party dependencies along the engine to alleviate +# some packaging/distribution issues. Currently, these are: +# +# o GL3W, which we rely on to load the OpenGL core profile on PC +# o Dear ImGui, for introspection and debugging tools +# +# The following variables can be set on the command-line at cmake time: +# +# -DCMAKE_BUILD_TYPE: +# Debug Debug build with -O0 -g +# Release Release build with -Os [default] +# +# -DAZUR_PLATFORM: +# gint Build for gint for fx-CG +# linux Build for Linux with SDL and OpenGL 3.3 +# emscripten Build for Emscripten with SDL and OpenGL ES 2.0 +# +# -DCMAKE_INSTALL_PREFIX: +# The usual install prefix. It must be different for each platform. For gint, +# it defaults to the compiler's data folder as usual. The environment +# variable AZUR_PATH_ is recognized by the find module. +#--- -#--- -# Configuration -# -# -DCMAKE_BUILD_TYPE -# Debug Debug build with -O0 -g -# Release Release build with -Os [default] -# -# -DAZUR_PLATFORM -# gint Build for gint for fx-CG -# linux Build for Linux with SDL and OpenGL 3.3 -# emscripten Build for Emscripten with SDL and OpenGL ES 2.0 -# -# -DCMAKE_INSTALL_PREFIX -#--- +cmake_minimum_required(VERSION 3.15) +project(Azur VERSION 0.1 LANGUAGES C CXX ASM) + +set(CMAKE_INSTALL_MESSAGE LAZY) if("${CMAKE_BUILD_TYPE}" STREQUAL "") set("${CMAKE_BUILD_TYPE}" Release) endif() -# Debug build if("${CMAKE_BUILD_TYPE}" STREQUAL Debug) set(AZUR_DEBUG TRUE) else() set(AZUR_DEBUG FALSE) endif() -# When using [fxsdk build-cg], assume gint +# Detect when the fxSDK is used, and assume gint. This allows one to simply run +# `fxsdk build-cg` to build the engine. if("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50) set(AZUR_PLATFORM gint) endif() @@ -35,17 +56,21 @@ endif() # Default install paths set(LIBDIR "lib") set(INCDIR "include") +set(MODPATH "lib/cmake") -# Target configuration: gint -if("${AZUR_PLATFORM}" STREQUAL "gint") +#--- +# Target-specific configuration +#--- + +if(AZUR_PLATFORM STREQUAL gint) set(AZUR_PLATFORM_GENERIC TRUE) set(AZUR_TOOLKIT_GINT TRUE) set(AZUR_GRAPHICS_GINT_CG TRUE) set(AZUR_TERMINAL_NONE TRUE) - find_package(Gint 2.4 REQUIRED) + # Link with gint and libprof (we only do this to get include directories) + find_package(Gint 2.8 REQUIRED) find_package(LibProf 2.4 REQUIRED) - link_libraries(LibProf::LibProf Gint::Gint) # Default to the fxSDK install path @@ -57,26 +82,25 @@ if("${AZUR_PLATFORM}" STREQUAL "gint") if(CMAKE_INSTALL_PREFIX STREQUAL "${FXSDK_COMPILER_INSTALL}") set(LIBDIR ".") set(INCDIR "include") + set(MODPATH "${FXSDK_CMAKE_MODULE_PATH}") endif() endif() -# Target configuration: linux if(AZUR_PLATFORM STREQUAL linux) set(AZUR_PLATFORM_GENERIC TRUE) set(AZUR_TOOLKIT_SDL TRUE) set(AZUR_GRAPHICS_OPENGL_3_3 TRUE) set(AZUR_TERMINAL_ANSI TRUE) + # Once again, we link only for the include paths find_package(PkgConfig REQUIRED) pkg_check_modules(sdl2 REQUIRED sdl2 IMPORTED_TARGET) pkg_check_modules(sdl2_image REQUIRED SDL2_image IMPORTED_TARGET) pkg_check_modules(opengl REQUIRED opengl IMPORTED_TARGET) pkg_check_modules(glx REQUIRED glx IMPORTED_TARGET) - link_libraries(PkgConfig::sdl2_image PkgConfig::sdl2 PkgConfig::opengl -lm) endif() -# Platform configuration: emscripten if(AZUR_PLATFORM STREQUAL emscripten) set(AZUR_PLATFORM_EMSCRIPTEN TRUE) set(AZUR_TOOLKIT_SDL TRUE) @@ -119,3 +143,10 @@ endif() add_subdirectory(libnum) add_subdirectory(azur) + +#--- +# Install +#--- + +# CMake module to find the library +install(FILES FindAzur.cmake DESTINATION ${MODPATH}) diff --git a/FindAzur.cmake b/FindAzur.cmake new file mode 100644 index 0000000..7bc92d0 --- /dev/null +++ b/FindAzur.cmake @@ -0,0 +1,162 @@ +# 1. Find the library's install path and data + +set(AZUR_PATH "$ENV{AZUR_PATH_${AZUR_PLATFORM}}") + +if(NOT "${FXSDK_PLATFORM_LONG}" STREQUAL "") + set(AZUR_PLATFORM gint) + set(AZUR_PATH "${FXSDK_COMPILER_INSTALL}") + set(AZUR_LIB "${AZUR_PATH}/libazur_${AZUR_PLATFORM}.a") + set(AZUR_INCLUDE "${AZUR_PATH}/include") + + message("(Azur) Using the fxSDK compiler path: ${AZUR_LIB}") + message("(Azur) Will take includes from: ${AZUR_INCLUDE}") +elseif(NOT "${AZUR_PATH}" STREQUAL "") + set(AZUR_LIB "${AZUR_PATH}/lib/libazur_${AZUR_PLATFORM}.a") + set(AZUR_INCLUDE "${AZUR_PATH}/include") + + if(NOT EXISTS "${AZUR_LIB}") + message(SEND_ERROR + "AZUR_PATH was set to ${AZUR_PATH}, but ${AZUR_LIB} does not exist") + endif() + + message("(Azur) Found AZUR_PATH_${AZUR_PLATFORM}: ${AZUR_LIB}") + message("(Azur) Will take includes from: ${AZUR_INCLUDE}") +else() + find_library(AZUR_PATH "azur_${AZUR_PLATFORM}") + if("${AZUR_PATH}" STREQUAL "AZUR_PATH-NOTFOUND") + message(SEND_ERROR + "Could not find libazur_${AZUR_PLATFORM}.a!\n" + "You can specify the installation path with the environment variable " + "AZUR_PATH, such as AZUR_PATH=/path/to/lib\n") + else() + set(AZUR_LIB "${AZUR_PATH}/lib/libazur_${AZUR_PLATFORM}.a") + set(AZUR_INCLUDE "${AZUR_PATH}/include") + + message("(Azur) Found Azur at: ${AZUR_LIB}") + message("(Azur) Will take includes from: ${AZUR_INCLUDE}") + endif() +endif() + +# 2. Find the library version and configuration + +if(NOT EXISTS "${AZUR_INCLUDE}/azur/config.h") + message(SEND_ERROR + "Could not find at ${AZUR_INCLUDE}/azur/config.h\n" + "Is libazur.a installed alongside the headers?") +endif() + +execute_process( + COMMAND sed "s/#define AZUR_VERSION \"\\([^\"]\\{1,\\}\\)\"/\\1/p; d" + "${AZUR_INCLUDE}/azur/config.h" + OUTPUT_VARIABLE AZUR_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) +message("(Azur) Library version found in header: ${AZUR_VERSION}") + +set(AZUR_3RDPARTY "") +set(AZUR_LIB_GL3W "${AZUR_PATH}/lib/libazur_${AZUR_PLATFORM}_gl3w.a") +set(AZUR_LIB_IMGUI "${AZUR_PATH}/lib/libazur_${AZUR_PLATFORM}_imgui.a") + +if(EXISTS "${AZUR_INCLUDE}/azur/gl3w" AND EXISTS "${AZUR_LIB_GL3W}") + list(APPEND AZUR_3RDPARTY "gl3w") + message("(Azur) Found gl3w at: ${AZUR_LIB_GL3W}") +endif() + +if(EXISTS "${AZUR_INCLUDE}/azur/imgui" AND EXISTS "${AZUR_LIB_IMGUI}") + list(APPEND AZUR_3RDPARTY "imgui") + message("(Azur) Found Dear ImGui at: ${AZUR_LIB_IMGUI}") +endif() + +if(EXISTS "${AZUR_INCLUDE}/azur/glm") + list(APPEND AZUR_3RDPARTY "glm") + message("(Azur) Found GLM at: ${AZUR_INCLUDE}/azur/glm") +endif() + +message("(Azur) Summary of external libraries found: ${AZUR_3RDPARTY}") + +# 3. Handle usual find_package() arguments and perform version check + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Azur + REQUIRED_VARS AZUR_LIB AZUR_INCLUDE + VERSION_VAR AZUR_VERSION) + +# 4. Find dependencies + +if(AZUR_PLATFORM STREQUAL linux) + find_package(PkgConfig REQUIRED) +endif() + +# 5. Generate targets + +if(Azur_FOUND) + if(NOT TARGET Azur::Azur) + add_library(Azur::Azur UNKNOWN IMPORTED) + endif() + + set_target_properties(Azur::Azur PROPERTIES + IMPORTED_LOCATION "${AZUR_LIB}" + INTERFACE_INCLUDE_DIRECTORIES "${AZUR_INCLUDE}" + INTERFACE_COMPILE_OPTIONS "-DAZUR_PLATFORM=${AZUR_PLATFORM}") + + if(AZUR_PLATFORM STREQUAL linux) + pkg_check_modules(sdl2 REQUIRED sdl2 IMPORTED_TARGET) + pkg_check_modules(sdl2_image REQUIRED SDL2_image IMPORTED_TARGET) + pkg_check_modules(opengl REQUIRED opengl IMPORTED_TARGET) + target_link_libraries(Azur::Azur INTERFACE + PkgConfig::sdl2_image PkgConfig::sdl2 PkgConfig::opengl -lm) + elseif(AZUR_PLATFORM STREQUAL emscripten) + set(PORTS -sUSE_SDL=2 -sUSE_SDL_IMAGE=2 -sSDL2_IMAGE_FORMATS=["png"]) + add_compile_options(${PORTS}) + add_link_options(${PORTS} -O3) + endif() +endif() + +if("gl3w" IN_LIST AZUR_3RDPARTY) + if(NOT TARGET Azur::gl3w) + add_library(Azur::gl3w UNKNOWN IMPORTED) + endif() + + set_target_properties(Azur::gl3w PROPERTIES + IMPORTED_LOCATION "${AZUR_LIB_GL3W}" + INTERFACE_INCLUDE_DIRECTORIES "${AZUR_INCLUDE}/azur/gl3w") + + if(AZUR_PLATFORM STREQUAL linux) + pkg_check_modules(glx REQUIRED glx IMPORTED_TARGET) + target_link_libraries(Azur::gl3w INTERFACE PkgConfig::glx -ldl) + target_link_libraries(Azur::Azur INTERFACE Azur::gl3w) + endif() +endif() + +if("glm" IN_LIST AZUR_3RDPARTY) + if(NOT TARGET Azur::GLM) + add_library(Azur::GLM INTERFACE IMPORTED) + endif() + + set_target_properties(Azur::GLM PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${AZUR_INCLUDE}/azur/glm") +endif() + +if("imgui" IN_LIST AZUR_3RDPARTY) + if(NOT TARGET Azur::ImGui) + add_library(Azur::ImGui UNKNOWN IMPORTED) + endif() + + set_target_properties(Azur::ImGui PROPERTIES + IMPORTED_LOCATION "${AZUR_LIB_IMGUI}" + INTERFACE_INCLUDE_DIRECTORIES + "${AZUR_INCLUDE}/azur/imgui;${AZUR_INCLUDE}/azur/imgui/backends" + INTERFACE_LINK_OPTIONS "-Wl,--gc-sections") + + if(AZUR_PLATFORM STREQUAL emscripten) + target_link_options(Azur::ImGui INTERFACE -sUSE_FREETYPE=1) + target_compile_definitions(Azur::ImGui INTERFACE -DIMGUI_ENABLE_FREETYPE) + target_include_directories(Azur::ImGui INTERFACE + "${AZUR_INCLUDE}/azur/imgui/misc/freetype") + else() + pkg_check_modules(freetype2 freetype2 IMPORTED_TARGET) + if(freetype2_FOUND) + target_link_libraries(Azur::ImGui INTERFACE PkgConfig::freetype2) + target_compile_definitions(Azur::ImGui INTERFACE -DIMGUI_ENABLE_FREETYPE) + endif() + endif() +endif() diff --git a/README.md b/README.md index e03fac1..b63905d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,15 @@ Azur is a game engine for the fx-CG series of graphing calculators that also sup Azur aims to implement real-world game engine mechanics such as ECS, animation and visual effects, physics, and state serialization. It doesn't try to be super fancy with them, but it does try to get the structure right. +Current status: +- [x] Build system supporting gint (fxSDK), Linux (SDL 2/OpenGL 3.3) and emscripten (SDL 2/OpenGL ES 2.0) +- [x] Platform-independent initialization/main loop/etc management. +- [x] Specialized fragmented-rendering pipeline for gint, providing high-performance graphics. +- [ ] Bare-bones fixed-point computation library. +- [ ] Experimental ECS system under design. + +Currently Azur is barely more than the native systems it uses (gint/OpenGL), with no solid unified APIs. It is mostly useful for writing high-performance gint games. + ## Projects in this repository The following are Azur libraries: @@ -20,30 +29,65 @@ The following external projects are Azur by some of Azur's features, and maintai ## Building +You *must* install into a different folder for each platform, as the headers would otherwise clash (particulary the auto-generated ``. The library names are different (eg. `libazur_emscripten.a`), but this is just to avoid confusing errors; the folders must still be different. + **Building for fx-CG** -Use the [fxSDK toolchain](https://gitea.planet-casio.com/Lephenixnoir/fxsdk). +Use the [fxSDK toolchain](https://gitea.planet-casio.com/Lephenixnoir/fxsdk). When building with the fxSDK, `AZUR_PLATFORM=gint` is assumed and the compiler's data folder is used to install the library. ``` -% fxsdk build-cg +% fxsdk build-cg install ``` **Building for Linux** +I recommend using a user-writable folder like `~/.local`. You can record the path in the environment variable `AZUR_PATH_linux`, in which case the find module for Azur will pick it up automatically regardless of whether CMake searches that particular folder by default. + ``` % cmake -B build-linux -DAZUR_PLATFORM=linux -DCMAKE_INSTALL_PREFIX="$HOME/.local" -% make -C build-linux +% make -C build-linux install -j$(nproc) + +# Later (eg. in ~/.profile): +% export AZUR_PATH_linux="$HOME/.local" ``` **Building for emscripten** -You will need the [emscripten toolchain](https://emscripten.org/). +You will need the [emscripten toolchain](https://emscripten.org/). I recommend to use a dedicated install folder since this is essentially a cross-compiling target. ``` -% emcmake cmake -B build-emscripten -D AZUR_PLATFORM=emscripten -% make -C build-emscripten +% emcmake cmake -B build-emscripten -D AZUR_PLATFORM=emscripten -DCMAKE_INSTALL_PREFIX="$HOME/.prefix-emscripten" +% make -C build-emscripten install -j$(nproc) + +# Later (eg. in ~/.profile): +% export AZUR_PATH_emscripten="$HOME/.prefix-emscripten" +``` + +## Using in an application + +Users building programs with Azur for Linux or emscripten should export the environment variables `AZUR_PATH_linux` or `AZUR_PATH_emscripten` as described above. The variable `AZUR_PLATFORM` should also be set on the command-line with `-D` during configuration, or hardcoded if the application only supports one target. + +The application's `CMakeLists.txt` can then do: + +```cmake +list(APPEND CMAKE_MODULE_PATH "$ENV{AZUR_PATH_${AZUR_PLATFORM}}/lib/cmake") +find_package(Azur 0.1 REQUIRED) +``` + +When using gint, only the `find_package()` is necessary. The fxSDK handles the rest. + +The find module then exports up to three targets that can be linked against: `Azur::Azur`, `Azur::GLM` and `Azur::ImGui` (gint only has the first). The result might look like this: + +```cmake +if(AZUR_PLATFORM STREQUAL gint) + target_link_libraries(myprogram Azur::Azur) +else() # Linux and emscripten + target_link_libraries(myprogram Azur::Azur Azur::GLM Azur::ImGui) +endif() ``` ## History note -Back in 2021 I made a single repository for this engine, along with other programs that I intended to write with it. At the time I didn't intend to distribute the engine in any serious fashion, but that changed after people expressed interest in playing with [After Burner](https://www.planet-casio.com/Fr/programmes/programme4238-1-after-burner-lephenixnoir-jeux-add-ins.html). I split the repository in May 2022 with `git filter-branch`, and edited the history so old commits can still be built, but don't expect that to work out-of-the-box. +Back in 2021 I made a single repository for this engine, along with other programs that I intended to write with it. At the time I didn't intend to distribute the engine in any serious fashion, but that changed after people expressed interest in playing with [After Burner](https://www.planet-casio.com/Fr/programmes/programme4238-1-after-burner-lephenixnoir-jeux-add-ins.html). + +I split the original repository in May 2022 with `git filter-branch`, extracting Azur-related contents to this repository. I edited the history so that old commits can still be built, but mostly for the sake of preserving history; don't expect to be able to use these early commits out-of-the-box. diff --git a/azur/CMakeLists.txt b/azur/CMakeLists.txt index 168445c..41c0b42 100644 --- a/azur/CMakeLists.txt +++ b/azur/CMakeLists.txt @@ -1,5 +1,9 @@ -cmake_minimum_required(VERSION 3.15) -project(Azur VERSION 0.1 LANGUAGES CXX C ASM) +#-----------------------------------------------------------------------------# +# ," /\ ", Azur: A game engine for CASIO fx-CG and PC # +# | _/__\_ | Designed by Lephe' and the Planète Casio community. # +# "._`\/'_." License: MIT # +#-----------------------------------------------------------------------------# +# Main library build system configure_file(include/azur/config.h.in include/azur/config.h) @@ -11,12 +15,24 @@ set(ASSETS) if(AZUR_TOOLKIT_SDL AND AZUR_GRAPHICS_OPENGL) list(APPEND SOURCES src/sdl_opengl/init.c - src/sdl_opengl/util.c) + src/sdl_opengl/util.c + "${CMAKE_CURRENT_BINARY_DIR}/src/glsl.c") + list(APPEND ASSETS glsl/vs_prelude_gles2.glsl glsl/fs_prelude_gles2.glsl + glsl/vs_prelude_gl3.glsl + glsl/fs_prelude_gl3.glsl glsl/vs_tex2d.glsl glsl/fs_tex2d.glsl) + + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/src/glsl.c" + COMMAND mkdir -p "${CMAKE_CURRENT_BINARY_DIR}/src" + COMMAND python gen_glsl.py "${CMAKE_CURRENT_BINARY_DIR}/src/glsl.c" + ${ASSETS} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Generating a C file with prebuilt shaders" + DEPENDS gen_glsl.py ${ASSETS}) endif() # gint rendering @@ -53,41 +69,25 @@ endif() add_library(azur STATIC ${SOURCES}) -# File preloading on emscripten -if(AZUR_PLATFORM_EMSCRIPTEN) - set_target_properties(azur PROPERTIES - INTERFACE_LINK_OPTIONS - "SHELL:--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/glsl@/azur/glsl" - LINK_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/glsl") +set_target_properties(azur PROPERTIES OUTPUT_NAME "azur_${AZUR_PLATFORM}") - # Add assets to link dependencies - set(ASSETS_ABSOLUTE) - foreach(ASSET IN LISTS ASSETS) - list(APPEND ASSETS_ABSOLUTE "${CMAKE_CURRENT_SOURCE_DIR}/${ASSET}") - endforeach() - set_target_properties(azur PROPERTIES LINK_DEPENDS "${ASSETS_ABSOLUTE}") -endif() - -# Use ImGui's integrated GL3W loader (which we build separately) +# Link with GL3W to load the OpenGL 3.3 core profile if(AZUR_GRAPHICS_OPENGL_3_3) target_link_libraries(azur PUBLIC gl3w) endif() -target_include_directories(azur - PUBLIC "${PROJECT_SOURCE_DIR}/include" - PUBLIC "${PROJECT_BINARY_DIR}/include" -) +target_include_directories(azur PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_BINARY_DIR}/include") #--- # Install #--- -# Library file: libazur.a +# Library file: libazur_*.a install(TARGETS azur DESTINATION ${LIBDIR}) # Headers: azur/*.h install(DIRECTORY include/ DESTINATION ${INCDIR} FILES_MATCHING PATTERN "*.h") # Generated header: azur/config.h -install(FILES "${PROJECT_BINARY_DIR}/include/azur/config.h" +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/azur/config.h" DESTINATION ${INCDIR}/azur) -# CMake module loading the library: TODO -# install(FILES cmake/FindAzur.cmake DESTINATION "${FXSDK_CMAKE_MODULE_PATH}") diff --git a/azur/gen_glsl.py b/azur/gen_glsl.py new file mode 100644 index 0000000..b1cecdb --- /dev/null +++ b/azur/gen_glsl.py @@ -0,0 +1,34 @@ +#-----------------------------------------------------------------------------# +# ," /\ ", Azur: A game engine for CASIO fx-CG and PC # +# | _/__\_ | Designed by Lephe' and the Planète Casio community. # +# "._`\/'_." License: MIT # +#-----------------------------------------------------------------------------# +# gen_glsl.py: Trivial utility to embed GLSL files into the library +# +# Azur comes with a set of default shaders, but installing GLSL files to be +# loaded at runtime comes with a number of install/distribution constraints. +# For simplicity, we embed the files into the library by generating a C file +# with a bunch of strings and compiling it. +#--- + +import sys +import os + +if len(sys.argv) < 2 or "-h" in sys.argv or "--help" in sys.argv: + print(f"usage: {sys.argv[0]} ") + +def encode(string): + # Escape characters that have special meaning in C + string = string.replace("\\", "\\\\").replace("\"", "\\\"") + # Enforce proper newlines + return "\n".join(f'"{s}\\n"' for s in string.split("\n")) + +inputs = [] +for input_file in sys.argv[2:]: + with open(input_file, "r") as fp: + name = os.path.splitext(os.path.basename(input_file))[0] + inputs.append((name, fp.read())) + +with open(sys.argv[1], "w") as fp: + for (name, data) in inputs: + fp.write(f"char const *azur_glsl__{name} =\n{encode(data)};\n\n") diff --git a/azur/include/azur/config.h.in b/azur/include/azur/config.h.in index 5f27705..76b2731 100644 --- a/azur/include/azur/config.h.in +++ b/azur/include/azur/config.h.in @@ -4,6 +4,7 @@ #pragma once +#define AZUR_VERSION "@Azur_VERSION@" #define AZUR_VERSION_MAJOR @Azur_VERSION_MAJOR@ #define AZUR_VERSION_MINOR @Azur_VERSION_MINOR@ diff --git a/azur/include/azur/sdl_opengl/gl.h b/azur/include/azur/sdl_opengl/gl.h index 75a53ac..0985690 100644 --- a/azur/include/azur/sdl_opengl/gl.h +++ b/azur/include/azur/sdl_opengl/gl.h @@ -7,7 +7,7 @@ AZUR_BEGIN_DECLS #ifdef AZUR_GRAPHICS_OPENGL_3_3 -# include "GL/gl3w.h" +# include # include #endif /* OpenGL 3.3 */ @@ -44,15 +44,22 @@ GLuint azgl_compile_shader_source(GLenum type, char const *code, ssize_t size); it, and returns the program ID (0 if link fails). */ GLuint azgl_link_program(GLuint shader_1, ... /* 0-terminated */); -/* azgl_load_program(): Load a program from shader source files. +/* azgl_load_program_file(): Load a program from shader source files. This function runs both azgl_compile_shader_file() and azgl_link_program() for all specified files. Each argument should be a pair with a shader type and a file name, with a final 0. Returns the program ID, or 0 if any loading/compilation/link step fails. */ -GLuint azgl_load_program( +GLuint azgl_load_program_file( GLenum type_1, char const *path_1, ... /* Pairs repeat until 0-terminated */); +/* azgl_load_program_source(): Load a program from shader source strings. + + Like azgl_load_program_file(), but takes code directly as input. */ +GLuint azgl_load_program_source( + GLenum type_1, char const *code_1, + ... /* Pairs repeat until 0-terminated */); + AZUR_END_DECLS diff --git a/azur/src/log.c b/azur/src/log.c index 35093ca..b49ccb3 100644 --- a/azur/src/log.c +++ b/azur/src/log.c @@ -4,7 +4,7 @@ #ifdef AZUR_DEBUG static int _level = AZLOG_DEBUG; #else -static int _level = AZLOG_ERROR; +static int _level = AZLOG_INFO; #endif #ifdef AZUR_TERMINAL_ANSI @@ -39,6 +39,8 @@ void azlog_write(int level, char const *file, int line, char const *func, fprintf(stderr, CYAN "%s:%d: " STOP YELLOW "%s: " STOP, file, line, func); #else + (void)file; + (void)line; fprintf(stderr, "%s: ", func); #endif diff --git a/azur/src/sdl_opengl/init.c b/azur/src/sdl_opengl/init.c index b054fb3..594b9e3 100644 --- a/azur/src/sdl_opengl/init.c +++ b/azur/src/sdl_opengl/init.c @@ -10,6 +10,35 @@ static SDL_GLContext glcontext = NULL; static void main_loop_quit(void); +#ifdef AZUR_PLATFORM_EMSCRIPTEN +#include + +static EM_BOOL fullscreen_callback(int ev, void const *_, void *window0) +{ + double w, h; + emscripten_get_element_css_size("canvas", &w, &h); + + SDL_Window *window = window0; + SDL_SetWindowSize(window, (int)w, (int)h); + + azlog(INFO, "Canvas size updated: now %dx%d", (int)w, (int)h); + return EM_TRUE; +} + +static void enter_fullscreen(SDL_Window *window) +{ + EmscriptenFullscreenStrategy strategy = { + .scaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF, + .filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT, + .canvasResizedCallback = fullscreen_callback, + .canvasResizedCallbackUserData = window, + }; + emscripten_enter_soft_fullscreen("canvas", &strategy); + azlog(INFO, "Entered fullscreen! (info)"); + azlog(ERROR, "Entered fullscreen! (error)"); +} +#endif /* AZUR_PLATFORM_EMSCRIPTEN */ + int azur_init(char const *title, int window_width, int window_height) { int rc = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); @@ -72,6 +101,10 @@ int azur_init(char const *title, int window_width, int window_height) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#ifdef AZUR_PLATFORM_EMSCRIPTEN + enter_fullscreen(window); +#endif + return 0; } diff --git a/azur/src/sdl_opengl/util.c b/azur/src/sdl_opengl/util.c index c7044b0..88d1d3f 100644 --- a/azur/src/sdl_opengl/util.c +++ b/azur/src/sdl_opengl/util.c @@ -58,23 +58,27 @@ static GLuint azgl_compile_shader(GLenum type, char const *code, ssize_t size, char const *origin) { /* Shader prelude; this gives shader version, some macro definitions and - some "selctors" which altogether give some degree of compatibility + some "selectors" which altogether provide some degree of compatibility between GLSL and GLSL ES. */ static char const *vs_prelude = NULL; static char const *fs_prelude = NULL; if(!vs_prelude) { #if defined AZUR_GRAPHICS_OPENGL_ES_2_0 - vs_prelude = load_file("azur/glsl/vs_prelude_gles2.glsl", NULL); + extern char const *azur_glsl__vs_prelude_gles2; + vs_prelude = azur_glsl__vs_prelude_gles2; #elif defined AZUR_GRAPHICS_OPENGL_3_3 - vs_prelude = load_file("azur/glsl/vs_prelude_gl3.glsl", NULL); + extern char const *azur_glsl__vs_prelude_gl3; + vs_prelude = azur_glsl__vs_prelude_gl3; #endif } if(!fs_prelude) { #if defined AZUR_GRAPHICS_OPENGL_ES_2_0 - fs_prelude = load_file("azur/glsl/fs_prelude_gles2.glsl", NULL); + extern char const *azur_glsl__fs_prelude_gles2; + fs_prelude = azur_glsl__fs_prelude_gles2; #elif defined AZUR_GRAPHICS_OPENGL_3_3 - fs_prelude = load_file("azur/glsl/fs_prelude_gl3.glsl", NULL); + extern char const *azur_glsl__fs_prelude_gl3; + fs_prelude = azur_glsl__fs_prelude_gl3; #endif } @@ -83,7 +87,7 @@ static GLuint azgl_compile_shader(GLenum type, char const *code, ssize_t size, prelude = vs_prelude; else if(type == GL_FRAGMENT_SHADER) prelude = fs_prelude; - else + if(prelude == NULL) prelude = ""; GLuint id = glCreateShader(type); @@ -95,8 +99,11 @@ static GLuint azgl_compile_shader(GLenum type, char const *code, ssize_t size, GLint rc = GL_FALSE; GLsizei log_length = 0; + if(size < 0) + size = (int)strlen(code); + char const *string_array[] = { prelude, code }; - GLint size_array[] = { strlen(prelude), size ? size : (int)strlen(code) }; + GLint size_array[] = { strlen(prelude), size }; azlog(INFO, "Compiling shader: %s\n", origin); glShaderSource(id, 2, string_array, size_array); @@ -135,7 +142,7 @@ GLuint azgl_compile_shader_file(GLenum type, char const *path) return id; } -GLuint azgl_compiler_shader_source(GLenum type, char const *code, ssize_t size) +GLuint azgl_compile_shader_source(GLenum type, char const *code, ssize_t size) { return azgl_compile_shader(type, code, size, ""); } @@ -199,21 +206,20 @@ GLuint azgl_link_program(GLuint shader_1, ... /* 0-terminated */) return azgl_link(shaders, count); } -GLuint azgl_load_program(GLenum type, char const *path, ...) +static GLuint azgl_load_program(bool is_file, GLenum type, char const *input, + va_list *args) { - va_list args; - va_start(args, path); - GLuint shaders[32]; int count = 0; do { - shaders[count++] = azgl_compile_shader_file(type, path); - type = va_arg(args, GLenum); - path = va_arg(args, char const *); + shaders[count++] = is_file + ? azgl_compile_shader_file(type, input) + : azgl_compile_shader_source(type, input, -1); + type = va_arg(*args, GLenum); + input = va_arg(*args, char const *); } while(count < 32 && type != 0); - va_end(args); GLuint prog = azgl_link(shaders, count); @@ -222,3 +228,21 @@ GLuint azgl_load_program(GLenum type, char const *path, ...) return prog; } + +GLuint azgl_load_program_file(GLenum type, char const *path, ...) +{ + va_list args; + va_start(args, path); + GLuint prog = azgl_load_program(true, type, path, &args); + va_end(args); + return prog; +} + +GLuint azgl_load_program_source(GLenum type, char const *code, ...) +{ + va_list args; + va_start(args, code); + GLuint prog = azgl_load_program(false, type, code, &args); + va_end(args); + return prog; +} diff --git a/libnum/CMakeLists.txt b/libnum/CMakeLists.txt index 1ed21ab..7fb42e5 100644 --- a/libnum/CMakeLists.txt +++ b/libnum/CMakeLists.txt @@ -1,16 +1,14 @@ -cmake_minimum_required(VERSION 3.15) -project(libnum VERSION 0.1) +#-----------------------------------------------------------------------------# +# ," /\ ", Azur: A game engine for CASIO fx-CG and PC # +# | _/__\_ | Designed by Lephe' and the Planète Casio community. # +# "._`\/'_." License: MIT # +#-----------------------------------------------------------------------------# +# libnum build system -# Most of the code is in the headers -add_library(num STATIC src/static_checks.cpp test.cpp) +add_library(num STATIC + src/static_checks.cpp) -target_include_directories(num - PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_compile_options(num PRIVATE -std=c++17) - -#--- -# Install -#--- +target_include_directories(num PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include") # Library file: libnum.a install(TARGETS num DESTINATION ${LIBDIR})