Compare commits

...

14 commits

Author SHA1 Message Date
Cayleb-Ordo
c62f5808ca Add CMake Configuration for ActorEditor
Name the project AtlasMisc as the atlas Object is shared.

Not working as of 04.06.2026:
- Linking to wxWidgets find_package target
  - Terrain.obj : `error LNK2019: Verweis auf nicht aufgel├Âstes externes Symbol ""int const wxEVT_NULL" (?wxEVT_NULL@@3HB)" in Funktion ""void __cdecl dynamic initializer for 'private: static struct wxEventTableEntry const * const TerrainSidebar::sm_eventTableEntries''(void)" (??__E?sm_eventTableEntries@TerrainSidebar@@0QBUwxEventTableEntry@@B@@YAXXZ)".`

Working:
- Using find_package extra variables to find most of the windows ext. libs
- excluding SDL2 and Boost, which use the custom find_prebuild_library function
2026-08-06 12:35:30 +02:00
Cayleb-Ordo
eb793b60c2 Add the doxygen cmake file to the CMake Project
Make the docs its own target instead of a project. Dont add the
new docs target to ALL. Add an option to disable generating the
docs.
Update doxygen_awesome to v2.4.2.
Update README to reflect new changes.
2026-08-06 12:35:30 +02:00
Cayleb-Ordo
dd2ae207e5 Add a module to fetch and setup Windows prebuild libraries
This module downloads the given svn revision based on the current
architecture selected. It also sets up the `CMAKE_PREFIX_PATH`.
Add new option to disable fetching, which assumes that the libraries
are already in the correct folders.
2026-08-06 12:35:30 +02:00
Cayleb-Ordo
0af738e0ec Add Root CMakeLists.txt and custom cmake modules
CMake is de facto the industrie standard for building C/C++ Code.
It is cross platform, supports presets and packaging for
Linux Distributions can be made with CPack. This also eliminates
the dependency to build and patch premake. Furthermore a lot of
IDE's are supported.

Add a BuildFlags CMake module with an INTERFACE library encapsulating
relevant build Flags and definitions. To provide support for multi
configuration generators use generator expressions as much as possible.
Add a (currently) empty 0ad-Functions module for later usage.
2026-08-06 12:35:30 +02:00
Vladislav Belov
c4e7364802
Removes unused BuildColor4ub from ModelRenderer
We don't need to calculate shading on CPU since we always use shaders.

Refs: a9c27b412b
2026-08-06 11:32:02 +02:00
Vladislav Belov
867bdf318b
Fixes missing material reference in ModelRenderer
Missed in 18a16aa135
2026-08-06 10:31:16 +02:00
Vladislav Belov
e64a138f92
Fixes outdated state on disabling GPU skinning 2026-08-04 23:06:12 +02:00
Vladislav Belov
4a7b7e7df1
Removes smart pointers from ModelRenderer
We don't need to use pointers because we know lifetimes of all
renderers. And its list statically defined. A new renderer should follow
DOD and use a separate submission list with a separate inplace renderer.
2026-08-04 23:06:10 +02:00
Vladislav Belov
fa90ddc8b6
Refactors ModelRenderer and makes it closer to DOD
Separates submitted models and moder renderer and makes relations
explicit. Now it's clear that we don't need separate ModelRenderer and
ModelVertexRenderer.
2026-08-04 23:06:09 +02:00
Vladislav Belov
764a420797
Merges ModelRenderer and ShaderModelRenderer
We use only shaders to render models so we don't need a separate class.

BatchModelRenderer was renamed in 6bc33fe8bd.
m_Renderer became unused in 0346ba1b18.
2026-08-04 23:06:07 +02:00
Vladislav Belov
8a2bb10827
Renames ShaderModelRenderer instances 2026-08-04 23:06:06 +02:00
Vladislav Belov
af9d102126
Removes legacy logic of reused ModelRendererPtr
It became unused in 4a69e9117e.
2026-08-04 23:06:04 +02:00
Ralph Sennhauser
822092fcb4
Fix set camera tooltip in Atlas player section
Some checks failed
checkrefs / lfscheck (push) Has been cancelled
checkrefs / checkrefs (push) Has been cancelled
lint / cppcheck (push) Has been cancelled
lint / copyright (push) Has been cancelled
lint / jenkinsfiles (push) Has been cancelled
pre-commit / build (push) Has been cancelled
Refs: fe192fe58f
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
2026-08-04 17:22:21 +02:00
Ralph Sennhauser
6e79dc2f70
Use dynamic events for Cinema Section
Replace static events with dynamic events and name delete path function
more aptly.

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
2026-08-04 17:04:22 +02:00
53 changed files with 1347 additions and 524 deletions

157
CMakeLists.txt Normal file
View file

@ -0,0 +1,157 @@
cmake_minimum_required(VERSION 3.25.1...4.0.0)
project(0ad VERSION 0.29.0)
# Available Options
option(android "Use non-working Android cross-compiling mode")
option(build-docs "Enable building the doxygen documentation(requires Network access)")
option(coverage "Enable code coverage data collection (GCC only)")
option(gles "Use non-working OpenGL ES 2.0 mode")
option(jenkins-tests "Configure CxxTest to use the XmlPrinter runner which produces Jenkins-compatible output")
option(minimal-flags "Only set compiler/linker flags that are really needed. Has no effect on Windows builds")
option(sanitize-address "Enable ASAN if available")
option(sanitize-thread "Enable TSAN if available")
option(sanitize-undefined-behaviour "Enable UBSAN if available")
option(with-system-cxxtest "Search standard paths for cxxtest, instead of using bundled copy")
option(with-lto "Enable Link Time Optimization (LTO)")
option(with-system-mozjs "Search standard paths for libmozjs115, instead of using bundled copy")
option(with-system-nvtt "Search standard paths for nvidia-texture-tools library, instead of using bundled copy")
option(with-valgrind "Enable Valgrind support (non-Windows only)")
option(without-audio "Disable use of OpenAL/Ogg/Vorbis APIs")
option(without-atlas "Disable Atlas scenario/map editor and ActorEditor")
option(without-dap-interface "Disable Dap interface project")
option(without-lobby "Disable the use of gloox and the multiplayer lobby")
option(without-miniupnpc "Disable use of miniupnpc for port forwarding")
option(without-nvtt "Disable use of NVTT")
option(without-pch "Disable generation and usage of precompiled headers")
option(without-tests "Disable generation of test projects")
# Windows specific options
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
option(fetch-prebuild-libs "Fetch prebuild libraries from SVN. Defaults to ON." ON)
endif()
# OS X specific options
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
option(macosx-version-min "Set minimum required version of the OS X API, the build will possibly fail if an older SDK is used, while newer API functions will be weakly linked (i.e. resolved at runtime)")
option(sysroot "Set compiler system root path, used for building against a non-system SDK. For example /usr/local becomes SYSROOT/user/local")
endif()
# Set the default build type if not specified (Only for single configuration generators)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
# Install options
set(bindir "" CACHE STRING "Directory for executables (typically '/usr/games'); default is to be relocatable")
set(datadir "" CACHE STRING "Directory for data files (typically '/usr/share/games/0ad'); default is ../data/ relative to executable")
set(libdir "" CACHE STRING "Directory for libraries (typically '/usr/lib/games/0ad'); default is ./ relative to executable")
# +++++++++++++++++++++ General Setup ++++++++++++++++++++
# Default Cache variables
# Append to the Modulepath. Allows to make custom cmake modules.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# Set default Arch
set(ARCH "x86" CACHE STRING "CPU Architecture. Possible values are arm, aarch64, x86, amd64, e2k, ppc64, loong64, riscv64")
set(MACOS_ARCH "x86_64" CACHE STRING "Mac OS specific Architecture. Possible values are arm64 and x86_64")
option(link_execinfo "")
option(mozjs_is_debug_build "")
# Detect CPU architecture (simplistic). The user can target an architecture by setting '-DARCH=arch', but the game still selects some know value.
if(android)
set(ARCH "arm" CACHE STRING "CPU Architecture. Possible values are arm, aarch64, x86, amd64, e2k, ppc64, loong64, riscv64" FORCE)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
if(NOT CMAKE_VS_PLATFORM_NAME)
if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64" OR ENV{PROCESSOR_ARCHITEW6432} STREQUAL "AMD64")
set(ARCH "amd64" CACHE STRING "CPU Architecture. Possible values are arm, aarch64, x86, amd64, e2k, ppc64, loong64, riscv64" FORCE)
endif()
else()
if(CMAKE_VS_PLATFORM_NAME MATCHES "x64")
set(ARCH "amd64" CACHE STRING "CPU Architecture. Possible values are arm, aarch64, x86, amd64, e2k, ppc64, loong64, riscv64" FORCE)
endif()
endif()
else()
# could be parsed from the same command as premakes version
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "(x86_64|x64)")
set(MACOS_ARCH "x86_64" CACHE STRING "Mac OS specific Architecture. Possible values are arm64 and x86_64" FORCE)
elseif(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
set(MACOS_ARCH "arm64" CACHE STRING "Mac OS specific Architecture. Possible values are arm64 and x86_64" FORCE)
endif()
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "(x86_64|x64)")
set(ARCH "amd64" CACHE STRING "CPU Architecture. Possible values are arm, aarch64, x86, amd64, e2k, ppc64, loong64, riscv64" FORCE)
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "(aarch64|aarch64_be)")
set(ARCH "aarch64" CACHE STRING "CPU Architecture. Possible values are arm, aarch64, x86, amd64, e2k, ppc64, loong64, riscv64" FORCE)
else()
message(WARNING "Cannot determine architecture from GCC, assuming x86")
endif()
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
if(ARCH MATCHES "amd64")
set(0AD_EXT_LIBDIR ${CMAKE_SOURCE_DIR}/libraries/win64 CACHE STRING "Extern libraries directory of 0ad. Can be referenced in other CMakeLists.txt files.")
else()
set(0AD_EXT_LIBDIR ${CMAKE_SOURCE_DIR}/libraries/win32 CACHE STRING "Extern libraries directory of 0ad. Can be referenced in other CMakeLists.txt files.")
endif()
endif()
# On Windows check if wxWidgets is available, if not disable atlas and emit warning. This is because there are currently no prebuilt binaries provided.
if(NOT without-atlas AND CMAKE_SYSTEM_NAME STREQUAL "Windows")
if(NOT EXISTS "${0AD_EXT_LIBDIR}/wxwidgets/include/wx/wx.h")
message(STATUS "wxWidgets not found, disabling atlas")
set(without-atlas ON CACHE BOOL "Disable Atlas scenario/map editor and ActorEditor" FORCE)
endif()
endif()
# Test whether we need to link libexecinfo. This is mostly the case on musl systems, as well as on BSD systems : only glibc provides the
# backtrace symbols we require in the libc, for other libcs we use the libexecinfo library.
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
set(link_execinfo ON CACHE BOOL "" FORCE)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
include(CheckCSourceCompiles)
file(READ ${CMAKE_SOURCE_DIR}/build/premake/tests/execinfo.c content)
check_c_source_compiles([[${content}]] LINK_EXECINFO)
if(NOT LINK_EXECINFO)
set(link_execinfo ON CACHE BOOL "" FORCE)
else()
set(link_execinfo OFF CACHE BOOL "" FORCE)
endif()
unset(LINK_EXECINFO)
unset(content)
endif()
# Test whether system mozjs is built with --enable-debug. The pc file doesn't specify the required -DDEBUG needed in that case
# Currently only working on bash shell!
if(with-system-mozjs)
execute_process(
COMMAND bash "-c" "${CMAKE_C_COMPILER} $(pkg-config mozjs-128 --cflags) ${CMAKE_SOURCE_DIR}/build/premake/tests/mozdebug.c -o /dev/null"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE errorCode
OUTPUT_QUIET
ERROR_QUIET
)
if(NOT errorCode EQUAL 0)
set(mozjs_is_debug_build ON CACHE BOOL "" FORCE)
else()
set(mozjs_is_debug_build OFF CACHE BOOL "" FORCE)
endif()
endif()
# Include the BuildFlags target only once after all setup is finished
include(0ad-BuildFlags)
# +++++++++++++++++++++ Windows specific ++++++++++++++++++++
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
include(SetupWindowsLibs)
endif()
# Add subprojects
if(NOT without-atlas)
add_subdirectory(${CMAKE_SOURCE_DIR}/source/tools/atlas/)
endif()
# Add doxygen target
if(build-docs)
add_subdirectory(${CMAKE_SOURCE_DIR}/docs/doxygen)
endif()

260
cmake/0ad-BuildFlags.cmake Normal file
View file

@ -0,0 +1,260 @@
cmake_minimum_required(VERSION 3.25.1...4.0.0)
# Add an interface library with common set of build/linker flags and definitions.
set(BUILD_FLAGS_TARGET BuildFlags)
add_library(${BUILD_FLAGS_TARGET} INTERFACE)
# Enable and require C++20 standard.
target_compile_features(${BUILD_FLAGS_TARGET} INTERFACE cxx_std_20)
set_target_properties(${BUILD_FLAGS_TARGET}
PROPERTIES
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
)
# Settings for build types
if(with-lto)
include(CheckIPOSupported)
check_ipo_supported(RESULT lto_supported OUTPUT lto_supported_error)
if(lto_supported)
set_target_properties(${BUILD_FLAGS_TARGET}
PROPERTIES
INTERPROCEDURAL_OPTIMIZATION TRUE
)
else()
message(WARNING "IPO / LTO not supported: <${lto_supported_error}>")
endif()
unset(lto_supported)
unset(lto_supported_error)
endif()
target_compile_definitions(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CONFIG:Release>:NDEBUG>
$<$<CONFIG:Release>:CONFIG_FINAL=1>
$<$<CONFIG:Debug>:DEBUG>
# Game Configuration Defines
$<$<BOOL:${mozjs_is_debug_build}>:DEBUG>
$<$<BOOL:${gles}>:CONFIG2_DAP_INTERFACE=0>
$<$<BOOL:${without-audio}>:CONFIG2_GLES=1>
$<$<BOOL:${without-nvtt}>:CONFIG2_NVTT=0>
$<$<BOOL:${without-lobby}>:CONFIG2_LOBBY=0>
$<$<BOOL:${without-miniupnpc}>:CONFIG2_MINIUPNPC=0>
$<$<BOOL:${without-dap-interface}>:CONFIG2_DAP_INTERFACE=0>
)
# Address Sanitizer Settings
if(sanitize-address)
target_compile_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=address)
target_link_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=address)
endif()
if(sanitize-thread)
target_compile_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=thread)
target_link_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=thread)
endif()
if(sanitize-undefined-behaviour)
target_compile_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=undefined)
target_link_options(${BUILD_FLAGS_TARGET} INTERFACE -fsanitize=undefined)
endif()
# hide warnings caused by library includes (Nothing to do for gcc/clang)
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:MSVC>:/external:W0>
)
# various platform-specific build flags
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:MSVC>:/MP>
# Since KB4088875 Windows 7 has a soft requirement for SSE2.
# Windows 8+ and Firefox ESR52 make it hard requirement.
# Finally since VS2012 it's enabled implicitely when not set.
$<$<CXX_COMPILER_ID:MSVC>:/arch:SSE2>
# use native wchar_t type (not typedef to unsigned short)
$<$<CXX_COMPILER_ID:MSVC>:/Zc:wchar_t>
$<$<CXX_COMPILER_ID:MSVC>:/utf-8>
# SpiderMonkey only supports building with MSVC on a best-effort basis,
# and the traditional MSVC preprocessor is incompatible with some headers.
# Use the modern, standard-compliant MSVC preprocessor instead.
$<$<CXX_COMPILER_ID:MSVC>:/Zc:preprocessor>
# enable most of the standard warnings
$<$<CXX_COMPILER_ID:MSVC>:/W4>
# FIXME: conversion warnings, should add -Wconversion to gcc and clang flags as well
$<$<CXX_COMPILER_ID:MSVC>:/wd4267>
$<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:MSVC>>:/O2>
)
# disable LNK4221 warning, to avoid spending energy ordering projects in linker invocations
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
"/ignore:4221"
)
# mozilla 115 linked list destructor in debug build
target_compile_definitions(${BUILD_FLAGS_TARGET} INTERFACE "__PRETTY_FUNCTION__=__FUNCSIG__")
# disable Windows debug heap, since it makes malloc/free hugely slower when running inside a debugger
set_target_properties(${BUILD_FLAGS_TARGET}
PROPERTIES
VS_DEBUGGER_ENVIRONMENT "_NO_DEBUG_HEAP=1"
)
elseif(UNIX)
if(NOT minimal-flags)
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
# most of the standard warnings
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wall>
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wextra>
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wpedantic>
# $<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wconversion> # FIXME: should seriously consider fixing so this warning can be enabled.
# add some other useful warnings that need to be enabled explicitly
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wunused-parameter> # (useful for finding some multiply-included header files)
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wredundant-decls>
# $<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wformat=2> # (useful sometimes, but a bit noisy, so skip it by default)
# $<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wcast-qual> # (useful for checking const-correctness, but a bit noisy, so skip it by default)
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wnon-virtual-dtor> # (sometimes noisy but finds real bugs)
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wundef> # (useful for finding macro name typos)
# disable some warnings that currently trigger
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wno-missing-field-initializers> # (this is common in external headers we can't fix)
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wno-reorder> # order of initialization list in constructors (lots of noise)
# enable security features (stack checking etc) that shouldn't have a significant effect on performance and can catch bugs
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fstack-protector-strong>
# always enable strict aliasing (useful in debug builds because of the warnings)
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fstrict-aliasing>
# don't omit frame pointers (for now), because performance will be impacted negatively by the way this breaks profilers more than it will be impacted positively by the optimisation
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fno-omit-frame-pointer>
# FORTIFY_SOURCE needs optimizations to be enabled
$<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:Clang,AppleClang,GNU>>:-U_FORTIFY_SOURCE> # (avoid redefinition warning if already defined)
$<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:Clang,AppleClang,GNU>>:-D_FORTIFY_SOURCE=2>
)
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<PLATFORM_ID:Darwin>:-multiply_defined>
$<$<PLATFORM_ID:Darwin>:suppress>
)
if(NOT without-pch)
# do something (?) so that ccache can handle compilation with PCH enabled (ccache 3.1+ also requires CCACHE_SLOPPINESS=time_macros for this to work)
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fpch-preprocess>
)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_NAME MATCHES ".*BSD*")
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fPIC>
)
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-Wl,--no-undefined"
"-Wl,--as-needed"
"-Wl,-z,relro"
)
endif()
if(ARCH STREQUAL "x86")
# To support intrinsics like __sync_bool_compare_and_swap on x86 we need to set -march to something that supports them (i686).
# We use pentium3 to also enable other features like mmx and sse, while tuning for generic to have good performance on every supported CPU.
# Note that all these features are already supported on amd64.
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-march=pentium3>
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-mtune=generic>
# This allows x86 operating systems to handle the 2GB+ INTERFACE mod.
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-mtune=generic-D_FILE_OFFSET_BITS=64>
)
endif()
if(ARCH STREQUAL "arm")
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
# disable warnings about va_list ABI change and use compile-time flags for futher configuration.
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-Wno-psabi>
# Android uses softfp, so we should too.
$<$<AND:$<CXX_COMPILER_ID:Clang,AppleClang,GNU>,$<BOOL:${android}>>:-mfloat-abi=softfp>
)
endif()
endif()
if(coverage)
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-fprofile-arcs>
$<$<CXX_COMPILER_ID:Clang,AppleClang,GNU>:-ftest-coverage>
)
target_link_libraries(${BUILD_FLAGS_TARGET} gcov)
endif()
# MacOS 10.12 only supports intel processors with SSE 4.1, so enable that.
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND ARCH STREQUAL "amd64")
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-msse4.1"
)
endif()
# Check if SDK path should be used
if(sysroot)
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-isysroot ${sysroot}"
)
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-Wl,-syslibroot, ${sysroot}"
)
endif()
# On OS X, sometimes we need to specify the minimum API version to use
if(macosx-version-min)
# clang and llvm-gcc look at mmacosx-version-min to determine link target and CRT version, and use it to set the macosx_version_min linker flag
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-mmacosx-version-min=${macosx-version-min}"
)
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
"-mmacosx-version-min=${macosx-version-min}"
)
endif()
# Only libc++ is supported on MacOS
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
-stdlib=libc++
)
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
-stdlib=libc++
)
endif()
# Hide symbols in dynamic shared objects by default, for efficiency and for equivalence with Windows
# - they should be exported explicitly with __attribute__ ((visibility ("default")))
target_compile_options(${BUILD_FLAGS_TARGET}
INTERFACE
-fvisibility=hidden
)
target_compile_definitions(${BUILD_FLAGS_TARGET}
INTERFACE
$<$<BOOL:${bindir}>:INSTALLED_BINDIR=${bindir}>
$<$<BOOL:${datadir}>:INSTALLED_DATADIR=${bindir}>
$<$<BOOL:${libdir}>:INSTALLED_LIBDIR=${bindir}>
)
# RPATH Settings. Must be done through INSTALL_RPATH on target/global base.
if(CMAKE_SYSTEM_NAME MATCHES ".*BSD*")
# On FreeBSD we need to allow use of $ORIGIN
target_link_options(${BUILD_FLAGS_TARGET}
INTERFACE
-Wl,-z,origin
)
endif()
endif()

47
cmake/0ad-Functions.cmake Normal file
View file

@ -0,0 +1,47 @@
cmake_minimum_required(VERSION 3.25.1...4.0.0)
# 0AD Specific Functions
# Add Precompiled Headers. If no target is given, this macro will fail with a FATAL_ERROR.
# rationale: we need one PCH per static lib, since one global header would increase dependencies. To that end, we can either include them as
# "projectdir/precompiled.h", or add "source/PCH/projectdir" to the include path and put the PCH there. The latter is better because many
# projects contain several dirs and it's unclear where there the PCH should be stored. This way is also a bit easier to use in that
# source files always include "precompiled.h".
# Notes:
# * Visual Assist manages to use the project include path and can correctly open these files from the IDE.
# * precompiled.cpp (needed to "Create" the PCH) also goes in the abovementioned dir.
# * using CMakes precompiled Header is not possible, as it does not allow for a custom name like used here.
function(add_pch)
set(single_args TARGET PCH_DIR)
cmake_parse_arguments(args "" "${single_args}" "" ${ARGN})
if(NOT args_TARGET)
message(FATAL_ERROR "add_pch: Missing target!!")
endif()
include(PrecompiledHeader)
if(NOT args_PCH_DIR)
get_target_property(source_root ${args_TARGET} SOURCE_DIR)
set(args_PCH_DIR ${source_root}/pch/${args_TARGET})
endif()
# Put the project-specific PCH directory at the start of the include path, so '#include "precompiled.h"' will look in there first
target_include_directories(${args_TARGET}
BEFORE PRIVATE
${args_PCH_DIR}/
)
if (CMAKE_GENERATOR MATCHES "Visual Studio")
set(pch_header "precompiled.h")
elseif(CMAKE_GENERATOR MATCHES "Xcode")
set(pch_header "../${args_PCH_DIR}/precompiled.h")
else()
set(pch_header "${args_PCH_DIR}/precompiled.h")
endif()
precompile_header(${args_TARGET} ${pch_header} ${args_PCH_DIR}/precompiled.cpp)
target_sources(${args_TARGET}
PRIVATE
${args_PCH_DIR}/precompiled.cpp
${args_PCH_DIR}/precompiled.h
)
target_compile_definitions(${args_TARGET} PRIVATE CONFIG_ENABLE_PCH=1)
endfunction(add_pch)

View file

@ -0,0 +1,54 @@
function(find_prebuild_library _name)
include(FindPackageHandleStandardArgs)
set(multi_args COMPONENTS PATHS)
set(single_args INC_PATH VERSION)
cmake_parse_arguments(args "${multi_args}" "${single_args}" "" ${ARGN})
string(TOLOWER ${_name} libname)
string(TOUPPER ${_name} target_name)
# ++++++++ Handle COMPONENTS +++++++++++++++++++++
if(args_COMPONENTS)
endif()
# ++++++++ Find relevant elements ++++++++++++++++
find_library(Lib${_name} NAMES ${libname} ${libname}${args_VERSION})
if(NOT args_INC_PATH)
find_path(Lib${_name}_inc NAMES ${libname}.h PATHS ${0AD_EXT_LIBDIR}/${_name}/include/)
# recursive add all paths beneth included...
else()
set(Lib${_name}_inc ${args_INC_PATH})
endif()
if(NOT Lib${_name}_inc)
set(Lib${_name}_inc ${0AD_EXT_LIBDIR}/${_name}/include/)
endif()
find_package_handle_standard_args(Lib${_name} REQUIRED_VARS Lib${_name})
message(STATUS "${Lib${_name}} - ${Lib${_name}_inc} - ${Lib${_name}_FOUND} - ${target_name}::${target_name}")
if (Lib${_name}_FOUND)
mark_as_advanced(
Lib${_name}
Lib${_name}_inc
)
endif()
if(Lib${_name} MATCHES "LibBoost")
add_library(${target_name}::headers INTERFACE IMPORTED)
set_target_properties(${target_name}::headers PROPERTIES
IMPORTED_LOCATION ${Lib${_name}_inc}
INTERFACE_INCLUDE_DIRECTORIES ${Lib${_name}_inc}
)
elseif(Lib${_name} MATCHES "SDL2")
add_library(${target_name}::${target_name} UNKNOWN IMPORTED)
set_target_properties(${target_name}::${target_name} PROPERTIES
IMPORTED_LOCATION ${Lib${_name}}
INTERFACE_INCLUDE_DIRECTORIES ${Lib${_name}_inc}/SDL
)
elseif (Lib${_name} AND NOT TARGET ${target_name}::${target_name})
add_library(${target_name}::${target_name} UNKNOWN IMPORTED)
set_target_properties(${target_name}::${target_name} PROPERTIES
IMPORTED_LOCATION ${Lib${_name}}
INTERFACE_INCLUDE_DIRECTORIES ${Lib${_name}_inc}
)
endif()
endfunction()

View file

@ -0,0 +1,35 @@
# Adds a custom precompiled header. This header must be included in the code if not added with FORCE_INCLUDE
function(precompile_header _target _header _source)
set(single_args FORCE_INCLUDE)
cmake_parse_arguments(args "" "${single_args}" "" ${ARGN})
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR CMAKE_C_COMPILER_ID STREQUAL "MSVC")
# Solution based opon https://www.dominikgrabiec.com/posts/2022/10/18/precompiled_header_snippet.html
target_compile_options(${_target}
PRIVATE
"/Yu${_header}"
)
set_source_files_properties(${_source}
PROPERTIES
COMPILE_OPTIONS "/Yc${_header}"
)
if(${args_FORCE_INCLUDE})
set_source_files_properties(${_source}
PROPERTIES
COMPILE_OPTIONS /FI${_header}
)
endif()
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU|AppleClang" OR CMAKE_C_COMPILER_ID MATCHES "Clang|GNU|AppleClang")
# Solution is based on internal cmake code
set_source_files_properties(${_source}
PROPERTIES
COMPILE_OPTIONS -Winvalid-pch -x ${_header}.gch
)
if(${args_FORCE_INCLUDE})
set_source_files_properties(${_source}
PROPERTIES
COMPILE_OPTIONS include ${_header}.gch
)
endif()
endif()
endfunction()

View file

@ -0,0 +1,33 @@
# Checks out the SVN Revision of windows libraries. Additionally sets up the environment for cmake.
# To update the libraries change the 'SVN_REVISION'. Important: the '-r' in the Revision must be retained.
message(STATUS "Fetching Windows prebuild Libraries for ${ARCH}")
if(fetch-prebuild-libs)
include(FetchContent)
if(ARCH STREQUAL "amd64")
set(REPO_NAME windows-libs-amd64)
else()
set(REPO_NAME windows-libs)
endif()
FetchContent_Populate(
prebuild_libs
SVN_REPOSITORY https://svn.wildfiregames.com/public/${REPO_NAME}/trunk
SVN_REVISION -r28278
SOURCE_DIR ${0AD_EXT_LIBDIR}
)
endif()
message(STATUS "Copy dependencies' binaries to 'binaries/system/' and adding to 'CMAKE_PREFIX_PATH'")
set(DIR_LIST cpp-httplib enet fcollada freetype gloox iconv icu libcurl libpng libsodium libxml2 microsoft miniupnpc nvtt openal sdl2 spidermonkey vorbis zlib)
foreach(dir ${DIR_LIST})
file(COPY ${0AD_EXT_LIBDIR}/${dir}/bin DESTINATION ${CMAKE_SOURCE_DIR}/binaries/system)
list(APPEND CMAKE_PREFIX_PATH ${0AD_EXT_LIBDIR}/${dir})
endforeach()
# Add the whole libraries directory to CMAKE_PREFIX_PATH. May be redundand but needed for wxWidgets
list(APPEND CMAKE_PREFIX_PATH ${0AD_EXT_LIBDIR})
# Add libraries not set during binary copy
list(APPEND CMAKE_PREFIX_PATH ${0AD_EXT_LIBDIR}/fmt)
list(APPEND CMAKE_PREFIX_PATH ${0AD_EXT_LIBDIR}/libzip)
list(APPEND CMAKE_PREFIX_PATH ${0AD_EXT_LIBDIR}/cxxtest-4.4)
message(STATUS "Copy build tools to 'build/bin'")
file(COPY ${0AD_EXT_LIBDIR}/cxxtest-4.4/bin DESTINATION ${CMAKE_SOURCE_DIR}/build/bin)

View file

@ -6,7 +6,11 @@
## Building the Doxygen documentation
To generate the Doxygen documentation: run "cmake -S . -B output && cmake --build output".
To generate the Doxygen documentation:
```console
cmake -S 0ad/rootdir -B output && cmake --build output --target docs
```
If you build the documentation with cmake, the output is located in the folder html inside your
specified build directory.

View file

@ -1,64 +1,66 @@
cmake_minimum_required(VERSION 3.18.4...3.28.0)
project(Pyrogenesis DESCRIPTION "Pyrogenesis, a RTS Engine" LANGUAGES NONE)
cmake_minimum_required(VERSION 3.25.1...4.0.0)
# Check if Doxygen and graphviz are installed.
find_package(Doxygen 1.9.1 REQUIRED dot)
if(DOXYGEN_FOUND)
include(FetchContent)
include(FetchContent)
FetchContent_Declare(doxygen_awesome_css
GIT_REPOSITORY https://github.com/jothepro/doxygen-awesome-css
GIT_TAG v2.3.3
SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/styling
)
FetchContent_MakeAvailable(doxygen_awesome_css)
message(STATUS "Fetching doxygen_awesome_css")
FetchContent_Declare(doxygen_awesome_css
GIT_REPOSITORY https://github.com/jothepro/doxygen-awesome-css
GIT_TAG v2.4.2
SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/styling
)
FetchContent_MakeAvailable(doxygen_awesome_css)
# Get current Branch Name to set it as the Project Number.
find_package(Git)
if(Git_FOUND)
set(ENV{GIT_DISCOVERY_ACROSS_FILESYSTEM} 1)
execute_process(COMMAND "${GIT_EXECUTABLE}" rev-parse --is-inside-work-tree OUTPUT_VARIABLE IS_GIT OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
if(IS_GIT)
execute_process(COMMAND "${GIT_EXECUTABLE}" rev-parse --abbrev-ref HEAD OUTPUT_VARIABLE CURRENT_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
endif()
# Get current Branch Name to set it as the Project Number.
find_package(Git)
if(Git_FOUND)
set(ENV{GIT_DISCOVERY_ACROSS_FILESYSTEM} 1)
execute_process(COMMAND "${GIT_EXECUTABLE}" rev-parse --is-inside-work-tree OUTPUT_VARIABLE IS_GIT OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
if(IS_GIT)
execute_process(COMMAND "${GIT_EXECUTABLE}" rev-parse --abbrev-ref HEAD OUTPUT_VARIABLE CURRENT_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
endif()
# Doxygen Configuration.
if(CURRENT_BRANCH)
set(DOXYGEN_PROJECT_NUMBER ${CURRENT_BRANCH})
else()
set(DOXYGEN_PROJECT_NUMBER main)
endif()
set(DOXYGEN_PROJECT_LOGO ${CMAKE_CURRENT_SOURCE_DIR}/pyrogenesis.png)
set(DOXYGEN_TAB_SIZE 4)
set(DOXYGEN_EXCLUDE_PATTERNS */.svn* */tests/test_*)
set(DOXYGEN_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../source)
set(DOXYGEN_EXAMPLE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../source)
set(DOXYGEN_EXCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/../../source/tools ${CMAKE_CURRENT_SOURCE_DIR}/../../source/third_party)
set(DOXYGEN_GENERATE_TREEVIEW YES)
set(DOXYGEN_HTML_EXTRA_STYLESHEET ${doxygen_awesome_css_SOURCE_DIR}/doxygen-awesome.css ${CMAKE_CURRENT_SOURCE_DIR}/style.css)
set(DOXYGEN_JAVADOC_AUTOBRIEF YES)
set(DOXYGEN_EXTRACT_ALL YES)
set(DOXYGEN_EXTRACT_PRIVATE YES)
set(DOXYGEN_EXTRACT_STATIC YES)
set(DOXYGEN_EXTRACT_ANON_NSPACES YES)
set(DOXYGEN_SHOW_DIRECTORIES YES)
set(DOXYGEN_STRIP_CODE_COMMENTS NO)
set(DOXYGEN_MACRO_EXPANSION YES)
set(DOXYGEN_EXPAND_ONLY_PREDEF YES)
set(DOXYGEN_GENERATE_TODOLIST NO)
set(DOXYGEN_PREDEFINED "UNUSED(x)=x" "METHODDEF(x)=static x" "GLOBAL(x)=x")
set(DOXYGEN_EXPAND_AS_DEFINED DEFAULT_COMPONENT_ALLOCATOR DEFAULT_SCRIPT_WRAPPER DEFAULT_INTERFACE_WRAPPER DEFAULT_MESSAGE_IMPL MESSAGE INTERFACE COMPONENT GUISTDTYPE)
set(DOXYGEN_WARN_LOGFILE doxygen.log)
# Doxygen Configuration.
set(DOXYGEN_PROJECT_NAME "Pyrogenesis")
set(DOXYGEN_PROJECT_BRIEF "Pyrogenesis, a RTS Engine")
if(CURRENT_BRANCH)
set(DOXYGEN_PROJECT_NUMBER ${CURRENT_BRANCH})
else()
set(DOXYGEN_PROJECT_NUMBER main)
endif()
set(DOXYGEN_PROJECT_LOGO ${CMAKE_CURRENT_SOURCE_DIR}/pyrogenesis.png)
set(DOXYGEN_TAB_SIZE 4)
set(DOXYGEN_EXCLUDE_PATTERNS */.svn* */tests/test_*)
set(DOXYGEN_INCLUDE_PATH ${CMAKE_SOURCE_DIR}/source)
set(DOXYGEN_EXAMPLE_PATH ${CMAKE_SOURCE_DIR}/source)
set(DOXYGEN_EXCLUDE ${CMAKE_SOURCE_DIR}/source/tools ${CMAKE_SOURCE_DIR}/source/third_party)
set(DOXYGEN_GENERATE_TREEVIEW YES)
set(DOXYGEN_HTML_EXTRA_STYLESHEET ${doxygen_awesome_css_SOURCE_DIR}/doxygen-awesome.css ${CMAKE_CURRENT_SOURCE_DIR}/style.css)
set(DOXYGEN_JAVADOC_AUTOBRIEF YES)
set(DOXYGEN_EXTRACT_ALL YES)
set(DOXYGEN_EXTRACT_PRIVATE YES)
set(DOXYGEN_EXTRACT_STATIC YES)
set(DOXYGEN_EXTRACT_ANON_NSPACES YES)
set(DOXYGEN_SHOW_DIRECTORIES YES)
set(DOXYGEN_STRIP_CODE_COMMENTS NO)
set(DOXYGEN_MACRO_EXPANSION YES)
set(DOXYGEN_EXPAND_ONLY_PREDEF YES)
set(DOXYGEN_GENERATE_TODOLIST NO)
set(DOXYGEN_PREDEFINED "UNUSED(x)=x" "METHODDEF(x)=static x" "GLOBAL(x)=x")
set(DOXYGEN_EXPAND_AS_DEFINED DEFAULT_COMPONENT_ALLOCATOR DEFAULT_SCRIPT_WRAPPER DEFAULT_INTERFACE_WRAPPER DEFAULT_MESSAGE_IMPL MESSAGE INTERFACE COMPONENT GUISTDTYPE)
set(DOXYGEN_WARN_LOGFILE doxygen.log)
doxygen_add_docs(${CMAKE_PROJECT_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/../../source
${CMAKE_CURRENT_SOURCE_DIR}/mainpage.dox
${CMAKE_CURRENT_SOURCE_DIR}/../../LICENSE.md
ALL)
doxygen_add_docs(docs
${CMAKE_SOURCE_DIR}/source
${CMAKE_CURRENT_SOURCE_DIR}/mainpage.dox
${CMAKE_SOURCE_DIR}/LICENSE.md
COMMENT "Creating Doxygen for the engine."
)
else()
message(SEND_ERROR "Make sure Doxygen is installed and usable")
message(SEND_ERROR "Make sure Doxygen is installed and usable")
endif()

View file

@ -53,25 +53,6 @@ public:
void SetElevation(float f);
void SetRotation(float f);
/**
* Calculate brightness of a point of a unit with the given normal vector,
* for rendering with CPU lighting.
* The resulting color contains both ambient and diffuse light.
* To cope with sun overbrightness, the color is scaled by 0.5.
*
* @param normal normal vector (must have length 1)
*/
RGBColor EvaluateUnitScaled(const CVector3D& normal) const
{
float dot = -normal.Dot(m_SunDir);
RGBColor color = m_AmbientColor;
if (dot > 0)
color += m_SunColor * dot;
return color * 0.5f;
}
// Comparison operators
bool operator==(const CLightEnv& o) const
{

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -33,7 +33,7 @@ namespace Renderer::Backend { class IDeviceCommandContext; }
* This computes and binds per-vertex data; the modifier is responsible
* for setting any shader uniforms etc.
*/
class CPUSkinnedModelVertexRenderer : public ModelVertexRenderer
class CPUSkinnedModelVertexRenderer final : public ModelVertexRenderer
{
public:
CPUSkinnedModelVertexRenderer();

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -34,7 +34,7 @@ namespace Renderer::Backend { class IShaderProgram; }
* This computes and binds per-vertex data; the modifier is responsible
* for setting any shader uniforms etc.
*/
class GPUSkinnedModelModelRenderer : public ModelVertexRenderer
class GPUSkinnedModelModelRenderer final : public ModelVertexRenderer
{
public:
GPUSkinnedModelModelRenderer();

View file

@ -34,7 +34,7 @@ struct InstancingModelRendererInternals;
* This computes and binds per-vertex data; the modifier is responsible
* for setting any shader uniforms etc (including the instancing transform).
*/
class InstancingModelRenderer : public ModelVertexRenderer
class InstancingModelRenderer final : public ModelVertexRenderer
{
public:
InstancingModelRenderer();

View file

@ -102,15 +102,11 @@ CMaterial::Pass GetMaterialPassFromCullGroup(const int cullGroup, const ERenderM
}
void ModelRenderer::Init()
{
}
// Helper function to copy object-space position and normal vectors into arrays.
// static
void ModelRenderer::CopyPositionAndNormals(
const CModelDefPtr& mdef,
const VertexArrayIterator<CVector3D>& Position,
const VertexArrayIterator<CVector3D>& Normal)
const CModelDefPtr& mdef,
const VertexArrayIterator<CVector3D>& Position,
const VertexArrayIterator<CVector3D>& Normal)
{
size_t numVertices = mdef->GetNumVertices();
SModelVertex* vertices = mdef->GetVertices();
@ -122,11 +118,11 @@ void ModelRenderer::CopyPositionAndNormals(
}
}
// Helper function to transform position and normal vectors into world-space.
// static
void ModelRenderer::BuildPositionAndNormals(
CModel* model,
const VertexArrayIterator<CVector3D>& Position,
const VertexArrayIterator<CVector3D>& Normal)
CModel* model,
const VertexArrayIterator<CVector3D>& Position,
const VertexArrayIterator<CVector3D>& Normal)
{
CModelDefPtr mdef = model->GetModelDef();
size_t numVertices = mdef->GetNumVertices();
@ -160,43 +156,16 @@ void ModelRenderer::BuildPositionAndNormals(
}
}
// Helper function for lighting
void ModelRenderer::BuildColor4ub(
CModel* model,
const VertexArrayIterator<CVector3D>& Normal,
const VertexArrayIterator<SColor4ub>& Color)
{
PROFILE("lighting vertices");
CModelDefPtr mdef = model->GetModelDef();
size_t numVertices = mdef->GetNumVertices();
const CLightEnv& lightEnv = g_Renderer.GetSceneRenderer().GetLightEnv();
CColor shadingColor = model->GetShadingColor();
for (size_t j = 0; j < numVertices; ++j)
{
RGBColor tempcolor = lightEnv.EvaluateUnitScaled(Normal[j]);
tempcolor.X *= shadingColor.r;
tempcolor.Y *= shadingColor.g;
tempcolor.Z *= shadingColor.b;
Color[j] = ConvertRGBColorTo4ub(tempcolor);
}
}
// static
void ModelRenderer::GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices, bool gpuSkinning)
{
MikkTSpace ms(mdef, newVertices, gpuSkinning);
ms.Generate();
}
// Copy UV coordinates
// static
void ModelRenderer::BuildUV(
const CModelDefPtr& mdef,
const VertexArrayIterator<float[2]>& UV,
int UVset)
const CModelDefPtr& mdef, const VertexArrayIterator<float[2]>& UV, int UVset)
{
const size_t numVertices = mdef->GetNumVertices();
const size_t numberOfUVPerVertex = mdef->GetNumUVsPerVertex();
@ -209,11 +178,9 @@ void ModelRenderer::BuildUV(
}
}
// Build default indices array.
// static
void ModelRenderer::BuildIndices(
const CModelDefPtr& mdef,
const VertexArrayIterator<u16>& Indices)
const CModelDefPtr& mdef, const VertexArrayIterator<u16>& Indices)
{
size_t idxidx = 0;
SModelFace* faces = mdef->GetFaces();
@ -227,105 +194,6 @@ void ModelRenderer::BuildIndices(
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
// ShaderModelRenderer implementation
/**
* Internal data of the ShaderModelRenderer.
*
* Separated into the source file to increase implementation hiding (and to
* avoid some causes of recompiles).
*/
struct ShaderModelRenderer::ShaderModelRendererInternals
{
ShaderModelRendererInternals(ShaderModelRenderer* r) : m_Renderer(r) { }
/// Back-link to "our" renderer
ShaderModelRenderer* m_Renderer;
/// ModelVertexRenderer used for vertex transformations
ModelVertexRendererPtr vertexRenderer;
/// List of submitted models for rendering in this frame
std::vector<CModel*> submissions[CSceneRenderer::CULL_MAX];
};
// Construction/Destruction
ShaderModelRenderer::ShaderModelRenderer(ModelVertexRendererPtr vertexrenderer)
{
m = new ShaderModelRendererInternals(this);
m->vertexRenderer = vertexrenderer;
}
ShaderModelRenderer::~ShaderModelRenderer()
{
delete m;
}
// Submit one model.
void ShaderModelRenderer::Submit(int cullGroup, CModel* model)
{
CModelRData* rdata = (CModelRData*)model->GetRenderData();
// Ensure model data is valid
const void* key = m->vertexRenderer.get();
if (!rdata || rdata->GetKey() != key)
{
model->InvalidatePosition();
rdata = m->vertexRenderer->CreateModelData(key, model);
model->SetRenderData(rdata);
model->SetDirty(~0u);
}
m->submissions[cullGroup].push_back(model);
}
// Call update for all submitted models and enter the rendering phase
void ShaderModelRenderer::PrepareModels(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
{
for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup)
{
for (CModel* model : m->submissions[cullGroup])
{
model->ValidatePosition();
CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData());
ENSURE(rdata->GetKey() == m->vertexRenderer.get());
}
m->vertexRenderer->UpdateModelsData(deviceCommandContext, m->submissions[cullGroup]);
for (CModel* model : m->submissions[cullGroup])
{
CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData());
rdata->m_UpdateFlags = 0;
}
}
}
void ShaderModelRenderer::UploadModels(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
{
for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup)
{
m->vertexRenderer->UploadModelsData(deviceCommandContext, m->submissions[cullGroup]);
}
}
// Clear the submissions list
void ShaderModelRenderer::EndFrame()
{
for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup)
m->submissions[cullGroup].clear();
}
// Helper structs for ShaderModelRenderer::Render():
struct SMRSortByDistItem
@ -413,12 +281,12 @@ struct SMRCompareTechBucket
}
};
void ShaderModelRenderer::Render(
void ModelRenderer::Render(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
const RenderModifierPtr& modifier, const CShaderDefines& context,
int cullGroup, int flags, const ERenderMode renderMode)
ModelVertexRenderer& modelVertexRenderer, RenderModifier& modifier, const CShaderDefines& context,
int cullGroup, int flags, const ERenderMode renderMode, std::span<CModel*> submissions)
{
if (m->submissions[cullGroup].empty())
if (submissions.empty())
return;
CMatrix3D worldToCam;
@ -429,7 +297,7 @@ void ShaderModelRenderer::Render(
/*
* Rendering approach:
*
* m->submissions contains the list of CModels to render.
* submissions contains the list of CModels to render.
*
* The data we need to render a model is:
* - CShaderTechnique
@ -497,10 +365,9 @@ void ShaderModelRenderer::Render(
{
PROFILE3("bucketing by material");
for (size_t i = 0; i < m->submissions[cullGroup].size(); ++i)
for (CModel* model : submissions)
{
CModel* model = m->submissions[cullGroup][i];
const CMaterial material{model->GetMaterial()};
const CMaterial& material{model->GetMaterial()};
const CShaderDefines& defines{material.GetShaderDefines()};
const CStrIntern shaderEffect{material.GetShaderEffect(materialPass)};
SMRMaterialBucketKey key(shaderEffect, defines);
@ -683,7 +550,7 @@ void ShaderModelRenderer::Render(
Renderer::Backend::IShaderProgram* shader = currentTech->GetShader(pass);
modifier->BeginPass(deviceCommandContext, shader);
modifier.BeginPass(deviceCommandContext, shader);
// TODO: Use a more generic approach to handle bound queries.
bool boundTime = false;
@ -753,7 +620,7 @@ void ShaderModelRenderer::Render(
if (newModeldef != currentModeldef)
{
currentModeldef = newModeldef;
m->vertexRenderer->PrepareModelDef(deviceCommandContext, *currentModeldef);
modelVertexRenderer.PrepareModelDef(deviceCommandContext, *currentModeldef);
}
// Bind all uniforms when any change
@ -813,12 +680,12 @@ void ShaderModelRenderer::Render(
}
}
modifier->PrepareModel(deviceCommandContext, model);
modifier.PrepareModel(deviceCommandContext, model);
CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData());
ENSURE(rdata->GetKey() == m->vertexRenderer.get());
ENSURE(rdata->GetKey() == &modelVertexRenderer);
m->vertexRenderer->RenderModel(deviceCommandContext, shader, model, rdata);
modelVertexRenderer.RenderModel(deviceCommandContext, shader, model, rdata);
}
}

View file

@ -30,6 +30,7 @@
#include "lib/types.h"
#include <memory>
#include <span>
#include <vector>
class CModel;
@ -39,17 +40,8 @@ namespace Renderer::Backend { class IDeviceCommandContext; }
struct SColor4ub;
template <typename T> class VertexArrayIterator;
class RenderModifier;
typedef std::shared_ptr<RenderModifier> RenderModifierPtr;
class LitRenderModifier;
typedef std::shared_ptr<LitRenderModifier> LitRenderModifierPtr;
class ModelVertexRenderer;
typedef std::shared_ptr<ModelVertexRenderer> ModelVertexRendererPtr;
class ModelRenderer;
typedef std::shared_ptr<ModelRenderer> ModelRendererPtr;
class RenderModifier;
/**
* Class CModelRData: Render data that is maintained per CModel.
@ -83,25 +75,12 @@ private:
/**
* Class ModelRenderer: Abstract base class for all model renders.
* ModelRenderer renders a per-frame list of models. It loads the appropriate
* shaders for rendering each model, and that batches by shader technique (and
* by mesh and texture).
*
* A ModelRenderer manages a per-frame list of models.
*
* It is supposed to be derived in order to create new ways in which
* the per-frame list of models can be managed (for batching, for
* transparent rendering, etc.) or potentially for rarely used special
* effects.
*
* A typical ModelRenderer will delegate vertex transformation/setup
* to a ModelVertexRenderer.
* It will delegate fragment stage setup to a RenderModifier.
*
* For most purposes, you should use a BatchModelRenderer with
* specialized ModelVertexRenderer and RenderModifier implementations.
*
* It is suggested that a derived class implement the provided generic
* Render function, however in some cases it may be necessary to supply
* a Render function with a different prototype.
* ModelRenderer delegates vertex transformation/setup to a
* ModelVertexRenderer. It delegates fragment stage setup to a RenderModifier.
*
* ModelRenderer also contains a number of static helper functions
* for building vertex arrays.
@ -109,61 +88,10 @@ private:
class ModelRenderer
{
public:
ModelRenderer() { }
virtual ~ModelRenderer() { }
/**
* Initialise global settings.
* Should be called before using the class.
*/
static void Init();
/**
* Submit: Submit a model for rendering this frame.
*
* preconditions : The model must not have been submitted to any
* ModelRenderer in this frame. Submit may only be called
* after EndFrame and before PrepareModels.
*
* @param model The model that will be added to the list of models
* submitted this frame.
*/
virtual void Submit(int cullGroup, CModel* model) = 0;
/**
* PrepareModels: Calculate renderer data for all previously
* submitted models.
*
* Must be called before any rendering calls and after all models
* for this frame have been submitted.
*/
virtual void PrepareModels(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext) = 0;
/**
* Upload renderer data for all previously submitted models to backend.
*
* Must be called before any rendering calls and after all models
* for this frame have been prepared.
*/
virtual void UploadModels(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext) = 0;
/**
* EndFrame: Remove all models from the list of submitted
* models.
*/
virtual void EndFrame() = 0;
/**
* Render: Render submitted models, using the given RenderModifier to setup
* the fragment stage.
*
* @note It is suggested that derived model renderers implement and use
* this Render functions. However, a highly specialized model renderer
* may need to "disable" this function and provide its own Render function
* with a different prototype.
*
* preconditions : PrepareModels must be called after all models have been
* submitted and before calling Render.
*
@ -172,10 +100,10 @@ public:
* If flags is non-zero, only models that contain flags in their
* CModel::GetFlags() are rendered.
*/
virtual void Render(
void Render(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
const RenderModifierPtr& modifier, const CShaderDefines& context,
int cullGroup, int flags, const ERenderMode renderMode) = 0;
ModelVertexRenderer& modelVertexRenderer, RenderModifier& modifier, const CShaderDefines& context,
int cullGroup, int flags, const ERenderMode renderMode, std::span<CModel*> submissions);
/**
* CopyPositionAndNormals: Copy unanimated object-space vertices and
@ -190,9 +118,9 @@ public:
* The array behind the iterator must be as large as the Position array.
*/
static void CopyPositionAndNormals(
const CModelDefPtr& mdef,
const VertexArrayIterator<CVector3D>& Position,
const VertexArrayIterator<CVector3D>& Normal);
const CModelDefPtr& mdef,
const VertexArrayIterator<CVector3D>& Position,
const VertexArrayIterator<CVector3D>& Normal);
/**
* BuildPositionAndNormals: Build animated vertices and normals,
@ -209,25 +137,9 @@ public:
* the Position array.
*/
static void BuildPositionAndNormals(
CModel* model,
const VertexArrayIterator<CVector3D>& Position,
const VertexArrayIterator<CVector3D>& Normal);
/**
* BuildColor4ub: Build lighting colors for the given model,
* based on previously calculated world space normals.
*
* @param model The model that is to be lit.
* @param Normal Array of the model's normal vectors, animated and
* transformed into world space.
* @param Color Points to the array that will receive the lit vertex color.
* The array behind the iterator must large enough to hold
* model->GetModelDef()->GetNumVertices() vertices.
*/
static void BuildColor4ub(
CModel* model,
const VertexArrayIterator<CVector3D>& Normal,
const VertexArrayIterator<SColor4ub>& Color);
CModel* model,
const VertexArrayIterator<CVector3D>& Position,
const VertexArrayIterator<CVector3D>& Normal);
/**
* BuildUV: Copy UV coordinates into the given vertex array.
@ -238,9 +150,9 @@ public:
* mdef->GetNumVertices() vertices.
*/
static void BuildUV(
const CModelDefPtr& mdef,
const VertexArrayIterator<float[2]>& UV,
int UVset);
const CModelDefPtr& mdef,
const VertexArrayIterator<float[2]>& UV,
int UVset);
/**
* BuildIndices: Create the indices array for the given CModelDef.
@ -250,8 +162,7 @@ public:
* mdef->GetNumFaces()*3 elements.
*/
static void BuildIndices(
const CModelDefPtr& mdef,
const VertexArrayIterator<u16>& Indices);
const CModelDefPtr& mdef, const VertexArrayIterator<u16>& Indices);
/**
* GenTangents: Generate tangents for the given CModelDef.
@ -263,33 +174,4 @@ public:
static void GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices, bool gpuSkinning);
};
/**
* Implementation of ModelRenderer that loads the appropriate shaders for
* rendering each model, and that batches by shader technique (and by mesh and texture).
*/
class ShaderModelRenderer : public ModelRenderer
{
friend struct ShaderModelRendererInternals;
public:
ShaderModelRenderer(ModelVertexRendererPtr vertexrender);
~ShaderModelRenderer() override;
// Batching implementations
void Submit(int cullGroup, CModel* model) override;
void PrepareModels(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext) override;
void UploadModels(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext) override;
void EndFrame() override;
void Render(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
const RenderModifierPtr& modifier, const CShaderDefines& context,
int cullGroup, int flags, const ERenderMode renderMode) override;
private:
struct ShaderModelRendererInternals;
ShaderModelRendererInternals* m;
};
#endif // INCLUDED_MODELRENDERER

View file

@ -62,7 +62,6 @@
#include "ps/VideoMode.h"
#include "ps/World.h"
#include "renderer/DebugRenderer.h"
#include "renderer/ModelRenderer.h"
#include "renderer/PostprocManager.h"
#include "renderer/RenderingOptions.h"
#include "renderer/SceneRenderer.h"
@ -456,7 +455,6 @@ CRenderer::CRenderer(Renderer::Backend::IDevice* device)
ModelDefActivateFastImpl();
ColorActivateFastImpl();
ModelRenderer::Init();
}
CRenderer::~CRenderer()

View file

@ -212,17 +212,17 @@ void CRenderingOptions::ReadConfigAndSetupHooks()
m_ConfigHooks->Setup("silhouettes", m_Silhouettes);
m_ConfigHooks->Setup("gpuskinning", [this]() {
const Renderer::Backend::IDevice::Capabilities& capabilities{
g_VideoMode.GetBackendDevice()->GetCapabilities()};
if (!g_ConfigDB.Get("gpuskinning", false))
return;
if (capabilities.computeShaders && capabilities.storage)
m_GPUSkinning = true;
else
if (g_ConfigDB.Get("gpuskinning", false))
{
m_GPUSkinning = false;
LOGMESSAGE("GPU skinning isn't supported on the current hardware.");
const Renderer::Backend::IDevice::Capabilities& capabilities{
g_VideoMode.GetBackendDevice()->GetCapabilities()};
if (capabilities.computeShaders && capabilities.storage)
m_GPUSkinning = true;
else
{
m_GPUSkinning = false;
LOGMESSAGE("GPU skinning isn't supported on the current hardware.");
}
}
if (CRenderer::IsInitialised())

View file

@ -68,6 +68,7 @@
#include <algorithm>
#include <cmath>
#include <optional>
struct SScreenRect
{
@ -115,78 +116,192 @@ public:
SilhouetteRenderer silhouetteRenderer;
/// Various model renderers
// Various model renderers
struct Models
{
// NOTE: The current renderer design (with ModelRenderer, ModelVertexRenderer,
// RenderModifier, etc) is mostly a relic of an older design that implemented
// the different materials and rendering modes through extensive subclassing
// and hooking objects together in various combinations.
// The new design uses the CShaderManager API to abstract away the details
// of rendering, and uses a data-driven approach to materials, so there are
// now a small number of generic subclasses instead of many specialised subclasses,
// but most of the old infrastructure hasn't been refactored out yet and leads to
// some unwanted complexity.
// Submitted models are split on two axes:
// - Normal vs Transp[arent] - alpha-blended models are stored in a separate
// - Opaque vs Transparent - alpha-blended models are stored in a separate
// list so we can draw them above/below the alpha-blended water plane correctly
// - Skinned vs Unskinned - with hardware lighting we don't need to
// duplicate mesh data per model instance (except for skinned models),
// so non-skinned models get different ModelVertexRenderers
// - Skinned vs Unskinned - we don't need to duplicate mesh data per
// model instance (except for skinned models), so non-skinned models
// get different ModelVertexRenderers
ModelRendererPtr NormalSkinned;
ModelRendererPtr NormalUnskinned; // == NormalSkinned if unskinned shader instancing not supported
ModelRendererPtr TranspSkinned;
ModelRendererPtr TranspUnskinned; // == TranspSkinned if unskinned shader instancing not supported
struct Submissions
{
std::vector<CModel*> submissions[CSceneRenderer::CULL_MAX];
};
ModelVertexRendererPtr VertexRendererShader;
ModelVertexRendererPtr VertexInstancingShader;
ModelVertexRendererPtr VertexGPUSkinningShader;
// Unskinned submissions should be prepared and rendered with
// VertexInstancingShader. Skinned - with Vertex*SkinningShader
// depending on whether GPU skinning is enabled.
Submissions OpaqueSkinned;
Submissions OpaqueUnskinned;
Submissions TransparentSkinned;
Submissions TransparentUnskinned;
LitRenderModifierPtr ModShader;
ModelRenderer modelRenderer;
InstancingModelRenderer VertexInstancingShader;
CPUSkinnedModelVertexRenderer VertexCPUSkinningShader;
// We can't create GPU skinning renderer for renderer devices without
// its support.
std::optional<GPUSkinnedModelModelRenderer> VertexGPUSkinningShader;
ShaderRenderModifier ModShader;
bool GPUSkinningEnabled{false};
} Model;
CShaderDefines globalContext;
/**
* Upload renderer data for all previously submitted models to backend.
*
* Must be called before any rendering calls and after all models
* for this frame have been prepared.
*/
void UploadModels(Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
{
PROFILE3("upload models");
ModelVertexRenderer& modelVertexSkinningRenderer{
Model.GPUSkinningEnabled
? static_cast<ModelVertexRenderer&>(*Model.VertexGPUSkinningShader)
: static_cast<ModelVertexRenderer&>(Model.VertexCPUSkinningShader)};
for (int cullGroup{0}; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup)
{
modelVertexSkinningRenderer.UploadModelsData(deviceCommandContext, Model.OpaqueSkinned.submissions[cullGroup]);
modelVertexSkinningRenderer.UploadModelsData(deviceCommandContext, Model.TransparentSkinned.submissions[cullGroup]);
}
for (int cullGroup{0}; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup)
{
Model.VertexInstancingShader.UploadModelsData(deviceCommandContext, Model.OpaqueUnskinned.submissions[cullGroup]);
Model.VertexInstancingShader.UploadModelsData(deviceCommandContext, Model.TransparentUnskinned.submissions[cullGroup]);
}
}
/**
* PrepareModels: Calculate renderer data for all previously
* submitted models.
*
* Must be called before any rendering calls and after all models
* for this frame have been submitted.
*/
void PrepareModels(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
{
PROFILE3("prepare models");
ModelVertexRenderer& modelVertexSkinningRenderer{
Model.GPUSkinningEnabled
? static_cast<ModelVertexRenderer&>(*Model.VertexGPUSkinningShader)
: static_cast<ModelVertexRenderer&>(Model.VertexCPUSkinningShader)};
for (int cullGroup{0}; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup)
{
PrepareModels(deviceCommandContext, modelVertexSkinningRenderer, Model.OpaqueSkinned.submissions[cullGroup]);
PrepareModels(deviceCommandContext, modelVertexSkinningRenderer, Model.TransparentSkinned.submissions[cullGroup]);
}
for (int cullGroup{0}; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup)
{
PrepareModels(deviceCommandContext, Model.VertexInstancingShader, Model.OpaqueUnskinned.submissions[cullGroup]);
PrepareModels(deviceCommandContext, Model.VertexInstancingShader, Model.TransparentUnskinned.submissions[cullGroup]);
}
}
void PrepareModels(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext, ModelVertexRenderer& modelVertexRenderer, std::span<CModel*> submissions)
{
for (CModel* model : submissions)
{
model->ValidatePosition();
CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData());
ENSURE(rdata->GetKey() == &modelVertexRenderer);
}
modelVertexRenderer.UpdateModelsData(deviceCommandContext, submissions);
for (CModel* model : submissions)
{
CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData());
rdata->m_UpdateFlags = 0;
}
}
/**
* Submit: Submit a model for rendering this frame.
*
* preconditions : The model must not have been submitted to any
* ModelRenderer in this frame. Submit may only be called
* after EndFrame and before PrepareModels.
*
* @param model The model that will be added to the list of models
* submitted this frame.
*/
void Submit(const int cullGroup, ModelVertexRenderer& modelVertexRenderer, Models::Submissions& submissions, CModel* model)
{
CModelRData* rdata{static_cast<CModelRData*>(model->GetRenderData())};
// Ensure model data is valid.
// TODO: using a pointer as a key is unsafe.
const void* key{&modelVertexRenderer};
if (!rdata || rdata->GetKey() != key)
{
model->InvalidatePosition();
rdata = modelVertexRenderer.CreateModelData(key, model);
model->SetRenderData(rdata);
model->SetDirty(~0u);
}
submissions.submissions[cullGroup].push_back(model);
}
/**
* Renders all non-alpha-blended models with the given context.
*/
void CallModelRenderers(
void CallOpaqueModelRenderers(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
const CShaderDefines& context, int cullGroup, int flags, const ERenderMode renderMode)
{
CShaderDefines contextSkinned = context;
if (g_RenderingOptions.GetGPUSkinning())
contextSkinned.Add(str_USE_INSTANCING, str_1);
Model.NormalSkinned->Render(deviceCommandContext, Model.ModShader, contextSkinned, cullGroup, flags, renderMode);
ModelVertexRenderer& modelVertexSkinningRenderer{
Model.GPUSkinningEnabled
? static_cast<ModelVertexRenderer&>(*Model.VertexGPUSkinningShader)
: static_cast<ModelVertexRenderer&>(Model.VertexCPUSkinningShader)};
if (Model.NormalUnskinned != Model.NormalSkinned)
{
CShaderDefines contextUnskinned = context;
contextUnskinned.Add(str_USE_INSTANCING, str_1);
Model.NormalUnskinned->Render(deviceCommandContext, Model.ModShader, contextUnskinned, cullGroup, flags, renderMode);
}
CShaderDefines contextSkinned = context;
if (Model.GPUSkinningEnabled)
contextSkinned.Add(str_USE_INSTANCING, str_1);
Model.modelRenderer.Render(deviceCommandContext, modelVertexSkinningRenderer, Model.ModShader, contextSkinned, cullGroup, flags, renderMode, Model.OpaqueSkinned.submissions[cullGroup]);
CShaderDefines contextUnskinned = context;
contextUnskinned.Add(str_USE_INSTANCING, str_1);
Model.modelRenderer.Render(deviceCommandContext, Model.VertexInstancingShader, Model.ModShader, contextUnskinned, cullGroup, flags, renderMode, Model.OpaqueUnskinned.submissions[cullGroup]);
}
/**
* Renders all alpha-blended models with the given context.
*/
void CallTranspModelRenderers(
void CallTransparentModelRenderers(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
const CShaderDefines& context, int cullGroup, int flags, const ERenderMode renderMode)
{
CShaderDefines contextSkinned = context;
if (g_RenderingOptions.GetGPUSkinning())
contextSkinned.Add(str_USE_INSTANCING, str_1);
Model.TranspSkinned->Render(deviceCommandContext, Model.ModShader, contextSkinned, cullGroup, flags, renderMode);
ModelVertexRenderer& modelVertexSkinningRenderer{
Model.GPUSkinningEnabled
? static_cast<ModelVertexRenderer&>(*Model.VertexGPUSkinningShader)
: static_cast<ModelVertexRenderer&>(Model.VertexCPUSkinningShader)};
if (Model.TranspUnskinned != Model.TranspSkinned)
{
CShaderDefines contextUnskinned = context;
contextUnskinned.Add(str_USE_INSTANCING, str_1);
Model.TranspUnskinned->Render(deviceCommandContext, Model.ModShader, contextUnskinned, cullGroup, flags, renderMode);
}
CShaderDefines contextSkinned = context;
if (Model.GPUSkinningEnabled)
contextSkinned.Add(str_USE_INSTANCING, str_1);
Model.modelRenderer.Render(deviceCommandContext, modelVertexSkinningRenderer, Model.ModShader, contextSkinned, cullGroup, flags, renderMode, Model.TransparentSkinned.submissions[cullGroup]);
CShaderDefines contextUnskinned = context;
contextUnskinned.Add(str_USE_INSTANCING, str_1);
Model.modelRenderer.Render(deviceCommandContext, Model.VertexInstancingShader, Model.ModShader, contextUnskinned, cullGroup, flags, renderMode, Model.TransparentUnskinned.submissions[cullGroup]);
}
};
@ -239,26 +354,12 @@ void CSceneRenderer::ReloadShaders([[maybe_unused]] Renderer::Backend::IDevice*
m->globalContext.Add(str_RENDER_DEBUG_MODE,
RenderDebugModeEnum::ToString(g_RenderingOptions.GetRenderDebugMode()));
m->Model.ModShader = LitRenderModifierPtr(new ShaderRenderModifier());
m->Model.VertexRendererShader = ModelVertexRendererPtr(new CPUSkinnedModelVertexRenderer());
m->Model.VertexInstancingShader = ModelVertexRendererPtr(new InstancingModelRenderer());
if (g_RenderingOptions.GetGPUSkinning())
m->Model.GPUSkinningEnabled = g_RenderingOptions.GetGPUSkinning();
if (m->Model.GPUSkinningEnabled)
{
m->Model.VertexGPUSkinningShader = ModelVertexRendererPtr(new GPUSkinnedModelModelRenderer());
m->Model.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader));
m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader));
if (!m->Model.VertexGPUSkinningShader.has_value())
m->Model.VertexGPUSkinningShader.emplace();
}
else
{
m->Model.VertexGPUSkinningShader.reset();
m->Model.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexRendererShader));
m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexRendererShader));
}
m->Model.NormalUnskinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexInstancingShader));
m->Model.TranspUnskinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexInstancingShader));
}
void CSceneRenderer::Initialize()
@ -282,8 +383,8 @@ void CSceneRenderer::Resize(int /*width*/, int /*height*/)
void CSceneRenderer::BeginFrame()
{
// choose model renderers for this frame
m->Model.ModShader->SetShadowMap(&m->shadow);
m->Model.ModShader->SetLightEnv(m_LightEnv);
m->Model.ModShader.SetShadowMap(&m->shadow);
m->Model.ModShader.SetLightEnv(m_LightEnv);
}
void CSceneRenderer::SetSimulation(CSimulation2* simulation)
@ -315,12 +416,12 @@ void CSceneRenderer::RenderShadowMap(
{
PROFILE("render models");
m->CallModelRenderers(deviceCommandContext, {}, cullGroup, ModelFlag::CAST_SHADOWS, ERenderMode::SOLID);
m->CallOpaqueModelRenderers(deviceCommandContext, {}, cullGroup, ModelFlag::CAST_SHADOWS, ERenderMode::SOLID);
}
{
PROFILE("render transparent models");
m->CallTranspModelRenderers(deviceCommandContext, {}, cullGroup, ModelFlag::CAST_SHADOWS, ERenderMode::SOLID);
m->CallTransparentModelRenderers(deviceCommandContext, {}, cullGroup, ModelFlag::CAST_SHADOWS, ERenderMode::SOLID);
}
}
@ -363,10 +464,10 @@ void CSceneRenderer::RenderModels(
const ERenderMode modelRenderMode{
m_ModelRenderMode == WIREFRAME ? WIREFRAME : SOLID};
m->CallModelRenderers(deviceCommandContext, context, cullGroup, flags, modelRenderMode);
m->CallOpaqueModelRenderers(deviceCommandContext, context, cullGroup, flags, modelRenderMode);
if (m_ModelRenderMode == EDGED_FACES)
m->CallModelRenderers(deviceCommandContext, {}, cullGroup, flags, EDGED_FACES);
m->CallOpaqueModelRenderers(deviceCommandContext, {}, cullGroup, flags, EDGED_FACES);
}
void CSceneRenderer::RenderTransparentModels(
@ -388,13 +489,13 @@ void CSceneRenderer::RenderTransparentModels(
m_ModelRenderMode == WIREFRAME ? WIREFRAME : SOLID};
if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_OPAQUE)
m->CallTranspModelRenderers(deviceCommandContext, contextOpaque, cullGroup, flags, modelRenderMode);
m->CallTransparentModelRenderers(deviceCommandContext, contextOpaque, cullGroup, flags, modelRenderMode);
if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_BLEND)
m->CallTranspModelRenderers(deviceCommandContext, contextBlend, cullGroup, flags, modelRenderMode);
m->CallTransparentModelRenderers(deviceCommandContext, contextBlend, cullGroup, flags, modelRenderMode);
if (m_ModelRenderMode == EDGED_FACES)
m->CallTranspModelRenderers(deviceCommandContext, {}, cullGroup, flags, EDGED_FACES);
m->CallTransparentModelRenderers(deviceCommandContext, {}, cullGroup, flags, EDGED_FACES);
}
// SetObliqueFrustumClipping: change the near plane to the given clip plane (in world space)
@ -709,24 +810,24 @@ void CSceneRenderer::RenderSilhouettes(
{
PROFILE("render model occluders");
m->CallModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_OCCLUDER, 0, ERenderMode::SOLID);
m->CallOpaqueModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_OCCLUDER, 0, ERenderMode::SOLID);
}
{
PROFILE("render transparent occluders");
m->CallTranspModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_OCCLUDER, 0, ERenderMode::SOLID);
m->CallTransparentModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_OCCLUDER, 0, ERenderMode::SOLID);
}
// Since we can't sort, we'll use the stencil buffer to ensure we only draw
// a pixel once (using the color of whatever model happens to be drawn first).
{
PROFILE("render model casters");
m->CallModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_CASTER, 0, ERenderMode::SOLID);
m->CallOpaqueModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_CASTER, 0, ERenderMode::SOLID);
}
{
PROFILE("render transparent casters");
m->CallTranspModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_CASTER, 0, ERenderMode::SOLID);
m->CallTransparentModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_CASTER, 0, ERenderMode::SOLID);
}
}
@ -770,15 +871,7 @@ void CSceneRenderer::PrepareSubmissions(
CShaderDefines context = m->globalContext;
// Prepare model renderers
{
PROFILE3("prepare models");
m->Model.NormalSkinned->PrepareModels(deviceCommandContext);
m->Model.TranspSkinned->PrepareModels(deviceCommandContext);
if (m->Model.NormalUnskinned != m->Model.NormalSkinned)
m->Model.NormalUnskinned->PrepareModels(deviceCommandContext);
if (m->Model.TranspUnskinned != m->Model.TranspSkinned)
m->Model.TranspUnskinned->PrepareModels(deviceCommandContext);
}
m->PrepareModels(deviceCommandContext);
m->terrainRenderer.PrepareForRendering();
@ -786,15 +879,7 @@ void CSceneRenderer::PrepareSubmissions(
m->particleRenderer.PrepareForRendering(context);
{
PROFILE3("upload models");
m->Model.NormalSkinned->UploadModels(deviceCommandContext);
m->Model.TranspSkinned->UploadModels(deviceCommandContext);
if (m->Model.NormalUnskinned != m->Model.NormalSkinned)
m->Model.NormalUnskinned->UploadModels(deviceCommandContext);
if (m->Model.TranspUnskinned != m->Model.TranspSkinned)
m->Model.TranspUnskinned->UploadModels(deviceCommandContext);
}
m->UploadModels(deviceCommandContext);
m->overlayRenderer.Upload(deviceCommandContext);
@ -908,13 +993,13 @@ void CSceneRenderer::EndFrame()
m->particleRenderer.EndFrame();
m->silhouetteRenderer.EndFrame();
// Finish model renderers
m->Model.NormalSkinned->EndFrame();
m->Model.TranspSkinned->EndFrame();
if (m->Model.NormalUnskinned != m->Model.NormalSkinned)
m->Model.NormalUnskinned->EndFrame();
if (m->Model.TranspUnskinned != m->Model.TranspSkinned)
m->Model.TranspUnskinned->EndFrame();
for (int cullGroup{0}; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup)
{
m->Model.OpaqueSkinned.submissions[cullGroup].clear();
m->Model.TransparentSkinned.submissions[cullGroup].clear();
m->Model.OpaqueUnskinned.submissions[cullGroup].clear();
m->Model.TransparentUnskinned.submissions[cullGroup].clear();
}
}
void CSceneRenderer::DisplayFrustum(Renderer::Backend::IDeviceCommandContext& deviceCommandContext)
@ -1029,21 +1114,25 @@ void CSceneRenderer::SubmitNonRecursive(CModel* model)
m->shadow.AddShadowCasterBound(cascade, model->GetWorldBounds());
}
bool requiresSkinning = (model->GetModelDef()->GetNumBones() != 0);
const bool requiresSkinning{model->GetModelDef()->GetNumBones() != 0};
ModelVertexRenderer& modelVertexSkinningRenderer{
m->Model.GPUSkinningEnabled
? static_cast<ModelVertexRenderer&>(*m->Model.VertexGPUSkinningShader)
: static_cast<ModelVertexRenderer&>(m->Model.VertexCPUSkinningShader)};
if (model->GetMaterial().UsesAlphaBlending())
{
if (requiresSkinning)
m->Model.TranspSkinned->Submit(m_CurrentCullGroup, model);
m->Submit(m_CurrentCullGroup, modelVertexSkinningRenderer, m->Model.TransparentSkinned, model);
else
m->Model.TranspUnskinned->Submit(m_CurrentCullGroup, model);
m->Submit(m_CurrentCullGroup, m->Model.VertexInstancingShader, m->Model.TransparentUnskinned, model);
}
else
{
if (requiresSkinning)
m->Model.NormalSkinned->Submit(m_CurrentCullGroup, model);
m->Submit(m_CurrentCullGroup, modelVertexSkinningRenderer, m->Model.OpaqueSkinned, model);
else
m->Model.NormalUnskinned->Submit(m_CurrentCullGroup, model);
m->Submit(m_CurrentCullGroup, m->Model.VertexInstancingShader, m->Model.OpaqueUnskinned, model);
}
}

View file

@ -0,0 +1,5 @@
target_sources(ActorEditor
PRIVATE
$<$<PLATFORM_ID:Windows>: ActorEditor.rc> # Caution, the blank before the File is needed
ActorEditor.cpp
)

View file

@ -0,0 +1,15 @@
target_sources(AtlasObject
PRIVATE
AtlasObject.h
AtlasObjectImpl.cpp
AtlasObjectImpl.h
AtlasObjectJS.cpp
AtlasObjectText.cpp
AtlasObjectText.h
AtlasObjectXML.cpp
JSONSpiritInclude.h
)
if(NOT without-tests)
add_subdirectory(tests/)
endif()

View file

@ -0,0 +1,13 @@
cxxtest_add_test(test_atlas_object_xml testAtlasObjectXML.cpp ${CMAKE_CURRENT_LIST_DIR}/test_AtlasObjectXML.h)
target_include_directories(test_atlas_object_xml
PRIVATE
${CMAKE_SOURCE_DIR}/source
${CXXTEST_INCLUDE_DIRS}
)
target_link_libraries(test_atlas_object_xml
PRIVATE
${BUILD_FLAGS_TARGET}
AtlasObject
)

View file

@ -0,0 +1,13 @@
target_sources(AtlasUI
PRIVATE
ActorEditor.cpp
ActorEditor.h
ActorEditorListCtrl.cpp
ActorEditorListCtrl.h
AnimListEditor.cpp
AnimListEditor.h
PropListEditor.cpp
PropListEditor.h
TexListEditor.cpp
TexListEditor.h
)

View file

@ -0,0 +1,5 @@
add_subdirectory(ActorEditor/)
add_subdirectory(CustomControls/)
add_subdirectory(General/)
add_subdirectory(Misc/)
add_subdirectory(ScenarioEditor/)

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
ToolButton.cpp
ToolButton.h
)

View file

@ -0,0 +1,12 @@
add_subdirectory(Buttons/)
add_subdirectory(Canvas/)
add_subdirectory(ColorDialog/)
add_subdirectory(DraggableListCtrl/)
add_subdirectory(EditableListCtrl/)
add_subdirectory(FileHistory/)
add_subdirectory(HighResTimer/)
add_subdirectory(MapDialog/)
add_subdirectory(MapResizeDialog/)
add_subdirectory(SnapSplitterWindow/)
add_subdirectory(VirtualDirTreeCtrl/)
add_subdirectory(Windows/)

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
Canvas.cpp
Canvas.h
)

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
ColorDialog.cpp
ColorDialog.h
)

View file

@ -0,0 +1,7 @@
target_sources(AtlasUI
PRIVATE
DraggableListCtrl.cpp
DraggableListCtrl.h
DraggableListCtrlCommands.cpp
DraggableListCtrlCommands.h
)

View file

@ -0,0 +1,17 @@
target_sources(AtlasUI
PRIVATE
EditableListCtrl.cpp
EditableListCtrl.h
EditableListCtrlCommands.cpp
EditableListCtrlCommands.h
FieldEditCtrl.cpp
FieldEditCtrl.h
ListCtrlValidator.cpp
ListCtrlValidator.h
QuickComboBox.cpp
QuickComboBox.h
QuickFileCtrl.cpp
QuickFileCtrl.h
QuickTextCtrl.cpp
QuickTextCtrl.h
)

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
FileHistory.cpp
FileHistory.h
)

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
HighResTimer.cpp
HighResTimer.h
)

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
MapDialog.cpp
MapDialog.h
)

View file

@ -0,0 +1,7 @@
target_sources(AtlasUI
PRIVATE
MapResizeDialog.cpp
MapResizeDialog.h
PseudoMiniMapPanel.cpp
PseudoMiniMapPanel.h
)

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
SnapSplitterWindow.cpp
SnapSplitterWindow.h
)

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
virtualdirtreectrl.cpp
virtualdirtreectrl.h
)

View file

@ -0,0 +1,7 @@
target_sources(AtlasUI
PRIVATE
AtlasDialog.cpp
AtlasDialog.h
AtlasWindow.cpp
AtlasWindow.h
)

View file

@ -0,0 +1,16 @@
target_sources(AtlasUI
PRIVATE
AtlasClipboard.cpp
AtlasClipboard.h
AtlasEventLoop.cpp
AtlasEventLoop.h
AtlasWindowCommand.cpp
AtlasWindowCommand.h
AtlasWindowCommandProc.cpp
AtlasWindowCommandProc.h
Datafile.cpp
Datafile.h
IAtlasSerialiser.h
Observable.cpp
Observable.h
)

View file

@ -0,0 +1,13 @@
target_sources(AtlasUI
PRIVATE
DLLInterface.cpp
DLLInterface.h
KeyMap.cpp
KeyMap.h
actored.h
precompiled.cpp
precompiled.h
$<$<PLATFORM_ID:Windows>: atlas.rc> # Caution, the blank before the File is needed
)
add_subdirectory(Graphics/)

View file

@ -0,0 +1,12 @@
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
include(GNUInstallDirs)
install(
FILES
${CMAKE_CURRENT_SOURCE_DIR}/ActorEditor.ico
${CMAKE_CURRENT_SOURCE_DIR}/ArchiveViewer.ico
${CMAKE_CURRENT_SOURCE_DIR}/FileConverter.ico
${CMAKE_CURRENT_SOURCE_DIR}/ScenarioEditor.ico
DESTINATION
${CMAKE_INSTALL_DATADIR}/0ad/tools/ActorEditor/icons
)
endif()

View file

@ -0,0 +1,10 @@
target_sources(AtlasUI
PRIVATE
ScenarioEditor.cpp
ScenarioEditor.h
SectionLayout.cpp
SectionLayout.h
)
add_subdirectory(Sections/)
add_subdirectory(Tools/)

View file

@ -0,0 +1,7 @@
add_subdirectory(Cinema/)
add_subdirectory(Common/)
add_subdirectory(Environment/)
add_subdirectory(Map/)
add_subdirectory(Object/)
add_subdirectory(Player/)
add_subdirectory(Terrain/)

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
Cinema.cpp
Cinema.h
)

View file

@ -45,21 +45,15 @@
using AtlasMessage::Shareable;
enum {
ID_PathsDrawing,
ID_PathsList,
ID_AddPath,
ID_DeletePath
};
CinemaSidebar::CinemaSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer)
{
{
auto* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _T("Common settings"));
m_DrawPath = new wxCheckBox(sizer->GetStaticBox(), ID_PathsDrawing, _("Draw all paths"));
m_DrawPath = new wxCheckBox(sizer->GetStaticBox(), wxID_ANY, _("Draw all paths"));
m_DrawPath->SetToolTip(_("Display every cinematic path added to the map"));
m_DrawPath->Bind(wxEVT_CHECKBOX, [this](auto&){ SetPathsDrawing(m_DrawPath->IsChecked()); });
sizer->Add(m_DrawPath, wxSizerFlags().Expand().Border(wxALL, Atlas::Style::STATICBOX_PADDING));
@ -70,20 +64,22 @@ CinemaSidebar::CinemaSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarCo
auto* boxSizer = new wxStaticBoxSizer(wxVERTICAL, this, _T("Paths"));
auto* box = boxSizer->GetStaticBox();
m_PathList = new wxListBox(box, ID_PathsList, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE | wxLB_SORT);
m_PathList = new wxListBox(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE | wxLB_SORT);
auto* deleteButton = new wxButton(box, ID_DeletePath, _("Delete"));
auto* deleteButton = new wxButton(box, wxID_ANY, _("Delete"));
deleteButton->SetToolTip(_T("Delete selected path"));
deleteButton->Bind(wxEVT_BUTTON, [this](auto&){ DeleteSelectedPath(); });
m_NewPathName = new wxTextCtrl(box, wxID_ANY);
auto* newPathName = new wxTextCtrl(box, wxID_ANY);
auto* addButton = new wxButton(box, ID_AddPath, _("Add"));
auto* addButton = new wxButton(box, wxID_ANY, _("Add"));
addButton->Bind(wxEVT_BUTTON, [this, newPathName](auto&){ AddPath(newPathName->GetValue()); newPathName->Clear(); });
wxFlexGridSizer* pathsSizer = new wxFlexGridSizer(1, 5, 5);
pathsSizer->AddGrowableCol(0);
pathsSizer->Add(m_PathList, wxSizerFlags().Proportion(1).Expand());
pathsSizer->Add(deleteButton, wxSizerFlags().Expand());
pathsSizer->Add(m_NewPathName, wxSizerFlags().Expand());
pathsSizer->Add(newPathName, wxSizerFlags().Expand());
pathsSizer->Add(addButton, wxSizerFlags().Expand());
boxSizer->Add(pathsSizer, wxSizerFlags().Expand().Border(wxALL, Atlas::Style::STATICBOX_PADDING));
@ -106,22 +102,21 @@ void CinemaSidebar::OnMapReload()
ReloadPathList();
}
void CinemaSidebar::OnTogglePathsDrawing(wxCommandEvent& evt)
void CinemaSidebar::SetPathsDrawing(const bool enable)
{
POST_COMMAND(SetCinemaPathsDrawing, (evt.IsChecked()));
POST_COMMAND(SetCinemaPathsDrawing, (enable));
}
void CinemaSidebar::OnAddPath(wxCommandEvent&)
void CinemaSidebar::AddPath(wxString name)
{
if (m_NewPathName->GetValue().empty())
if (name.empty())
return;
POST_COMMAND(AddCinemaPath, (m_NewPathName->GetValue().ToStdWstring()));
m_NewPathName->Clear();
POST_COMMAND(AddCinemaPath, (name.ToStdWstring()));
ReloadPathList();
}
void CinemaSidebar::OnDeletePath(wxCommandEvent&)
void CinemaSidebar::DeleteSelectedPath()
{
int index = m_PathList->GetSelection();
if (index < 0)
@ -148,9 +143,3 @@ void CinemaSidebar::ReloadPathList()
m_PathList->SetStringSelection(selection);
}
wxBEGIN_EVENT_TABLE(CinemaSidebar, Sidebar)
EVT_CHECKBOX(ID_PathsDrawing, CinemaSidebar::OnTogglePathsDrawing)
EVT_BUTTON(ID_AddPath, CinemaSidebar::OnAddPath)
EVT_BUTTON(ID_DeletePath, CinemaSidebar::OnDeletePath)
wxEND_EVENT_TABLE();

View file

@ -37,15 +37,12 @@ protected:
void OnFirstDisplay() override;
private:
void OnTogglePathsDrawing(wxCommandEvent& evt);
void OnAddPath(wxCommandEvent& evt);
void OnDeletePath(wxCommandEvent& evt);
void SetPathsDrawing(const bool enable);
void AddPath(wxString name);
void DeleteSelectedPath();
void ReloadPathList();
wxCheckBox* m_DrawPath;
wxListBox* m_PathList;
wxTextCtrl* m_NewPathName;
wxDECLARE_EVENT_TABLE();
};

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
Sidebar.cpp
Sidebar.h
)

View file

@ -0,0 +1,7 @@
target_sources(AtlasUI
PRIVATE
Environment.cpp
Environment.h
LightControl.cpp
LightControl.h
)

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
Map.cpp
Map.h
)

View file

@ -0,0 +1,7 @@
target_sources(AtlasUI
PRIVATE
Object.cpp
Object.h
VariationControl.cpp
VariationControl.h
)

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
Player.cpp
Player.h
)

View file

@ -262,7 +262,7 @@ public:
wxGridSizer* gridSizer = new wxGridSizer(3, 5, 5);
wxButton* cameraSet = new wxButton(cameraSizer->GetStaticBox(), ID_CameraSet, _("Set"), wxDefaultPosition, wxSize(48, -1));
gridSizer->Add(Tooltipped(cameraSet,
_("Set player camera to cameraSizer->GetStaticBox() view")), wxSizerFlags().Expand());
_("Set player camera to this view")), wxSizerFlags().Expand());
wxButton* cameraView = new wxButton(cameraSizer->GetStaticBox(), ID_CameraView, _("View"), wxDefaultPosition, wxSize(48, -1));
cameraView->Enable(false);
gridSizer->Add(Tooltipped(cameraView,

View file

@ -0,0 +1,5 @@
target_sources(AtlasUI
PRIVATE
Terrain.cpp
Terrain.h
)

View file

@ -0,0 +1,17 @@
target_sources(AtlasUI
PRIVATE
ActorViewerTool.cpp
AlterElevation.cpp
FillTerrain.cpp
FlattenElevation.cpp
PaintTerrain.cpp
PickWaterHeight.cpp
PikeElevation.cpp
PlaceObject.cpp
ReplaceTerrain.cpp
SmoothElevation.cpp
TransformObject.cpp
TransformPath.cpp
)
add_subdirectory(Common/)

View file

@ -0,0 +1,11 @@
target_sources(AtlasUI
PRIVATE
Brushes.cpp
Brushes.h
MiscState.cpp
MiscState.h
ObjectSettings.cpp
ObjectSettings.h
Tools.cpp
Tools.h
)

View file

@ -0,0 +1,162 @@
cmake_minimum_required(VERSION 3.25.1...4.0.0)
project(AtlasMisc LANGUAGES CXX)
include(0ad-Functions)
# +++++++++++++++++++++ Project Macros ++++++++++++++++++++
macro(set_atlas_build_flags _target)
target_link_options(${_target}
PRIVATE
$<$<PLATFORM_ID:Linux,FreeBSD>:-fPIC>
$<$<PLATFORM_ID:Linux>:-rdynamic>
)
target_compile_options(${_target}
PRIVATE
$<$<PLATFORM_ID:Linux,FreeBSD>:-fPIC>
$<$<PLATFORM_ID:Linux,Darwin>:-Wno-unused-local-typedefs>
)
target_link_libraries(${_target}
PRIVATE
$<$<PLATFORM_ID:Windows>:winmm delayimp>
)
endmacro()
# +++++++++++++++++++++ Required Packages ++++++++++++++++++
find_package(wxWidgets 3.0.4 REQUIRED COMPONENTS gl xml)
find_package(Iconv 1.0 REQUIRED)
find_package(ZLIB 1.2 REQUIRED)
find_package(LibXml2 2.9 REQUIRED)
find_package(CxxTest 4.4 REQUIRED)
if(UNIX)
find_package(Boost 1.69.0 REQUIRED CONFIG)
find_package(SDL2 2.0.2 REQUIRED)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
include(FindPrebuildLibrary)
find_prebuild_library(Sdl2)
find_prebuild_library(Boost INC_PATH ${0AD_EXT_LIBDIR}/boost/include/)
endif()
# +++++++++++++++++++++ Project Targets ++++++++++++++++++++
add_library(AtlasObject STATIC)
add_library(AtlasUI SHARED)
add_executable(ActorEditor)
# Set Macos Bundle and Windows Window Application
set_target_properties(ActorEditor
PROPERTIES
WIN32_EXECUTABLE $<$<PLATFORM_ID:Windows>:TRUE>
MACOSX_BUNDLE $<$<PLATFORM_ID:Darwin>:TRUE>
)
add_subdirectory(AtlasFrontends/)
add_subdirectory(AtlasObject/)
add_subdirectory(AtlasUI/)
# +++++++++++++++++++++ Set Output Paths +++++++++++++++++++
set_target_properties(AtlasObject
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/binaries/system
)
set_target_properties(AtlasUI
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/binaries/system
)
set_target_properties(ActorEditor
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/binaries/system
)
# +++++++++++++++++++++ AtlasObject ++++++++++++++++++++++++
set_atlas_build_flags(AtlasObject)
target_include_directories(AtlasObject PRIVATE ${CMAKE_SOURCE_DIR}/source)
target_link_libraries(AtlasObject
PRIVATE
${BUILD_FLAGS_TARGET}
$<$<PLATFORM_ID:Linux>:Boost::headers>
$<$<PLATFORM_ID:Windows>:BOOST::headers>
Iconv::Iconv
LibXml2::LibXml2
SDL2::SDL2
)
# +++++++++++++++++++++ AtlasUI ++++++++++++++++++++++++++++
if(NOT without-pch)
add_pch(TARGET AtlasUI PCH_DIR ${PROJECT_SOURCE_DIR}/AtlasUI/Misc)
else()
target_compile_definitions(AtlasUI PRIVATE CONFIG_ENABLE_PCH=0)
set_target_properties(AtlasUI PROPERTIES
DISABLE_PRECOMPILE_HEADERS TRUE
)
target_include_directories(AtlasUI
BEFORE PRIVATE
${PROJECT_SOURCE_DIR}/AtlasUI/Misc
)
endif()
set_atlas_build_flags(AtlasUI)
target_include_directories(AtlasUI PRIVATE ${CMAKE_SOURCE_DIR}/source/)
target_link_libraries(AtlasUI
PRIVATE
${BUILD_FLAGS_TARGET}
LibXml2::LibXml2
Iconv::Iconv
$<$<PLATFORM_ID:Linux>:Boost::headers>
$<$<PLATFORM_ID:Windows>:BOOST::headers>
SDL2::SDL2
ZLIB::ZLIB
AtlasObject
wxWidgets::wxWidgets
)
target_compile_definitions(AtlasUI
PRIVATE
$<$<VERSION_GREATER_EQUAL:${wxWidgets_VERSION},3.3.0>:wxNO_REQUIRE_LITERAL_MSGIDS>
)
# +++++++++++++++++++++ ActorEditor ++++++++++++++++++++++++
target_include_directories(ActorEditor
PRIVATE
${PROJECT_SOURCE_DIR}/
)
target_link_libraries(ActorEditor
PRIVATE
${BUILD_FLAGS_TARGET}
$<$<NOT:$<PLATFORM_ID:Windows>>:AtlasObject>
AtlasUI
)
target_link_options(ActorEditor
PRIVATE
$<$<AND:$<PLATFORM_ID:Windows>,$<STREQUAL:${ARCH},amd64>>:/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df'>
$<$<AND:$<PLATFORM_ID:Windows>,$<STREQUAL:${ARCH},x86>>:/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df'>
$<$<PLATFORM_ID:Darwin>:-arch ${MACOS_ARCH}>
)
target_compile_options(ActorEditor
PRIVATE
$<$<PLATFORM_ID:Darwin>:-arch ${MACOS_ARCH}>
)
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set_target_properties(ActorEditor PROPERTIES
XCODE_ATTRIBUTE_ARCHS ${MACOS_ARCH}
XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET $<$<BOOL:${macosx-version-min}>:${macosx-version-min}>
)
endif()
# get_target_property(win32 ActorEditor WIN32_EXECUTABLE)
# get_target_property(macos ActorEditor MACOSX_BUNDLE)
# file(GENERATE OUTPUT debugexpr.txt CONTENT "${win32} ${macos}" TARGET ActorEditor)
# include(CMakePrintHelpers)
# cmake_print_properties(TARGETS AtlasUI
# PROPERTIES
# # INCLUDE_DIRECTORIES
# # LINK_LIBRARIES
# # COMPILE_OPTIONS
# # COMPILE_DEFINITIONS
# # WIN32_EXECUTABLE
# # MACOSX_BUNDLE
# # IMPORTED_LOCATION
# # INTERFACE_INCLUDE_DIRECTORIES
# # CXX_EXTENSIONS
# # CXX_STANDARD_REQUIRED
# )