Merge branch 'master' into patch-modernize

master
yvt 2021-05-02 23:39:03 +09:00
commit b1022213f3
118 changed files with 9464 additions and 3191 deletions

69
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,69 @@
name: CI
on:
pull_request:
push:
jobs:
build-windows:
name: Build (Windows)
runs-on: windows-2019
steps:
- name: Checkout
uses: actions/checkout@v1
with:
submodules: true
path: openspades
- name: Cache vcpkg and dependencies
uses: actions/cache@v2
with:
path: |
vcpkg/installed
!.git
key: ${{ runner.os }}-${{ hashFiles('vcpkg_x86-windows.txt', '.gitmodules') }}
- name: Bootstrap vcpkg
run: vcpkg/bootstrap-vcpkg.bat
- name: Build dependencies
run: vcpkg/vcpkg install @vcpkg_x86-windows.txt
- name: Build application
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{ runner.workspace }}/openspades.mk
build-type: RelWithDebInfo
configure-options: -A Win32 -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_TOOLCHAIN_FILE=${{ runner.workspace }}/openspades/vcpkg/scripts/buildsystems/vcpkg.cmake -D VCPKG_TARGET_TRIPLET=x86-windows-static
parallel: 8
build-macos:
name: Build (macOS)
runs-on: macos-10.15
steps:
- name: Checkout
uses: actions/checkout@v1
with:
submodules: true
path: openspades
- name: Cache vcpkg and dependencies
uses: actions/cache@v2
with:
path: |
vcpkg/installed
!.git
key: ${{ runner.os }}-${{ hashFiles('vcpkg_x86_64-darwin.txt', '.gitmodules') }}
- name: Bootstrap vcpkg
run: vcpkg/bootstrap-vcpkg.sh
- name: Build dependencies
run: vcpkg/vcpkg install @vcpkg_x86_64-darwin.txt
- name: Build application
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{ runner.workspace }}/openspades.mk
build-type: RelWithDebInfo
configure-options: -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_TOOLCHAIN_FILE=${{ runner.workspace }}/openspades/vcpkg/scripts/buildsystems/vcpkg.cmake -D VCPKG_TARGET_TRIPLET=x64-osx -D CMAKE_OSX_ARCHITECTURES=x86_64
parallel: 8

4
.gitignore vendored
View File

@ -34,10 +34,6 @@ CMakeCache.txt
*CMakeFiles/
*.cmake
# cmake input dir (optional)
Sources/Externals/include/
Sources/Externals/lib/
# mac related
*.DS_Store

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "flatpak/shared-modules"]
path = flatpak/shared-modules
url = https://github.com/flathub/shared-modules.git
[submodule "vcpkg"]
path = vcpkg
url = https://github.com/microsoft/vcpkg.git

View File

@ -1,19 +0,0 @@
language: cpp
dist: xenial
compiler:
- gcc
cache: apt
install:
- sudo apt-get install pkg-config libglew-dev libcurl3-openssl-dev libjpeg-dev libxinerama-dev libxft-dev libsdl2-dev libsdl2-image-dev libfreetype6-dev libopus-dev libopusfile-dev gcc
before_script:
- mkdir openspades.mk
- cd openspades.mk
script:
- cmake -DOPENSPADES_RESOURCES=off ..
- cat CMakeCache.txt
- make -k

View File

@ -9,53 +9,90 @@ set(OPENSPADES_FULL_VERSION "${OpenSpades_VERSION_MAJOR}.${OpenSpades_VERSION_MI
set(OS_BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_PREFIX_PATH Sources/Externals)
if(VCPKG_TARGET_TRIPLET)
set(USE_VCPKG ON)
else()
set(USE_VCPKG OFF)
endif()
# Prefer GLVND OpenGL
if(POLICY CMP0072)
cmake_policy(SET CMP0072 NEW)
endif()
include(cmake/FindSDL2.cmake)
if(NOT SDL2_FOUND)
message(FATAL_ERROR "SDL 2.0 not found, set ENV{SDL2DIR} to point to SDL 2.0, and optionally set the cmake var SDL2_LIBRARY_TEMP to the lib dir")
endif()
if(USE_VCPKG)
find_package(Ogg CONFIG REQUIRED)
find_package(Opus CONFIG REQUIRED)
find_package(sdl2-image CONFIG REQUIRED)
find_package(SDL2 CONFIG REQUIRED)
find_package(freetype CONFIG REQUIRED)
include(cmake/FindSDL2_image.cmake)
if(NOT SDL2_IMAGE_FOUND)
message(FATAL_ERROR "SDL_image 2.0 not found, set ENV{SDL2DIR} to point to SDL 2.0, and optionally set the cmake var SDL2_LIBRARY_TEMP to the lib dir")
endif()
if(NOT APPLE)
find_package(GLEW REQUIRED)
set(GLEW_LIBRARY GLEW::GLEW)
include(FindOpenGL)
if(NOT OPENGL_FOUND AND NOT OPENGL_XMESA_FOUND AND NOT OPENGL_GLU_FOUND)
message(FATAL_ERROR "OpenGL not found, please install it")
endif()
if(NOT APPLE)
include(cmake/FindGLEW2.cmake)
if(NOT GLEW_FOUND)
message(FATAL_ERROR "GLEW not found, please install it and make sure CMake can find it (add it to the PATH)")
find_package(CURL REQUIRED)
set(CURL_LIBRARY CURL::libcurl)
endif()
set(SDL2_LIBRARY SDL2::SDL2main SDL2::SDL2-static)
set(SDL2_IMAGE_LIBRARY SDL2::SDL2_image)
set(FREETYPE_LIBRARIES freetype)
if(APPLE)
# Use system libraries
include(FindOpenGL)
include(FindCURL)
endif()
FIND_LIBRARY(OpusFile_LIBRARY
NAMES opusfile
PATH_SUFFIXES lib64 lib
PATHS ${CMAKE_PREFIX_PATH}
)
else()
include(cmake/FindSDL2.cmake)
if(NOT SDL2_FOUND)
message(FATAL_ERROR "SDL 2.0 not found, set ENV{SDL2DIR} to point to SDL 2.0, and optionally set the cmake var SDL2_LIBRARY_TEMP to the lib dir")
endif()
include(cmake/FindSDL2_image.cmake)
if(NOT SDL2_IMAGE_FOUND)
message(FATAL_ERROR "SDL_image 2.0 not found, set ENV{SDL2DIR} to point to SDL 2.0, and optionally set the cmake var SDL2_LIBRARY_TEMP to the lib dir")
endif()
include(FindOpenGL)
if(NOT OPENGL_FOUND AND NOT OPENGL_XMESA_FOUND AND NOT OPENGL_GLU_FOUND)
message(FATAL_ERROR "OpenGL not found, please install it")
endif()
if(NOT APPLE)
include(cmake/FindGLEW2.cmake)
if(NOT GLEW_FOUND)
message(FATAL_ERROR "GLEW not found, please install it and make sure CMake can find it (add it to the PATH)")
endif()
endif()
include(FindZLIB)
if(NOT ZLIB_FOUND)
message(FATAL_ERROR "ZLIB not found, manually set ZLIB_ROOT in CMake")
endif()
include(FindCURL)
if(NOT CURL_FOUND)
message(FATAL_ERROR "cURL not found, please install it (and make sure it's in your path)")
endif()
include(FindFreetype)
if(NOT FREETYPE_FOUND)
message(FATAL_ERROR "FreeType not found, please install it (and make sure it's in your path)")
endif()
include(cmake/FindOpus.cmake)
if(NOT OpusFile_FOUND)
message(FATAL_ERROR "libopus/libopusfile not found, please install it (and make sure it's in your path)")
endif()
endif()
include(FindZLIB)
if(NOT ZLIB_FOUND)
message(FATAL_ERROR "ZLIB not found, manually set ZLIB_ROOT in CMake")
endif()
include(FindCURL)
if(NOT CURL_FOUND)
message(FATAL_ERROR "cURL not found, please install it (and make sure it's in your path)")
endif()
include(FindFreetype)
if(NOT FREETYPE_FOUND)
message(FATAL_ERROR "FreeType not found, please install it (and make sure it's in your path)")
endif()
include(cmake/FindOpus.cmake)
if(NOT OpusFile_FOUND)
message(FATAL_ERROR "libopus/libopusfile not found, please install it (and make sure it's in your path)")
endif()
if(CMAKE_COMPILER_IS_GNUCXX)
# GCC C++11 support
@ -152,7 +189,9 @@ if(HAS_SOCKLEN_T)
add_definitions(-DHAS_SOCKLEN_T=1)
endif()
option(OPENSPADES_RESOURCES "NO_OPENSPADES_RESOURCES" ON)
option(OPENSPADES_RESOURCES "Build game assets" ON)
option(OPENSPADES_NONFREE_RESOURCES "Download non-GPL game assets" ON)
option(OPENSPADES_YSR "Download YSRSpades (closed-source audio backend; macOS only)" ON)
# note that all paths are without trailing slash
set(OPENSPADES_INSTALL_DOC "share/doc/openspades" CACHE STRING "Directory for installing documentation. ")
@ -193,24 +232,27 @@ endif()
configure_file("${PROJECT_SOURCE_DIR}/OpenSpades.h.in" "${PROJECT_BINARY_DIR}/OpenSpades.h")
configure_file("${PROJECT_SOURCE_DIR}/OpenSpades.rc.in" "${PROJECT_BINARY_DIR}/OpenSpades.rc")
include_directories(BEFORE "${PROJECT_BINARY_DIR}")
include_directories("${SDL2_INCLUDE_DIR}")
include_directories("${SDL2_IMAGE_INCLUDE_DIR}")
if(OPENGL_INCLUDE_DIR)
include_directories("${OPENGL_INCLUDE_DIR}")
if(USE_VCPKG)
include_directories("${PROJECT_SOURCE_DIR}/vcpkg/installed/${VCPKG_TARGET_TRIPLET}/include")
else()
include_directories("${SDL2_INCLUDE_DIR}")
include_directories("${SDL2_IMAGE_INCLUDE_DIR}")
if(OPENGL_INCLUDE_DIR)
include_directories("${OPENGL_INCLUDE_DIR}")
endif()
if(NOT APPLE)
include_directories("${GLEW_INCLUDE_DIR}")
endif()
include_directories("${ZLIB_INCLUDE_DIR}")
include_directories(${CURL_INCLUDE_DIRS})
include_directories(${FREETYPE_INCLUDE_DIRS})
include_directories(${OpusFile_INCLUDE_DIR})
endif()
if(NOT APPLE)
include_directories("${GLEW_INCLUDE_DIR}")
endif()
include_directories("${ZLIB_INCLUDE_DIR}")
include_directories(${CURL_INCLUDE_DIRS})
include_directories(${FREETYPE_INCLUDE_DIRS})
include_directories(${OpusFile_INCLUDE_DIR})
add_subdirectory(Resources)
add_subdirectory(Sources)
if(UNIX)
if(UNIX AND NOT APPLE)
# various texts
INSTALL(FILES AUTHORS LICENSE README.md DESTINATION ${OPENSPADES_INSTALL_DOC}/)
@ -228,15 +270,7 @@ if(UNIX)
if(OPENSPADES_RESOURCES)
# install asset paks (including non-GPL one)
install(FILES
${CMAKE_BINARY_DIR}/Resources/pak000-Nonfree.pak
${CMAKE_BINARY_DIR}/Resources/pak002-Base.pak
${CMAKE_BINARY_DIR}/Resources/pak005-Models.pak
${CMAKE_BINARY_DIR}/Resources/pak010-BaseSkin.pak
${CMAKE_BINARY_DIR}/Resources/pak050-Locales.pak
${CMAKE_BINARY_DIR}/Resources/pak999-References.pak
${CMAKE_BINARY_DIR}/Resources/font-unifont.pak
DESTINATION ${OPENSPADES_INSTALL_RESOURCES})
install(FILES ${PAK_FILES} DESTINATION ${OPENSPADES_INSTALL_RESOURCES})
endif(OPENSPADES_RESOURCES)
# Package info (used for automatic update check)
@ -259,9 +293,50 @@ if(UNIX)
# Currently there is no files in lib/openspades. But if you reading this message in future and want to
# place somewhere libs, binaries or other non-media stuff, place them in lib/openspades. Thank you.
endif(UNIX)
endif(UNIX AND NOT APPLE)
if(APPLE)
# Create a macOS application bundle
set_target_properties(OpenSpades PROPERTIES
MACOSX_BUNDLE ON
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/XSpades/XSpades-Info.plist
MACOSX_BUNDLE_BUNDLE_VERSION ${OPENSPADES_FULL_VERSION}
MACOSX_BUNDLE_LONG_VERSION_STRING ${OPENSPADES_FULL_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENSPADES_FULL_VERSION}
MACOSX_BUNDLE_GUI_IDENTIFIER jp.yvt.openspades
MACOSX_BUNDLE_BUNDLE_NAME OpenSpades)
set(BUNDLE_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Icons/OpenSpades.icns)
list(APPEND BUNDLE_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE)
if(OPENSPADES_RESOURCES)
list(APPEND BUNDLE_RESOURCES ${PAK_FILES})
set_source_files_properties(${PAK_FILES}
PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
add_dependencies(OpenSpades OpenSpades_Resources_DevPaks OpenSpades_Resources)
endif(OPENSPADES_RESOURCES)
list(APPEND BUNDLE_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Resources/PackageInfo.json)
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/Resources/PackageInfo.json
PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
if (OPENSPADES_YSR)
list(APPEND BUNDLE_RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/libysrspades.dylib)
# Download `libysrspades.dylib` automatically
add_dependencies(OpenSpades OpenSpades_YSRSpades_Prebuilt)
add_custom_target(OpenSpades_YSRSpades_Prebuilt ALL COMMENT "Downloading libysrspades.dylib"
DEPENDS ${PROJECT_BINARY_DIR}/libysrspades.dylib)
add_custom_command(
OUTPUT ${PROJECT_BINARY_DIR}/libysrspades.dylib
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMAND
wget -c
https://openspadesmedia.yvt.jp/development-packages/YSRSpades/libysrspades.dylib
)
endif (OPENSPADES_YSR)
set_target_properties(OpenSpades PROPERTIES RESOURCE "${BUNDLE_RESOURCES}")
target_sources(OpenSpades PRIVATE "${BUNDLE_RESOURCES}")
endif(APPLE)
#see http://www.cmake.org/cmake/help/v2.8.11/cpack.html
set(CPACK_PACKAGE_NAME "OpenSpades")

View File

@ -1,17 +0,0 @@
// This header file is provided for the Xcode project.
// In other platforms, please use OpenSpades.h generated by CMake.
#define OpenSpades_VERSION_MAJOR 0
#define OpenSpades_VERSION_MINOR 1
#define OpenSpades_VERSION_REVISION 3
#define OS_STRINGIFY2(x) #x
#define OS_STRINGIFY(x) OS_STRINGIFY2(x)
#define OpenSpades_VER_STR "OpenSpades 0.1.3-rc for OS X"
#define PACKAGE_STRING OpenSpades_VER_STR
/* #undef HAS_OPENAL */
/* #undef RESDIR_DEFINED */
//#define RESDIR ""

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:OpenSpades.xcodeproj">
</FileRef>
</Workspace>

View File

@ -85,41 +85,76 @@ GCC 4.9 / Clang 3.2 or later is recommended because OpenSpades relies on C++11 f
* PowerShell 5.0
* Integrated with Windows 10.
* Older versions are not tested, but might work
* *Visual Studio 2017*
* *Visual Studio 2017* or later
* VS2015 is also supported, but VS2017 is more recommended
* VS2013 is no longer supported, but might work
2. Grab the source code:
* Stable version: https://github.com/yvt/openspades/releases
* Latest development version (0.1.x): https://github.com/yvt/openspades/archive/master.zip
3. Extract or checkout the source
3. Checkout the source
* All examples will assume `E:/Projects/openspades`, update paths in the examples to reflect yours
4. Get (pre-compiled) copies of glew, curl, sdl2 and zlib, and place them in `E:/Projects/openspades/Sources/Externals`
* See the file `E:/Projects/openspades/Sources/Externals/readme.txt` for details and links to pre-compiled sets of libraries for your version of Visual Studio
* Make sure to update all git submodules, e.g., by `git clone ... --recurse-submodules`). Note that the GitHub website's ZIP download currently does not support submodules.
4. Build libraries using vcpkg:
```bat
cd E:/Projects/openspades
vcpkg/bootstrap-vcpkg.bat
vcpkg/vcpkg install @vcpkg_x86-windows.txt
```
5. Run CMake:
* Source: `E:/Projects/openspades`
* Binaries: `E:/Projects/openspades/OpenSpades.msvc`
* Generator:
* For VS2017: `Visual Studio 15 (2017)` (not Win64!)
* For VS2015: `Visual Studio 14 (2015)` (not Win64!)
* For VS2019: `Visual Studio 16 (2019)`
* For VS2017: `Visual Studio 15 (2017)`
* For VS2015: `Visual Studio 14 (2015)`
* Platform: `Win32`
* Toolchain file: `E:/Projects/openspades/vcpkg/scripts/buildsystems/vcpkg.cmake`
* Add a new string entry `VCPKG_TARGET_TRIPLET=x86-windows-static`
6. Open `E:/Projects/openspades/OpenSpades.msvc/OpenSpades.sln` in Visual Studio.
7. Build the solution.
* The recommended build configuration is `MinSizeRel` or `Release` if you're not an developer
* The default build output directory is `E:/projects/OpenSpades/OpenSpades.msvc/bin/BUILD_TYPE/`
8. Copy all `.dll` files from `Source/Externals/lib` to the build output directory.
9. To get audio working, download a [Windows release of OpenSpades](https://github.com/yvt/openspades/releases), extract it, and copy the following dlls to the build output directory:
8. To get audio working, download a [Windows release of OpenSpades](https://github.com/yvt/openspades/releases), extract it, and copy the following dlls to the build output directory:
* For OpenAL audio: `openal32.dll`
* For YSR audio: `YSRSpades.dll`, `libgcc_s_dw2-1.dll`, `libstdc++-6.dll`, `pthreadGC2.dll`
10. Download the [Non-free pak](https://github.com/yvt/openspades-paks/releases/download/r33/OpenSpadesDevPackage-r33.zip), extract it, and copy `Nonfree/pak000-Nonfree.pak` to the `Resources` folder inside your build output directory, which is probably `E:/Projects/openspades/openspades.msvc/bin/BUILD_TYPE/Resources`. You can also copy the paks contained in `Official Mods/` folder of OpenSpades 0.0.12b to add more fonts and improve localization support of your build.
11. Copy `Resources/PackageInfo.json` to the `Resources` folder inside your build output directory.
9. Download the [Non-free pak](https://github.com/yvt/openspades-paks/releases/download/r33/OpenSpadesDevPackage-r33.zip), extract it, and copy `Nonfree/pak000-Nonfree.pak` to the `Resources` folder inside your build output directory, which is probably `E:/Projects/openspades/openspades.msvc/bin/BUILD_TYPE/Resources`. You can also copy the paks contained in `Official Mods/` folder of OpenSpades 0.0.12b to add more fonts and improve localization support of your build.
### On macOS (with Xcode)
1. Get the latest version of Xcode and OpenSpades source.
2. Get (pre-compiled) copies of libraries, and place them in `Sources/Externals`
* See the file `Sources/Externals/readme.txt` for details
4. Download [macOS release of OpenSpades](https://github.com/yvt/openspades/releases), show the package contents, and copy `libysrspades.dylib` to `Sources/Externals/lib`.
5. Download and extract the [Non-free pak](https://github.com/yvt/openspades-paks/releases/download/r33/OpenSpadesDevPackage-r33.zip). After that, copy `Nonfree/pak000-Nonfree.pak` and `font-unifont.pak` to `Resources/`.
6. Open `OpenSpades.xcodeproj` and build.
### On macOS (with Ninja)
1. Get the latest version of Xcode and the OpenSpades source code. Install the following prerequisites:
- Xcode's command-line tools. Install them by `xcode-select --install` and `sudo xcodebuild -license`.
- CMake.
- Install `pkg-config` by one of the following methods:
- Homebrew: `brew install pkg-config`
- Nix: add `$(nix-build '<nixpkgs>' -A pkg-config-unwrapped --no-out-link)/bin` to `PATH`.
2. `vcpkg/bootstrap-vcpkg.sh`
3. `vcpkg/vcpkg install @vcpkg_x86_64-darwin.txt`
4. Create directory `openspades.mk` in the cloned/downloaded openspades repo and compile:
```bash
mkdir openspades.mk
cd openspades.mk
cmake -G Ninja .. -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_OSX_ARCHITECTURES=x86_64 -D CMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -D VCPKG_TARGET_TRIPLET=x64-osx
ninja
```
5. Launch:
```bash
open bin/OpenSpades.app
```
(Universal builds aren't supported yet.)
### Network usage during building
OpenSpades' build process automatically downloads prebuilt game assets and libraries as needed. Specifically:
- `pak000-Nonfree.pak` and `font-uniform.pak` from <https://github.com/yvt/openspades-paks>. Can be disabled by passing `-D OPENSPADES_NONFREE_RESOURCES=NO` to CMake.
- The prebuilt binaries of YSRSpades (audio engine) from <https://github.com/yvt/openspades-media>. Can be disabled by passing `-D OPENSPADES_YSR=NO` to CMake.
In addition, vcpkg (sort of package manager only used for Windows and macOS builds) [collects and sends telemetry data to Microsoft](https://vcpkg.readthedocs.io/en/latest/about/privacy/). You can opt out of this behavior by passing `-disableMetrics` option when running `vcpkg/bootstrap-vcpkg.sh` command.
## Troubleshooting
For troubleshooting and common problems see [TROUBLESHOOTING](TROUBLESHOOTING.md).

View File

@ -1,57 +1,117 @@
set(COMPILED_PAK_FILES
${CMAKE_CURRENT_BINARY_DIR}/pak002-Base.pak
${CMAKE_CURRENT_BINARY_DIR}/pak005-Models.pak
${CMAKE_CURRENT_BINARY_DIR}/pak010-BaseSkin.pak
${CMAKE_CURRENT_BINARY_DIR}/pak050-Locales.pak
${CMAKE_CURRENT_BINARY_DIR}/pak999-References.pak)
if(OPENSPADES_RESOURCES AND OPENSPADES_NONFREE_RESOURCES)
set(NONFREE_PAK_FILES
${CMAKE_CURRENT_BINARY_DIR}/pak000-Nonfree.pak
${CMAKE_CURRENT_BINARY_DIR}/font-unifont.pak)
endif(OPENSPADES_NONFREE_RESOURCES)
set(PAK_FILES
${COMPILED_PAK_FILES}
${NONFREE_PAK_FILES}
PARENT_SCOPE)
if(OPENSPADES_RESOURCES)
if(OPENSPADES_NONFREE_RESOURCES)
if (WIN32)
# No automatic downloading for Windows (for now)
elseif (UNIX)
add_custom_target(OpenSpades_Resources_DevPaks ALL COMMENT "Downloading non-GPL assets"
DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/pak000-Nonfree.pak
${CMAKE_CURRENT_BINARY_DIR}/font-unifont.pak)
add_custom_command(
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/downloadpak.sh
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/pak000-Nonfree.pak
${CMAKE_CURRENT_BINARY_DIR}/font-unifont.pak
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
endif(OPENSPADES_NONFREE_RESOURCES)
if (WIN32)
# No automatic downloading for Windows (for now)
elseif (UNIX)
add_custom_target(OpenSpades_Resources_DevPaks ALL COMMENT "Downloading non-GPL assets")
add_custom_command(
TARGET OpenSpades_Resources_DevPaks
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/downloadpak.sh
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
# TODO: subgroups for script files
file(GLOB_RECURSE GFX_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Gfx/*)
file(GLOB_RECURSE LICENSE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/License/*)
file(GLOB_RECURSE LOCALE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Locales/*)
file(GLOB_RECURSE MAP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Maps/*.vxl)
file(GLOB_RECURSE MODEL_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Models/*)
file(GLOB_RECURSE SCRIPT_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Scripts/*.as)
file(GLOB_RECURSE SHADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Shaders/*.fs
${CMAKE_CURRENT_SOURCE_DIR}/Shaders/*.program
${CMAKE_CURRENT_SOURCE_DIR}/Shaders/*.vs)
file(GLOB_RECURSE SOUND_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Sounds/*)
file(GLOB_RECURSE TEXTURE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Textures/*)
set(PAK_IN_FILES
${GFX_FILES} ${LICENSE_FILES} ${LOCALE_FILES} ${MAP_FILES}
${MODEL_FILES} ${SCRIPT_FILES} ${SHADER_FILES} ${SOUND_FILES}
${TEXTURE_FILES})
set(PACKAGE_INFO_IN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/PackageInfo.json)
set(PACKAGE_INFO_OUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/PackageInfo.json)
source_group("Gfx" FILES ${GFX_FILES})
source_group("License Texts" FILES ${LICENSE_FILES})
source_group("Translations" FILES ${LOCALE_FILES})
source_group("Maps" FILES ${MAP_FILES})
source_group("Models" FILES ${MODEL_FILES})
source_group("Scripts" FILES ${SCRIPT_FILES})
source_group("Shaders" FILES ${SHADER_FILES})
source_group("Sounds" FILES ${SOUND_FILES})
source_group("Textures" FILES ${TEXTURE_FILES})
add_custom_target(OpenSpades_Resources ALL
COMMENT "Packing assets"
SOURCES ${SCRIPT_FILES} ${SHADER_FILES}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR})
COMMENT "Building assets"
SOURCES ${PAK_IN_FILES} ${PACKAGE_INFO_IN_FILE}
DEPENDS
${PACKAGE_INFO_OUT_FILE}
${COMPILED_PAK_FILES})
if(WIN32)
if(MSVC)
# multi-config
add_custom_command(
TARGET OpenSpades_Resources
COMMAND powershell -ExecutionPolicy Bypass ${CMAKE_CURRENT_SOURCE_DIR}/mkpak.ps1
${CMAKE_BINARY_DIR}/bin/$<CONFIGURATION>/Resources
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
else()
add_custom_command(
TARGET OpenSpades_Resources
COMMAND powershell -ExecutionPolicy Bypass ${CMAKE_CURRENT_SOURCE_DIR}/mkpak.ps1
${CMAKE_BINARY_DIR}/bin/Resources
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
add_custom_command(
OUTPUT ${COMPILED_PAK_FILES}
COMMAND powershell -ExecutionPolicy Bypass
${CMAKE_CURRENT_SOURCE_DIR}/mkpak.ps1
${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Building paks"
DEPENDS ${PAK_IN_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/mkpak.ps1
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
elseif (UNIX)
add_custom_command(
TARGET OpenSpades_Resources
OUTPUT ${COMPILED_PAK_FILES}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/mkpak.sh
COMMENT "Building paks"
DEPENDS ${PAK_IN_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/mkpak.sh
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/PackageInfo.json
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
add_custom_command(
OUTPUT ${PACKAGE_INFO_OUT_FILE}
DEPENDS ${PACKAGE_INFO_IN_FILE}
COMMENT "Copying PackageInfo.json"
COMMAND ${CMAKE_COMMAND} -E copy
${PACKAGE_INFO_IN_FILE} ${PACKAGE_INFO_OUT_FILE})
if (WIN32 AND MSVC)
# copy the output files to the multi-config binary directory
# (you can't use generator expressions (`$<...>`) in `add_custom_command`'s
# `OUTPUT` parameter; it's not supported by CMake.)
add_custom_command(
TARGET OpenSpades_Resources POST_BUILD
COMMENT "Copying assets to the currently-selected configuration's build directory"
COMMAND
${CMAKE_COMMAND} -E make_directory
${CMAKE_BINARY_DIR}/bin/$<CONFIGURATION>/Resources
COMMAND
${CMAKE_COMMAND} -E copy_if_different
${COMPILED_PAK_FILES} ${PACKAGE_INFO_OUT_FILE}
${CMAKE_BINARY_DIR}/bin/$<CONFIGURATION>/Resources)
endif (WIN32 AND MSVC)
endif()
if(UNIX)
if(UNIX AND NOT APPLE)
add_custom_target(OpenSpades_Unix ALL COMMENT "Process unix stuff")
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Icons)
@ -77,4 +137,4 @@ if(UNIX)
COMMAND sh -c \"gzip -9 -c ${CMAKE_CURRENT_BINARY_DIR}/Unix/Man/openspades.6 > openspades.6.gz\"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Unix/Man
)
endif(UNIX)
endif(UNIX AND NOT APPLE)

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2017-12-31 04:46-0500\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: openspades\n"
@ -1761,35 +1761,35 @@ msgstr "Automatische Suche nach Aktualisierung ist nicht verfügbar."
#: Sources/Client/Client_NetHandler.cpp:271
msgctxt "Client"
msgid "Spectator"
msgstr ""
msgstr "Zuschauer"
#: Sources/Client/Client_Draw.cpp:99
msgctxt "Client"
msgid "Unbound"
msgstr ""
msgstr "Unbelegt"
#: Sources/Client/Client_Draw.cpp:655
msgctxt "Client"
msgid "[{0}] Cycle camera mode"
msgstr ""
msgstr "[{0}] Kameramodus wechseln"
#: Sources/Client/Client_Draw.cpp:657
msgctxt "Client"
msgid "[{0}/{1}] Next/previous player"
msgstr ""
msgstr "[{0}/{1}] Nächster/Vorheriger Spieler"
#: Sources/Client/Client_Draw.cpp:661
msgctxt "Client"
msgid "[{0}] Unfollow"
msgstr ""
msgstr "[{0}] Nicht mehr folgen"
#: Sources/Client/Client_Draw.cpp:664
msgctxt "Client"
msgid "[{0}/{1}] Follow a player"
msgstr ""
msgstr "[{0}/{1}] Einem Spieler folgen"
#: Sources/Client/Client_Draw.cpp:669
msgctxt "Client"
msgid "[{0}/{1}] Go up/down"
msgstr ""
msgstr "[{0}/{1}] Gehe hoch/runter"

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2019-01-01 05:55\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Greek\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: openspades\n"

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2019-01-01 05:55\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Spanish\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: openspades\n"
@ -256,7 +256,7 @@ msgstr "Granada"
#: Sources/Client/Client_Update.cpp:860 Sources/Client/Client_Update.cpp:886
msgctxt "Client"
msgid "Headshot"
msgstr "Disparos en la Cabeza"
msgstr "Disparo en la Cabeza"
#. ! A cause of death shown in the kill feed.
#: Sources/Client/Client_Update.cpp:864 Sources/Client/Client_Update.cpp:890
@ -268,7 +268,7 @@ msgstr "Cambio de equipo"
#: Sources/Client/Client_Update.cpp:868 Sources/Client/Client_Update.cpp:894
msgctxt "Client"
msgid "Weapon Change"
msgstr "Cambiar arma"
msgstr "Cambio de arma"
#: Sources/Client/Client_Update.cpp:907 Sources/Client/Client_Update.cpp:933
msgctxt "Client"
@ -810,7 +810,7 @@ msgstr "Sangre"
#: Resources/Scripts/Gui/Preferences.as:644
msgctxt "Preferences"
msgid "Ejecting Brass"
msgstr ""
msgstr "Eyectar cartuchos de bala"
#: Resources/Scripts/Gui/Preferences.as:645
#: Resources/Scripts/Gui/Preferences.as:645
@ -1186,7 +1186,7 @@ msgstr "Avanzado"
#: Resources/Scripts/Gui/StartupScreen.as:288
msgctxt "StartupScreen"
msgid "An unknown error has occurred while opening the update info website."
msgstr "Un error desconocido ha ocurrido mientras se abria el directorio de configuraciones."
msgstr "Un error desconocido ha ocurrido mientras se abría el sitio web de información de actualización."
#: Resources/Scripts/Gui/StartupScreen.as:853
#: Resources/Scripts/Gui/StartupScreen.as:853
@ -1689,7 +1689,7 @@ msgstr "Desconocido ({0})"
#: Resources/Scripts/Gui/StartupScreen.as:1764
msgctxt "StartupScreen"
msgid "System default"
msgstr "Predeterminado"
msgstr "Predeterminado por el sistema"
#: Resources/Scripts/Gui/StartupScreen.as:1813
#: Resources/Scripts/Gui/StartupScreen.as:1813
@ -1725,7 +1725,7 @@ msgstr "Mostrar detalles..."
#: Resources/Scripts/Gui/UpdateCheckView.as:102
msgctxt "UpdateCheck"
msgid "Version {0} is available! (You currently have {1})"
msgstr "¡Una nueva versión {0} está disponible! (Actualmente tienes la {1})"
msgstr "¡La nueva versión {0} está disponible! (Actualmente tienes la {1})"
#: Resources/Scripts/Gui/UpdateCheckView.as:105
#: Resources/Scripts/Gui/UpdateCheckView.as:105
@ -1743,19 +1743,19 @@ msgstr "Buscando actualizaciones..."
#: Resources/Scripts/Gui/UpdateCheckView.as:113
msgctxt "UpdateCheck"
msgid "Failed to check for updates."
msgstr "No se ha podido buscar actualizaciones."
msgstr "Búsqueda de actualizaciones fallida."
#: Resources/Scripts/Gui/UpdateCheckView.as:116
#: Resources/Scripts/Gui/UpdateCheckView.as:116
msgctxt "UpdateCheck"
msgid "Automatic update check is not enabled."
msgstr "Las actualizaciones automáticas no están habilitada."
msgstr "La comprobación automática de nuevas actualizaciones no está habilitada."
#: Resources/Scripts/Gui/UpdateCheckView.as:119
#: Resources/Scripts/Gui/UpdateCheckView.as:119
msgctxt "UpdateCheck"
msgid "Automatic update check is not available."
msgstr "Las actualizaciones automáticas no están disponibles."
msgstr "La comprobación automática de nuevas actualizaciones no está disponible."
#: Sources/Client/Client_NetHandler.cpp:258
#: Sources/Client/Client_NetHandler.cpp:271
@ -1771,12 +1771,12 @@ msgstr "Sin Asignar"
#: Sources/Client/Client_Draw.cpp:655
msgctxt "Client"
msgid "[{0}] Cycle camera mode"
msgstr "[{0}] Cambiar punto de vista"
msgstr "[{0}] Vista en 3ra persona"
#: Sources/Client/Client_Draw.cpp:657
msgctxt "Client"
msgid "[{0}/{1}] Next/previous player"
msgstr "[{0}/{1}] Próximo jugador/anterior"
msgstr "[{0}/{1}] Siguiente/anterior jugador"
#: Sources/Client/Client_Draw.cpp:661
msgctxt "Client"

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2017-12-31 04:46-0500\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Crowdin-Project: openspades\n"

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2019-01-01 05:55\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Hungarian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: openspades\n"
@ -95,7 +95,7 @@ msgstr "Nyomj [{0}]-t az újratöltéshez"
#: Sources/Client/Client_Draw.cpp:584 Sources/Client/Client_Draw.cpp:608
msgctxt "Client"
msgid "You will respawn in: {0}"
msgstr "{0} mp. múlva újra fogsz éledni"
msgstr "{0} másodperc múlva újra fogsz éledni"
#: Sources/Client/Client_Draw.cpp:586 Sources/Client/Client_Draw.cpp:610
msgctxt "Client"
@ -245,7 +245,7 @@ msgstr "Esés"
#: Sources/Client/Client_Update.cpp:853 Sources/Client/Client_Update.cpp:879
msgctxt "Client"
msgid "Melee"
msgstr ""
msgstr "Közelharc"
#: Sources/Client/Client_Update.cpp:856 Sources/Client/Client_Update.cpp:882
msgctxt "Client"
@ -293,7 +293,7 @@ msgstr "Nem tehetsz oda blokkot."
#: Sources/Client/LimboView.cpp:79 Sources/Client/LimboView.cpp:79
msgctxt "Client"
msgid "Spawn"
msgstr ""
msgstr "Játékba lépés"
#: Sources/Client/LimboView.cpp:183 Sources/Client/LimboView.cpp:183
msgctxt "Client"
@ -1264,7 +1264,7 @@ msgid "Antialias:Enables a technique to improve the appearance of high-contrast
"FXAA: Performs antialiasing by smoothing artifacts out as a post-process.|Off|MSAA 2x|4x|FXAA"
msgstr "Antialias: Javítja a magas kontrasztú élek megjelenítését.\n\n"
"MSAA: Antialiasingot végez egy köztes magas felbontású kép generálásával. Ez néz ki a legjobban, de bizonyos beállításokkal nem működik megfelelően.\n\n"
"FXAA: Antialiasingot végez utómunkálatként a kép elsimításával.|Off|MSAA 2x|4x|FXAA"
"FXAA: Antialiasingot végez utómunkálatként a kép elsimításával.|Nincs|MSAA 2x|4x|FXAA"
#: Resources/Scripts/Gui/StartupScreen.as:1150
#: Resources/Scripts/Gui/StartupScreen.as:1150
@ -1288,7 +1288,7 @@ msgstr "Lineáris HDR renderelés"
#: Resources/Scripts/Gui/StartupScreen.as:1157
msgctxt "StartupScreen"
msgid "Uses a number representation which allows wider dynamic range during rendering process. Additionally, this allows color calculation whose value is in linear correspondence with actual energy, that is, physically accurate blending can be achieved."
msgstr "Számábrázolás segítségével nagyobb dinamikus tartományt tud elérni a renderelés alatt. Továbbá, ez lehetővé teszi az energiájuktól lineárisan függő színek kiszámítását, ezzel fizikailag pontos keverést elérve."
msgstr "Nagyobb dinamikus tartomány elérését lehetővé tévő számábrázolást használ a renderelés közben. Továbbá, ez lehetővé teszi az energiájuktól lineárisan függő színek kiszámítását, ezzel fizikailag pontos színkeverést elérve."
#: Resources/Scripts/Gui/StartupScreen.as:1164
#: Resources/Scripts/Gui/StartupScreen.as:1164
@ -1438,7 +1438,7 @@ msgstr "Az utófeldolgozásnak köszönhetően a kép jobban és élethűbben n
#: Resources/Scripts/Gui/StartupScreen.as:1203
msgctxt "StartupScreen"
msgid "Particles|Low:Artifact occurs when a particle intersects other objects.|Medium:Particle intersects objects smoothly.|High:Particle intersects objects smoothly, and some objects casts their shadow to particles."
msgstr ""
msgstr "Részecskék|Alacsony:Maradványok láthatók, amikor egy részecske ütközik objektumokkal.|Közepes:A részecskék és objektumok ütközése egyenletes.|Magas:A részecskék és objektumok ütközése egyenletes, és bizonyos objektumok árnyékot vetnek a részecskékre."
#: Resources/Scripts/Gui/StartupScreen.as:1213
#: Resources/Scripts/Gui/StartupScreen.as:1213
@ -1450,7 +1450,7 @@ msgstr "Dinamikus fények"
#: Resources/Scripts/Gui/StartupScreen.as:1215
msgctxt "StartupScreen"
msgid "Gives some objects an ability to emit light to give them an energy-emitting impression."
msgstr ""
msgstr "Lehetővé teszi, hogy bizonyos tárgyak fényt bocsássanak ki, hogy energiakibocsátás benyomását keltsék."
#: Resources/Scripts/Gui/StartupScreen.as:1218
#: Resources/Scripts/Gui/StartupScreen.as:1218
@ -1510,7 +1510,7 @@ msgstr "Víz shader | Nincs: A víz a többi blokkhoz hasonlóan kerül megrajzo
#: Resources/Scripts/Gui/StartupScreen.as:1251
msgctxt "StartupScreen"
msgid "Med"
msgstr ""
msgstr "Közepes"
#: Resources/Scripts/Gui/StartupScreen.as:1256
#: Resources/Scripts/Gui/StartupScreen.as:1256
@ -1558,7 +1558,7 @@ msgstr "YSR"
#: Resources/Scripts/Gui/StartupScreen.as:1512
msgctxt "StartupScreen"
msgid "YSR is an experimental 3D HDR sound engine optimized for OpenSpades. It features several enhanced features including automatic load control, dynamics compressor, HRTF-based 3D audio, and high quality reverb."
msgstr "A YSR egy kísérleti 3D HDR hangot előállító, OpenSpades-re optimalizált szoftver. Több javított funkciót is tartalmaz, mint automatikus terheléselosztó, dinamikus kompresszor, HRTF alapú 3D hang, és magas minőségű visszhang."
msgstr "A YSR egy kísérleti 3D HDR hangot előállító, OpenSpades-re optimalizált szoftver. Több javított funkciót is tartalmaz, mint automatikus terheléselosztás, dinamikai kopresszor, HRTF alapú 3D hang, és magas minőségű visszhang."
#. ! The name of audio driver that outputs no audio.
#: Resources/Scripts/Gui/StartupScreen.as:1523
@ -1597,7 +1597,7 @@ msgstr "EAX"
#: Resources/Scripts/Gui/StartupScreen.as:1547
msgctxt "StartupScreen"
msgid "Enables extended features provided by the OpenAL driver to create more ambience."
msgstr ""
msgstr "Engedélyezi az OpenAL driver által nyújtott extra funkciókat a jobb hangzás érdekében."
#: Resources/Scripts/Gui/StartupScreen.as:1563
#: Resources/Scripts/Gui/StartupScreen.as:1563
@ -1633,7 +1633,7 @@ msgstr "Konfigurációs mappa megnyitása"
#: Resources/Scripts/Gui/StartupScreen.as:1649
msgctxt "StartupScreen"
msgid "Reveal Config Folder in Finder"
msgstr ""
msgstr "Konfigurációs mappa megnyitása a fájlkezelőben"
#: Resources/Scripts/Gui/StartupScreen.as:1651
#: Resources/Scripts/Gui/StartupScreen.as:1651
@ -1725,7 +1725,7 @@ msgstr "Részletek mutatása..."
#: Resources/Scripts/Gui/UpdateCheckView.as:102
msgctxt "UpdateCheck"
msgid "Version {0} is available! (You currently have {1})"
msgstr "A verzió {0} elérhető! (Jelenlegi verzió: {1})"
msgstr "A {0} verzió elérhető! (Jelenlegi verzió: {1})"
#: Resources/Scripts/Gui/UpdateCheckView.as:105
#: Resources/Scripts/Gui/UpdateCheckView.as:105

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2019-01-01 06:00\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: openspades\n"

View File

@ -0,0 +1,4 @@
{
"descriptionEnglish": "Italian",
"description": "Italiano"
}

File diff suppressed because it is too large Load Diff

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2017-12-31 04:46-0500\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Japanese\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: openspades\n"

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2017-12-31 04:46-0500\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: openspades\n"

View File

@ -0,0 +1,4 @@
{
"descriptionEnglish": "Lithuanian",
"description": "lietuvių kalba"
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
{
"descriptionEnglish": "Norwegian Bokmål",
"description": "Norsk Bokmål"
}

File diff suppressed because it is too large Load Diff

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2019-01-01 05:55\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: openspades\n"

View File

@ -3,15 +3,15 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2017-12-31 04:46-0500\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Polish\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
"X-Crowdin-Project: openspades\n"
"X-Crowdin-Language: pl\n"
"X-Crowdin-File: openspades.pot\n"
@ -211,7 +211,8 @@ msgid "{0} block"
msgid_plural "{0} blocks"
msgstr[0] "blok"
msgstr[1] "bloki"
msgstr[2] "bloków"
msgstr[2] ""
msgstr[3] "bloków"
#: Sources/Client/Client_Update.cpp:486 Sources/Client/Client_Update.cpp:512
msgctxt "Client"
@ -388,7 +389,8 @@ msgid "Spectator{1}"
msgid_plural "Spectators{1}"
msgstr[0] "Obserwator{1}"
msgstr[1] "Obserwatorzy{1}"
msgstr[2] "Obserwatorzy{1}"
msgstr[2] ""
msgstr[3] "Obserwatorzy{1}"
#: Sources/Client/TCProgressView.cpp:151 Sources/Client/TCProgressView.cpp:151
msgctxt "Client"

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2017-12-31 04:46-0500\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Portuguese, Brazilian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: openspades\n"

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2017-12-31 04:46-0500\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Portuguese\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: openspades\n"

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2019-01-01 05:55\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
"X-Crowdin-Project: openspades\n"

View File

@ -0,0 +1,4 @@
{
"descriptionEnglish": "Turkish",
"description": "Türkçe"
}

File diff suppressed because it is too large Load Diff

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2019-01-01 05:55\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Ukrainian\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
"X-Crowdin-Project: openspades\n"

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2019-01-01 05:55\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Vietnamese\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: openspades\n"

View File

@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: openspades\n"
"Report-Msgid-Bugs-To: i at yvt.jp\n"
"POT-Creation-Date: 2016-12-25 23:47-0200\n"
"PO-Revision-Date: 2019-01-01 05:55\n"
"Last-Translator: yvt <i@yvt.jp>\n"
"PO-Revision-Date: 2020-04-19 14:46\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Chinese Simplified\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: crowdin.com\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Crowdin-Project: openspades\n"

View File

@ -113,6 +113,7 @@ namespace spades {
{
StartupScreenConfigView cfg(Manager);
// TODO: Add r_temporalAA when it's more complete
cfg.AddRow(StartupScreenConfigSelectItemEditor(
ui, StartupScreenGraphicsAntialiasConfig(ui), "0|2|4|fxaa",
_Tr("StartupScreen",

View File

@ -71,7 +71,6 @@ void main() {
vec3 fixedPosition = chunkPosition;
fixedPosition += fixedPositionAttribute * 0.5;
fixedPosition += normalAttribute * 0.1;
vec3 normal = normalAttribute;
vec3 shadowVertexPos = vertexPos.xyz;

View File

@ -80,7 +80,6 @@ void main() {
vec3 fixedPosition = chunkPosition;
fixedPosition += fixedPositionAttribute * 0.5;
fixedPosition += normalAttribute * 0.1;
vec3 normal = normalAttribute;
vec3 shadowVertexPos = vertexPos.xyz;

View File

@ -33,13 +33,19 @@ float decodeDepth(float w, float near, float far){
}
void main() {
float centerDepth = texture2D(depthTexture, texCoord).x;
if (centerDepth >= 0.999999) {
float centerDepthRaw = texture2D(depthTexture, texCoord).x;
// A tangent at `texCoord` in `depthTexture`
float centerDepthRawDfdx = dFdx(centerDepthRaw);
float centerDepthRawDfdy = dFdy(centerDepthRaw);
float centerDepthRawDfdi =
dot(vec2(centerDepthRawDfdx, centerDepthRawDfdy), unitShift / vec2(dFdx(texCoord.x), dFdy(texCoord.y)));
if (centerDepthRaw >= 0.999999) {
// skip background
gl_FragColor = vec4(1.0);
return;
}
centerDepth = decodeDepth(centerDepth, zNearFar.x, zNearFar.y);
vec2 sum = vec2(0.0000001);
if (isUpsampling) {
@ -47,6 +53,10 @@ void main() {
inputOriginCoord *= pixelShift.xy * 2.0;
for (float i = -4.0; i <= 4.0; i += 2.0) {
// Extrapolate the depth value using the tangent
float centerDepthRawInterpolated = centerDepthRaw + centerDepthRawDfdi * i;
float centerDepth = decodeDepth(centerDepthRawInterpolated, zNearFar.x, zNearFar.y);
vec2 sampledCoord = inputOriginCoord + unitShift * i;
float sampledDepth = texture2D(depthTexture, sampledCoord).x;
sampledDepth = decodeDepth(sampledDepth, zNearFar.x, zNearFar.y);
@ -61,6 +71,10 @@ void main() {
} else {
for (float i = -4.0; i <= 4.0; i += 1.0) {
// Extrapolate the depth value using the tangent
float centerDepthRawInterpolated = centerDepthRaw + centerDepthRawDfdi * i;
float centerDepth = decodeDepth(centerDepthRawInterpolated, zNearFar.x, zNearFar.y);
vec2 sampledCoord = texCoord + unitShift * i;
float sampledDepth = texture2D(depthTexture, sampledCoord).x;
sampledDepth = decodeDepth(sampledDepth, zNearFar.x, zNearFar.y);

View File

@ -20,22 +20,93 @@
uniform sampler2D mainTexture;
uniform sampler2D blurredTexture;
varying vec2 texCoord;
uniform float enhancement;
uniform float saturation;
uniform vec3 tint;
uniform float sharpening;
uniform float sharpeningFinalGain;
uniform float blurPixelShift;
vec3 acesToneMapping(vec3 x)
{
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
}
// 1/(dacesToneMapping(x)/dx)
float acesToneMappingDiffRcp(float color) {
float denom = 0.0576132 + color * (0.242798 + color);
return (denom * denom) / (0.0007112 + color * (0.11902 + color * 0.238446));
}
void main() {
// Input is in the device color space
gl_FragColor = texture2D(mainTexture, texCoord);
if (sharpeningFinalGain > 0.0) {
// generated by ./1dgaussGen.rb
// pixelShift is texture coord shift / texture pixel
float pixelShift = blurPixelShift;
float shift1 = pixelShift * -2.30654399138844;
const float scale1 = 0.178704407070903;
float shift2 = pixelShift * -0.629455560633963;
const float scale2 = 0.321295592929097;
float shift3 = pixelShift * 0.629455560633963;
const float scale3 = 0.321295592929097;
float shift4 = pixelShift * 2.30654399138844;
const float scale4 = 0.178704407070903;
vec4 blurred = texture2D(blurredTexture, texCoord + vec2(0.0, shift1)) * scale1;
blurred += texture2D(blurredTexture, texCoord + vec2(0.0, shift2)) * scale2;
blurred += texture2D(blurredTexture, texCoord + vec2(0.0, shift3)) * scale3;
blurred += texture2D(blurredTexture, texCoord + vec2(0.0, shift4)) * scale4;
// `sharpening` tells to what extent we must enhance the edges based on
// global factors.
float enhancingFactor = sharpening;
#if USE_HDR
// Now we take the derivative of `acesToneMapping` into consideration.
// Specifially, when `acesToneMapping` reduces the color contrast
// around the current pixel by N times, we compensate by scaling
// `enhancingFactor` by N.
float localLuminance = dot(blurred.xyz, vec3(1. / 3.));
float localLuminanceLinear = clamp(localLuminance * localLuminance, 0.0, 1.0);
enhancingFactor *= acesToneMappingDiffRcp(localLuminanceLinear * 0.8);
// We don't want specular highlights to cause black edges, so weaken the
// effect if the local luminance is high.
localLuminance = max(localLuminance, dot(gl_FragColor.xyz, vec3(1. / 3.)));
if (localLuminance > 1.0) {
localLuminance -= 1.0;
enhancingFactor *= 1.0 - (localLuminance + localLuminance * localLuminance) * 100.0;
}
#endif
// Clamp the sharpening effect's intensity.
enhancingFactor = clamp(enhancingFactor, 1.0, 4.0);
// Derive the value of `localSharpening` that achieves the desired
// contrast enhancement. When `sharpeningFinalGain = 1`, the sharpening
// effect multiplies the color contrast exactly by `enhancingFactor`.
float localSharpening = (enhancingFactor - 1.0) * sharpeningFinalGain;
// Given a parameter value `localSharpening`, the sharpening kernel defined
// in here enhances the color difference across a horizontal or vertical
// edge by the following factor:
//
// r_sharp = 1 + localSharpening
// Sharpening is done by reversing the effect of the blur kernel.
// Clamp the lower bound to suppress the black edges around specular highlights.
vec3 lowerBound = gl_FragColor.xyz * 0.6;
gl_FragColor.xyz += (gl_FragColor.xyz - blurred.xyz) * localSharpening;
gl_FragColor.xyz = max(gl_FragColor.xyz, lowerBound);
}
// Apply tinting and manual exposure
gl_FragColor.xyz *= tint;
vec3 gray = vec3(dot(gl_FragColor.xyz, vec3(1. / 3.)));

View File

@ -0,0 +1,88 @@
/*
Copyright (c) 2021 yvt
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This bi-cubic spline interpolation code is based on
*
* http://www.dannyruijters.nl/cubicinterpolation/
* https://github.com/DannyRuijters/CubicInterpolationCUDA
*
* @license Copyright (c) 2008-2013, Danny Ruijters. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*/
void bspline_weights(vec2 fraction, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3) {
vec2 one_frac = 1.0 - fraction;
vec2 squared = fraction * fraction;
vec2 one_sqd = one_frac * one_frac;
w0 = 1.0 / 6.0 * one_sqd * one_frac;
w1 = 2.0 / 3.0 - 0.5 * squared * (2.0 - fraction);
w2 = 2.0 / 3.0 - 0.5 * one_sqd * (2.0 - one_frac);
w3 = 1.0 / 6.0 * squared * fraction;
}
vec3 cubicTex2D(sampler2D tex, vec2 coord, vec2 inverseTexSize) {
// transform the coordinate from [0,extent] to [-0.5, extent-0.5]
vec2 coord_grid = coord - 0.5;
vec2 index = floor(coord_grid);
vec2 fraction = coord_grid - index;
vec2 w0, w1, w2, w3;
bspline_weights(fraction, w0, w1, w2, w3);
vec2 g0 = w0 + w1;
vec2 g1 = w2 + w3;
vec2 h0 =
(w1 / g0) - vec2(0.5) + index; // h0 = w1/g0 - 1, move from [-0.5, extent-0.5] to [0, extent]
vec2 h1 =
(w3 / g1) + vec2(1.5) + index; // h1 = w3/g1 + 1, move from [-0.5, extent-0.5] to [0, extent]
// fetch the four linear interpolations
vec3 tex00 = texture2D(tex, vec2(h0.x, h0.y) * inverseTexSize).xyz;
vec3 tex10 = texture2D(tex, vec2(h1.x, h0.y) * inverseTexSize).xyz;
vec3 tex01 = texture2D(tex, vec2(h0.x, h1.y) * inverseTexSize).xyz;
vec3 tex11 = texture2D(tex, vec2(h1.x, h1.y) * inverseTexSize).xyz;
// weigh along the y-direction
tex00 = g0.y * tex00 + g1.y * tex01;
tex10 = g0.y * tex10 + g1.y * tex11;
// weigh along the x-direction
return (g0.x * tex00 + g1.x * tex10);
}
uniform sampler2D mainTexture;
uniform vec2 inverseVP;
varying vec2 texCoord;
void main() {
gl_FragColor.xyz = cubicTex2D(mainTexture, texCoord, inverseVP);
gl_FragColor.w = 1.0;
}

View File

@ -0,0 +1,2 @@
Shaders/PostFilters/ResampleBicubic.fs
Shaders/PostFilters/ResampleBicubic.vs

View File

@ -0,0 +1,32 @@
/*
Copyright (c) 2021 yvt
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
attribute vec2 positionAttribute;
varying vec2 texCoord;
uniform vec2 inverseVP;
void main() {
vec2 scrPos = positionAttribute * 2. - 1.;
gl_Position = vec4(scrPos, 0.5, 1.);
texCoord = positionAttribute / inverseVP;
}

View File

@ -0,0 +1,133 @@
/*
Copyright (c) 2017 yvt
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
uniform sampler2D inputTexture;
uniform sampler2D depthTexture;
uniform sampler2D previousTexture;
uniform sampler2D processedInputTexture;
uniform vec2 inverseVP;
uniform mat4 reprojectionMatrix;
varying vec2 texCoord;
/* UE4-style temporal AA. Implementation is based on my ShaderToy submission */
// YUV-RGB conversion routine from Hyper3D
vec3 encodePalYuv(vec3 rgb)
{
return vec3(
dot(rgb, vec3(0.299, 0.587, 0.114)),
dot(rgb, vec3(-0.14713, -0.28886, 0.436)),
dot(rgb, vec3(0.615, -0.51499, -0.10001))
);
}
vec3 decodePalYuv(vec3 yuv)
{
return vec3(
dot(yuv, vec3(1., 0., 1.13983)),
dot(yuv, vec3(1., -0.39465, -0.58060)),
dot(yuv, vec3(1., 2.03211, 0.))
);
}
void main() {
// ------------------------------------------------------------------------
// Reprojection
//
// Calulate the Z position of the current pixel. Take the minimum Z value
// of the neighboring pixels to preserve the antialiasing of foreground
// objects.
vec2 off = inverseVP;
float inputZ0 = texture2D(depthTexture, texCoord).x;
float inputZ1 = texture2D(depthTexture, texCoord + vec2(+off.x, 0.0)).x;
float inputZ2 = texture2D(depthTexture, texCoord + vec2(-off.x, 0.0)).x;
float inputZ3 = texture2D(depthTexture, texCoord + vec2(0.0, +off.y)).x;
float inputZ4 = texture2D(depthTexture, texCoord + vec2(0.0, -off.y)).x;
float inputZ5 = texture2D(depthTexture, texCoord + vec2(+off.x, +off.y)).x;
float inputZ6 = texture2D(depthTexture, texCoord + vec2(-off.x, +off.y)).x;
float inputZ7 = texture2D(depthTexture, texCoord + vec2(+off.x, -off.y)).x;
float inputZ8 = texture2D(depthTexture, texCoord + vec2(-off.x, -off.y)).x;
float inputZ = min(min(min(inputZ0, inputZ1), min(inputZ2, inputZ3)),
min(min(inputZ4, inputZ5), min(inputZ6, min(inputZ7, inputZ8))));
// Predict where the point was in the previous frame. The Z range [0, 0.1]
// is for a view weapon, so assume no movement in this range.
vec4 reprojectedTexCoord;
if (inputZ < 0.1) {
reprojectedTexCoord.xy = texCoord.xy;
} else {
reprojectedTexCoord = reprojectionMatrix * vec4(texCoord, inputZ, 1.0);
reprojectedTexCoord.xy /= reprojectedTexCoord.w;
}
vec4 lastColor = texture2D(previousTexture, reprojectedTexCoord.xy);
// ------------------------------------------------------------------------
vec3 antialiased = lastColor.xyz;
float mixRate = min(lastColor.w, 0.5);
vec3 in0 = texture2D(processedInputTexture, texCoord).xyz;
antialiased = mix(antialiased, in0, mixRate);
vec3 in1 = texture2D(inputTexture, texCoord + vec2(+off.x, 0.0)).xyz;
vec3 in2 = texture2D(inputTexture, texCoord + vec2(-off.x, 0.0)).xyz;
vec3 in3 = texture2D(inputTexture, texCoord + vec2(0.0, +off.y)).xyz;
vec3 in4 = texture2D(inputTexture, texCoord + vec2(0.0, -off.y)).xyz;
vec3 in5 = texture2D(inputTexture, texCoord + vec2(+off.x, +off.y)).xyz;
vec3 in6 = texture2D(inputTexture, texCoord + vec2(-off.x, +off.y)).xyz;
vec3 in7 = texture2D(inputTexture, texCoord + vec2(+off.x, -off.y)).xyz;
vec3 in8 = texture2D(inputTexture, texCoord + vec2(-off.x, -off.y)).xyz;
antialiased = encodePalYuv(antialiased);
in0 = encodePalYuv(in0);
in1 = encodePalYuv(in1);
in2 = encodePalYuv(in2);
in3 = encodePalYuv(in3);
in4 = encodePalYuv(in4);
in5 = encodePalYuv(in5);
in6 = encodePalYuv(in6);
in7 = encodePalYuv(in7);
in8 = encodePalYuv(in8);
vec3 minColor = min(min(min(in0, in1), min(in2, in3)), in4);
vec3 maxColor = max(max(max(in0, in1), max(in2, in3)), in4);
minColor = mix(minColor,
min(min(min(in5, in6), min(in7, in8)), minColor), 0.5);
maxColor = mix(maxColor,
max(max(max(in5, in6), max(in7, in8)), maxColor), 0.5);
vec3 preclamping = antialiased;
antialiased = clamp(antialiased, minColor, maxColor);
mixRate = 1.0 / (1.0 / mixRate + 1.0);
vec3 diff = abs(antialiased - preclamping);
float clampAmount = max(max(diff.x, diff.y), diff.z);
mixRate += clampAmount * 8.0;
mixRate = clamp(mixRate, 0.05, 0.5);
antialiased = decodePalYuv(antialiased);
gl_FragColor = vec4(max(antialiased, vec3(0.0)), mixRate);
}

View File

@ -0,0 +1,2 @@
Shaders/PostFilters/TemporalAA.fs
Shaders/PostFilters/TemporalAA.vs

View File

@ -0,0 +1,36 @@
/*
Copyright (c) 2017 yvt
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
attribute vec2 positionAttribute;
varying vec2 texCoord;
void main() {
vec2 pos = positionAttribute;
vec2 scrPos = pos * 2. - 1.;
gl_Position = vec4(scrPos, 0.5, 1.);
texCoord = pos;
}

View File

@ -1,21 +1,21 @@
/*
Copyright (c) 2013 yvt
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
@ -23,6 +23,7 @@
void PrepareForShadow_Map(vec3 vertexCoord, vec3 normal) ;
void PrepareForShadow_Model(vec3 vertexCoord, vec3 normal);
void PrepareForRadiosity_Map(vec3 vertexCoord, vec3 normal);
void PrepareForRadiosityForMap_Map(vec3 vertexCoord, vec3 centerCoord, vec3 normal);
void PrepareForShadow(vec3 vertexCoord, vec3 normal) {
PrepareForShadow_Map(vertexCoord, normal);
@ -30,9 +31,9 @@ void PrepareForShadow(vec3 vertexCoord, vec3 normal) {
PrepareForRadiosity_Map(vertexCoord, normal);
}
// map uses specialized shadow coordinate calculation to avoid glitch
void PrepareForShadowForMap(vec3 vertexCoord, vec3 fixedVertexCoord, vec3 normal) {
PrepareForShadow_Map(fixedVertexCoord, normal);
void PrepareForShadowForMap(vec3 vertexCoord, vec3 centerCoord, vec3 normal) {
// map uses specialized shadow coordinate calculation to avoid glitch
PrepareForShadow_Map(centerCoord + normal * 0.1, normal);
PrepareForShadow_Model(vertexCoord, normal);
PrepareForRadiosity_Map(vertexCoord, normal);
PrepareForRadiosityForMap_Map(vertexCoord, centerCoord, normal);
}

View File

@ -58,7 +58,8 @@ vec3 Radiosity_Map(float detailAmbientOcclusion, float ssao) {
detailAmbientOcclusion *= ssao;
// ambient occlusion
float amb = texture3D(ambientShadowTexture, ambientShadowTextureCoord).x;
vec2 ambTexVal = texture3D(ambientShadowTexture, ambientShadowTextureCoord).xy;
float amb = ambTexVal.x / max(ambTexVal.y, 0.25);
amb = max(amb, 0.); // for some reason, mainTexture value becomes negative
// mix ambient occlusion values generated by two different methods somehow

View File

@ -1,33 +1,80 @@
/*
Copyright (c) 2013 yvt
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
/**** CPU RADIOSITY (FASTER?) *****/
uniform sampler3D ambientShadowTexture;
varying vec3 radiosityTextureCoord;
varying vec3 ambientShadowTextureCoord;
varying vec3 normalVarying;
void PrepareForRadiosity_Map(vec3 vertexCoord, vec3 normal) {
radiosityTextureCoord = (vertexCoord + vec3(0., 0., 0.)) / vec3(512., 512., 64.);
ambientShadowTextureCoord = (vertexCoord + vec3(0.5, 0.5, 1.5)) / vec3(512., 512., 65.);
ambientShadowTextureCoord = (vertexCoord + vec3(0., 0., 1.)) / vec3(512., 512., 65.);
normalVarying = normal;
}
void PrepareForRadiosityForMap_Map(vec3 vertexCoord, vec3 centerCoord, vec3 normal) {
radiosityTextureCoord = (vertexCoord + vec3(0., 0., 0.)) / vec3(512., 512., 64.);
ambientShadowTextureCoord = (vertexCoord + vec3(0., 0., 1.) + normal * 0.5) / vec3(512., 512., 65.);
vec3 centerAST = (centerCoord + vec3(0., 0., 1.) + normal * 0.5) / vec3(512., 512., 65.);
vec3 rel = vertexCoord - centerCoord;
vec3 relAST = rel * 2.0 / vec3(512., 512., 65.);
// Detect the following pattern:
//
// +-----+-----+
// |#####| |
// |#####| |
// |#####| |
// +-----+-----+
// | V|#####|
// | C |#####|
// | |#####|
// +-----+-----+
//
// C = centerCoord, V = vertexCoord, # = covered by a solid voxel
//
float weightSum;
if (normal.x != 0.0) {
weightSum = texture3D(ambientShadowTexture, centerAST + vec3(0.0, relAST.y, 0.0)).y +
texture3D(ambientShadowTexture, centerAST + vec3(0.0, 0.0, relAST.z)).y -
texture3D(ambientShadowTexture, centerAST + vec3(0.0, relAST.y, relAST.z)).y;
} else if (normal.y != 0.0) {
weightSum = texture3D(ambientShadowTexture, centerAST + vec3(relAST.x, 0.0, 0.0)).y +
texture3D(ambientShadowTexture, centerAST + vec3(0.0, 0.0, relAST.z)).y -
texture3D(ambientShadowTexture, centerAST + vec3(relAST.x, 0.0, relAST.z)).y;
} else {
weightSum = texture3D(ambientShadowTexture, centerAST + vec3(relAST.x, 0.0, 0.0)).y +
texture3D(ambientShadowTexture, centerAST + vec3(0.0, relAST.y, 0.0)).y -
texture3D(ambientShadowTexture, centerAST + vec3(relAST.x, relAST.y, 0.0)).y;
}
// Hide the light leaks by corners by modifying the AO texture coordinates
if (weightSum < -0.5) {
radiosityTextureCoord -= rel / vec3(512., 512., 64.);
ambientShadowTextureCoord = centerAST;
}
normalVarying = normal;
}

View File

@ -59,7 +59,8 @@ vec3 Radiosity_Map(float detailAmbientOcclusion, float ssao) {
detailAmbientOcclusion *= ssao;
// ambient occlusion
float amb = texture3D(ambientShadowTexture, ambientShadowTextureCoord).x;
vec2 ambTexVal = texture3D(ambientShadowTexture, ambientShadowTextureCoord).xy;
float amb = ambTexVal.x / (ambTexVal.y + 1.0e-12);
amb = max(amb, 0.); // by some reason, mainTexture value becomes negative
// mix ambient occlusion values generated by two different methods somehow

View File

@ -24,3 +24,7 @@ void PrepareForRadiosity_Map(vec3 vertexCoord, vec3 normal) {
hemisphereLighting = 1. - normal.z * .2;
}
void PrepareForRadiosityForMap_Map(vec3 vertexCoord, vec3 centerCoord, vec3 normal) {
hemisphereLighting = 1. - normal.z * .2;
}

View File

@ -29,7 +29,7 @@ if [ -f "$PAK_NAME" ]; then
fi
wget "$PAK_URL" -O "$PAK_NAME"
unzip -u -o "$PAK_NAME" -d "$OUTPUT_DIR"
unzip -o "$PAK_NAME" -d "$OUTPUT_DIR"
# relocate paks to the proper location
mv "$OUTPUT_DIR/Nonfree/pak000-Nonfree.pak" "$OUTPUT_DIR/"

View File

@ -664,7 +664,7 @@ void CScriptArray::RemoveRange(asUINT start, asUINT count)
// Compact the elements
// As objects in arrays of objects are not stored inline, it is safe to use memmove here
// since we're just copying the pointers to objects and not the actual objects.
memcpy(buffer->data + start*elementSize, buffer->data + (start + count)*elementSize, (buffer->numElements - count)*elementSize);
memmove(buffer->data + start*elementSize, buffer->data + (start + count)*elementSize, (buffer->numElements - count)*elementSize);
buffer->numElements -= count;
}

View File

@ -938,7 +938,7 @@
#endif
// Free BSD
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__)
#define AS_BSD
#if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__)
#undef COMPLEX_MASK
@ -947,7 +947,7 @@
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY)
#define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
#define AS_X86
#elif defined(__LP64__)
#elif defined(__LP64__) && !defined(__sparc64__)
#define AS_X64_GCC
#define HAS_128_BIT_PRIMITIVES
#define SPLIT_OBJS_BY_MEMBER_TYPES
@ -1079,15 +1079,23 @@
// Haiku OS
#elif __HAIKU__
#define AS_HAIKU
// Only x86-32 is currently supported by Haiku, but they do plan to support
// x86-64 and PowerPC in the future, so should go ahead and check the platform
// for future compatibility
#if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__)
#define AS_X86
#define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
#define CDECL_RETURN_SIMPLE_IN_MEMORY
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
#elif defined(__x86_64__)
#define AS_X64_GCC
#define HAS_128_BIT_PRIMITIVES
#undef COMPLEX_MASK
#define COMPLEX_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR)
#undef COMPLEX_RETURN_MASK
#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR)
#define AS_LARGE_OBJS_PASSED_BY_REF
#define AS_LARGE_OBJ_MIN_SIZE 5
#undef STDCALL
#define STDCALL
#else
#define AS_MAX_PORTABILITY
#endif

View File

@ -38,7 +38,7 @@
#include <stdlib.h>
#if !defined(__APPLE__) && !defined(__SNC__) && !defined(__ghs__) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
#if !defined(__APPLE__) && !defined(__SNC__) && !defined(__ghs__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__)
#include <malloc.h>
#endif

View File

@ -47,6 +47,31 @@ set_target_properties(OpenSpades PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BIN
set_target_properties(OpenSpades PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set_target_properties(OpenSpades PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
if(APPLE OR WIN32)
# This value is reflected to the macOS application bundle's name, so use
# the correct capitalization.
# We also want the correct capitalization on Windows.
set_target_properties(OpenSpades PROPERTIES OUTPUT_NAME OpenSpades)
else(APPLE)
set_target_properties(OpenSpades PROPERTIES OUTPUT_NAME openspades)
endif(APPLE)
if (APPLE)
# The built pak files are copied into the macOS application bundle. CMake
# won't copy unless they are included in the target's source files.
#
# Since they are specified as `add_custom_command`'s output files, so they
# have the `GENERATED` property. However, `GENERATED` is a directory-local
# property (until [cmake!5308] lands in CMake 3.20). This means it needs to
# be set again here.
#
# [cmake!5308]: https://gitlab.kitware.com/cmake/cmake/-/merge_requests/5308
set_source_files_properties(${PAK_FILES} PROPERTIES GENERATED 1)
# The same goes for `libysrspades.dylib`.
set_source_files_properties(${PROJECT_BINARY_DIR}/libysrspades.dylib PROPERTIES GENERATED 1)
endif(APPLE)
if(WIN32)
# Use a single output directory for all configs
# (Without this, the generated binary cannot find pak files created by mkpak.ps1 unless
@ -101,6 +126,9 @@ target_link_libraries(OpenSpades ${SDL2_LIBRARY} ${SDL2_IMAGE_LIBRARY} ${OPENGL_
if(NOT APPLE)
target_link_libraries(OpenSpades ${GLEW_LIBRARY})
endif()
if(USE_VCPKG)
target_link_libraries(OpenSpades Ogg::ogg Opus::opus)
endif()
#todo: MACOSX_BUNDLE_ICON_FILE ?
@ -117,7 +145,11 @@ endif()
if(UNIX)
if(NOT(CMAKE_SYSTEM_NAME MATCHES "BSD" OR APPLE))
target_link_libraries(OpenSpades rt)
if (NOT CMAKE_SYSTEM_NAME MATCHES "Haiku")
target_link_libraries(OpenSpades rt)
else()
target_link_libraries(OpenSpades network)
endif()
endif()
target_link_libraries(OpenSpades pthread)
endif()

View File

@ -44,5 +44,12 @@ namespace spades {
auto &team = teams[player.GetTeamId()];
return team.hasIntel && team.carrier == player.GetId();
}
void CTFGameMode::ResetTeamScoreAndIntelHoldingStatus() {
for (Team &team : teams) {
team.score = 0;
team.hasIntel = false;
}
}
} // namespace client
} // namespace spades

View File

@ -53,6 +53,14 @@ namespace spades {
void SetCaptureLimit(int v) { captureLimit = v; }
bool PlayerHasIntel(World &world, Player &player);
/**
* Resets both team score and the holding status of both flags.
*
* This is what the vanila client does upon receiving a winning
* `IntelCapture`.
*/
void ResetTeamScoreAndIntelHoldingStatus();
};
} // namespace client
} // namespace spades

View File

@ -422,7 +422,7 @@ namespace spades {
{
float scale = dt;
Vector3 vel = player.GetVelocty();
Vector3 vel = player.GetVelocity();
Vector3 front = player.GetFront();
Vector3 right = player.GetRight();
Vector3 up = player.GetUp();
@ -698,8 +698,9 @@ namespace spades {
{
float sp = 1.f - aimDownState;
sp *= .3f;
sp *= std::min(1.f, p.GetVelocty().GetLength() * 5.f);
viewWeaponOffset.x += sinf(p.GetWalkAnimationProgress() * M_PI * 2.f) * 0.013f * sp;
sp *= std::min(1.f, p.GetVelocity().GetLength() * 5.f);
viewWeaponOffset.x +=
sinf(p.GetWalkAnimationProgress() * M_PI * 2.f) * 0.013f * sp;
float vl = cosf(p.GetWalkAnimationProgress() * M_PI * 2.f);
vl *= vl;
viewWeaponOffset.z += vl * 0.018f * sp;
@ -897,11 +898,11 @@ namespace spades {
Matrix4 leg2 = Matrix4::Translate(0.25f, 0.2f, -0.1f);
float ang = sinf(p.GetWalkAnimationProgress() * M_PI * 2.f) * 0.6f;
float walkVel = Vector3::Dot(p.GetVelocty(), p.GetFront2D()) * 4.f;
float walkVel = Vector3::Dot(p.GetVelocity(), p.GetFront2D()) * 4.f;
leg1 = leg1 * Matrix4::Rotate(MakeVector3(1, 0, 0), ang * walkVel);
leg2 = leg2 * Matrix4::Rotate(MakeVector3(1, 0, 0), -ang * walkVel);
walkVel = Vector3::Dot(p.GetVelocty(), p.GetRight()) * 3.f;
walkVel = Vector3::Dot(p.GetVelocity(), p.GetRight()) * 3.f;
leg1 = leg1 * Matrix4::Rotate(MakeVector3(0, 1, 0), ang * walkVel);
leg2 = leg2 * Matrix4::Rotate(MakeVector3(0, 1, 0), -ang * walkVel);
@ -931,11 +932,11 @@ namespace spades {
Matrix4 leg2 = Matrix4::Translate(0.25f, 0.f, -0.1f);
float ang = sinf(p.GetWalkAnimationProgress() * M_PI * 2.f) * 0.6f;
float walkVel = Vector3::Dot(p.GetVelocty(), p.GetFront2D()) * 4.f;
float walkVel = Vector3::Dot(p.GetVelocity(), p.GetFront2D()) * 4.f;
leg1 = leg1 * Matrix4::Rotate(MakeVector3(1, 0, 0), ang * walkVel);
leg2 = leg2 * Matrix4::Rotate(MakeVector3(1, 0, 0), -ang * walkVel);
walkVel = Vector3::Dot(p.GetVelocty(), p.GetRight()) * 3.f;
walkVel = Vector3::Dot(p.GetVelocity(), p.GetRight()) * 3.f;
leg1 = leg1 * Matrix4::Rotate(MakeVector3(0, 1, 0), ang * walkVel);
leg2 = leg2 * Matrix4::Rotate(MakeVector3(0, 1, 0), -ang * walkVel);

View File

@ -439,7 +439,8 @@ namespace spades {
weapInput.secondary = down;
}
if (world->GetLocalPlayer()->IsToolWeapon() && weapInput.secondary &&
!lastVal && world->GetLocalPlayer()->IsReadyToUseTool() &&
!lastVal &&
world->GetLocalPlayer()->GetWeapon().TimeToNextFire() <= 0 &&
!world->GetLocalPlayer()->GetWeapon().IsReloading() &&
GetSprintState() == 0.0f) {
AudioParam params;

View File

@ -712,7 +712,7 @@ namespace spades {
return Vector3::Dot(result.hitPos - origin, lastSceneDef.viewAxis[2]);
}
return std::nan(nullptr);
return NAN;
}
} // namespace client
} // namespace spades

View File

@ -388,7 +388,7 @@ namespace spades {
PlayerInput inp = playerInput;
WeaponInput winp = weapInput;
Vector3 velocity = player.GetVelocty();
Vector3 velocity = player.GetVelocity();
Vector3 horizontalVelocity{velocity.x, velocity.y, 0.0f};
if (horizontalVelocity.GetLength() < 0.1f) {
@ -448,7 +448,7 @@ namespace spades {
hasDelayedReload = false;
}
// PlayerInput actualInput = player->GetInput();
// PlayerInput actualInput = player.GetInput();
WeaponInput actualWeapInput = player.GetWeaponInput();
if (!(actualWeapInput.secondary && player.IsToolWeapon() && player.IsAlive()) &&
@ -859,7 +859,7 @@ namespace spades {
} else if (kt == KillTypeGrenade) {
corp->AddImpulse(MakeVector3(0, 0, -4.f - SampleRandomFloat() * 4.f));
}
corp->AddImpulse(victim.GetVelocty() * 32.f);
corp->AddImpulse(victim.GetVelocity() * 32.f);
corpses.emplace_back(std::move(corp));
if (corpses.size() > corpseHardLimit) {

View File

@ -33,8 +33,6 @@
#include <Draw/SWPort.h>
#include <Draw/SWRenderer.h>
SPADES_SETTING(cg_smp);
namespace spades {
namespace client {
class HitTestDebugger::Port : public draw::SWPort {
@ -141,8 +139,7 @@ namespace spades {
def.fovX = def.fovY = range;
// we cannot change GameMap's listener in the client thread with SMP renderer
def.skipWorld = ((int)cg_smp != 0);
def.skipWorld = false;
def.zNear = 0.05f;
def.zFar = 200.f;

View File

@ -87,6 +87,7 @@ namespace spades {
PacketTypeWeaponReload = 28, // C2S2P
PacketTypeChangeTeam = 29, // C2S2P
PacketTypeChangeWeapon = 30, // C2S2P
PacketTypeMapCached = 31, // S2C
PacketTypeHandShakeInit = 31, // S2C
PacketTypeHandShakeReturn = 32, // C2S
PacketTypeVersionGet = 33, // S2C
@ -1285,6 +1286,16 @@ namespace spades {
} break;
case PacketTypeMapStart: {
// next map!
if (protocolVersion == 4) {
// The AoS 0.76 protocol allows the client to load a map from a local cache
// if possible. After receiving MapStart, the client should respond with
// MapCached to indicate whether the map with a given checksum exists in the
// cache or not. We don't implement a local cache, so we always ask the
// server to send fresh map data.
NetPacketWriter wri(PacketTypeMapCached);
wri.Write((uint8_t)0);
enet_peer_send(peer, 0, wri.CreatePacket());
}
client->SetWorld(NULL);
auto mapSize = reader.ReadInt();
@ -1397,8 +1408,10 @@ namespace spades {
ctf.GetTeam(p.GetTeamId()).score++;
bool winning = reader.ReadByte() != 0;
if (winning)
if (winning) {
ctf.ResetTeamScoreAndIntelHoldingStatus();
client->TeamWon(p.GetTeamId());
}
} break;
case PacketTypeIntelPickup: {
Player &p = GetPlayer(reader.ReadByte());

View File

@ -552,9 +552,8 @@ namespace spades {
SPAssert(map);
if (weapInput.secondary) {
// vanilla behavior (confirmed by measurement)
spread *= 0.5f;
if (!weapInput.secondary) {
spread *= 2;
}
// pyspades takes destroying more than one block as a
@ -648,7 +647,6 @@ namespace spades {
GetHorizontalLength(mapResult.hitPos - muzzle) < hitPlayerDistance)) {
IntVector3 outBlockCoord = mapResult.hitBlock;
// TODO: set correct ray distance
// FIXME: why ray casting twice?
finalHitPos = mapResult.hitPos;
@ -761,17 +759,37 @@ namespace spades {
Vector3 rec = weapon->GetRecoil();
float upLimit = Vector3::Dot(GetFront2D(), o);
upLimit -= 0.03f; // ???
o += GetUp() * std::min(rec.y, std::max(0.f, upLimit)) * (input.crouch ? 0.5f : 1.0f);
// vanilla's horizontial recoil seems to driven by a triangular wave generator.
// the period was measured with SMG
float triWave = world.GetTime() * 0.9788f;
triWave -= std::floor(triWave);
if (triWave < 0.5f) {
triWave = triWave * 4.0f - 1.0f;
// vanilla's horizontial recoil is driven by a triangular wave generator.
int time = (int)(world.GetTime() * 1000);
float triWave;
if (time % 1024 < 512) {
triWave = (time % 512) - 255.5;
} else {
triWave = 3.0f - triWave * 4.0f;
triWave = 255.5 - (time % 512);
}
o += GetRight() * rec.x * triWave * (input.crouch ? 0.5f : 1.0f);
float horzModifier = 1;
float vertModifier = 1;
if ((input.moveLeft || input.moveRight || input.moveForward || input.moveBackward) && !weapInput.secondary) {
horzModifier *= 2;
vertModifier *= 2;
}
if (airborne) {
horzModifier *= 2;
vertModifier *= 2;
}
else if (input.crouch) {
horzModifier /= 2;
vertModifier /= 2;
}
horzModifier *= sqrt(1 - pow(o.z, 4));
o += GetRight() * rec.x * triWave * horzModifier;
o += GetUp() * std::min(rec.y, std::max(0.f, upLimit)) * vertModifier;
o = o.Normalize();
SetOrientation(o);
@ -795,7 +813,7 @@ namespace spades {
vel = MakeVector3(0, 0, 0);
}
vel += GetVelocty();
vel += GetVelocity();
if (this == world.GetLocalPlayer()) {
auto gren = stmp::make_unique<Grenade>(world, muzzle, vel, fuse);

View File

@ -209,7 +209,7 @@ namespace spades {
Vector3 GetUp();
Vector3 GetEye() { return eye; }
Vector3 GetOrigin(); // actually not origin at all!
Vector3 GetVelocty() { return velocity; }
Vector3 GetVelocity() { return velocity; }
int GetMoveSteps() { return moveSteps; }
World &GetWorld() { return world; }

View File

@ -218,9 +218,9 @@ namespace spades {
}
}
Vector3 GetRecoil() override {
return MakeVector3(0.025f, 0.05f, 0.f); // measured
return MakeVector3(0.0001f, 0.05f, 0.f);
}
float GetSpread() override { return 0.012f; } // measured (standing, crouched)
float GetSpread() override { return 0.006f; }
int GetPelletSize() override { return 1; }
};
@ -228,7 +228,7 @@ namespace spades {
public:
SMGWeapon3(World &w, Player &p) : Weapon(w, p) {}
std::string GetName() override { return "SMG"; }
float GetDelay() override { return 0.11f; }
float GetDelay() override { return 0.1f; }
int GetClipSize() override { return 30; }
int GetMaxStock() override { return 120; }
float GetReloadTime() override { return 2.5f; }
@ -240,14 +240,14 @@ namespace spades {
case HitTypeHead: return 75;
case HitTypeArms: return 18;
case HitTypeLegs: return 18;
case HitTypeBlock: return 35;
case HitTypeBlock: return 34;
default: SPAssert(false); return 0;
}
}
Vector3 GetRecoil() override {
return MakeVector3(0.01f, 0.0125f, 0.f); // measured
return MakeVector3(0.00005f, 0.0125f, 0.f);
}
float GetSpread() override { return 0.025f; } // measured (standing, crouched)
float GetSpread() override { return 0.012f; }
int GetPelletSize() override { return 1; }
};
@ -268,14 +268,14 @@ namespace spades {
case HitTypeArms: return 16;
case HitTypeLegs: return 16;
case HitTypeBlock:
// Actually, you cast a hit per pallet. This value is a guess, by the way.
// Actually, you cast a hit per pallet.
// --GM
return 34;
return 22;
default: SPAssert(false); return 0;
}
}
Vector3 GetRecoil() override {
return MakeVector3(0.05f, 0.1f, 0.f); // measured
return MakeVector3(0.0002f, 0.1f, 0.f);
}
float GetSpread() override { return 0.024f; }
int GetPelletSize() override { return 8; }
@ -307,8 +307,7 @@ namespace spades {
}
}
Vector3 GetRecoil() override {
// FIXME: needs to measured
return MakeVector3(0.0001f, 0.075f, 0.f);
return MakeVector3(0.0002f, 0.075f, 0.f);
}
float GetSpread() override { return 0.004f; }
int GetPelletSize() override { return 1; }
@ -330,12 +329,11 @@ namespace spades {
case HitTypeHead: return 75;
case HitTypeArms: return 18;
case HitTypeLegs: return 18;
case HitTypeBlock: return 34;
case HitTypeBlock: return 26;
default: SPAssert(false); return 0;
}
}
Vector3 GetRecoil() override {
// FIXME: needs to measured
return MakeVector3(0.00005f, 0.0125f, 0.f);
}
float GetSpread() override { return 0.012f; }
@ -363,7 +361,6 @@ namespace spades {
}
}
Vector3 GetRecoil() override {
// FIXME: needs to measured
return MakeVector3(0.0002f, 0.075f, 0.f);
}
float GetSpread() override { return 0.036f; }

View File

@ -16,6 +16,10 @@ namespace spades {
std::array<uint32_t, 4> regs;
#ifdef WIN32
__cpuid(reinterpret_cast<int *>(regs.data()), a);
#elif defined(__i386__) && (defined(__pic__) || defined(__PIC__))
asm volatile("mov %%ebx, %%edi\ncpuid\nxchg %%edi, %%ebx\n"
: "=a"(regs[0]), "=D"(regs[1]), "=c"(regs[2]), "=d"(regs[2])
: "a"(a), "c"(0));
#else
asm volatile("cpuid"
: "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3])

View File

@ -21,7 +21,7 @@
#include <cstring>
#include <string>
#include <opusfile.h>
#include <opus/opusfile.h>
#include "OpusAudioStream.h"

View File

@ -89,7 +89,7 @@ namespace spades {
return false;
}
}
#elif __unix || __unix__
#elif (__unix || __unix__) || defined(__HAIKU__)
bool ShowDirectoryInShell(const std::string &directoryPath) {
// FIXME: escape single quotes
if (directoryPath.find("'") != std::string::npos) {

View File

@ -46,6 +46,10 @@ std::string VersionInfo::GetVersionInfo() {
return std::string("FreeBSD");
#elif defined(__OpenBSD__)
return std::string("OpenBSD");
#elif defined(__NetBSD__)
return std::string("NetBSD");
#elif defined(__HAIKU__)
return std::string("Haiku");
#else
return std::string("Unknown OS");
#endif

View File

@ -69,7 +69,7 @@ namespace spades {
for (Chunk &c : chunks) {
float *data = (float *)c.data;
std::fill(data, data + ChunkSize * ChunkSize * ChunkSize, 1.f);
std::fill(data, data + ChunkSize * ChunkSize * ChunkSize * 2, 1.f);
}
for (int x = 0; x < chunkW; x++) {
@ -97,16 +97,16 @@ namespace spades {
device.TexParamater(IGLDevice::Texture3D, IGLDevice::TextureWrapT, IGLDevice::Repeat);
device.TexParamater(IGLDevice::Texture3D, IGLDevice::TextureWrapR,
IGLDevice::ClampToEdge);
device.TexImage3D(IGLDevice::Texture3D, 0, IGLDevice::Red, w, h, d + 1, 0,
IGLDevice::Red, IGLDevice::FloatType, NULL);
device.TexImage3D(IGLDevice::Texture3D, 0, IGLDevice::RG, w, h, d + 1, 0, IGLDevice::RG,
IGLDevice::FloatType, NULL);
SPLog("Chunk texture allocated");
std::vector<float> v;
v.resize(w * h);
v.resize(w * h * 2);
std::fill(v.begin(), v.end(), 1.f);
for (int i = 0; i < d + 1; i++) {
device.TexSubImage3D(IGLDevice::Texture3D, 0, 0, 0, i, w, h, 1, IGLDevice::Red,
device.TexSubImage3D(IGLDevice::Texture3D, 0, 0, 0, i, w, h, 1, IGLDevice::RG,
IGLDevice::FloatType, v.data());
}
@ -124,38 +124,22 @@ namespace spades {
device.DeleteTexture(texture);
}
/**
* Evaluate the AO term at the point specified by given world coordinates.
*/
float GLAmbientShadowRenderer::Evaluate(IntVector3 ipos) {
SPADES_MARK_FUNCTION_DEBUG();
float sum = 0;
float sum = 0.0f;
Vector3 pos = MakeVector3((float)ipos.x, (float)ipos.y, (float)ipos.z);
pos.x += 0.5f;
pos.y += 0.5f;
pos.z += 0.5f;
float muzzleDiff = 0.02f;
for (int i = 0; i < NumRays; i++) {
Vector3 dir = rays[i];
// check allowed ray direction
uint8_t directions[8] = {0, 1, 2, 3, 4, 5, 6, 7};
int numDirections = 0;
for (int x = -1; x <= 0; x++)
for (int y = -1; y <= 0; y++)
for (int z = -1; z <= 0; z++) {
if (!map->IsSolidWrapped(ipos.x + x, ipos.y + y, ipos.z + z)) {
unsigned int bits = 0;
if (x)
bits |= 1;
if (y)
bits |= 2;
if (z)
bits |= 4;
directions[numDirections++] = bits;
}
}
if (numDirections == 0)
numDirections = 8;
int dirId = 0;
for (Vector3 dir : rays) {
unsigned int bits = directions[dirId];
unsigned int bits = i & 7;
if (bits & 1)
dir.x = -dir.x;
if (bits & 2)
@ -163,25 +147,15 @@ namespace spades {
if (bits & 4)
dir.z = -dir.z;
dirId++;
if (dirId >= numDirections)
dirId = 0;
Vector3 muzzle = pos + dir * muzzleDiff;
Vector3 muzzle = pos;
IntVector3 hitBlock;
float brightness = 1.f;
if (map->IsSolidWrapped((int)floorf(muzzle.x), (int)floorf(muzzle.y),
(int)floorf(muzzle.z))) {
if (numDirections < 8)
SPAssert(false);
continue;
}
if (map->CastRay(muzzle, dir, 18.f, hitBlock)) {
if (map->CastRay(muzzle, dir, (float)RayLength, hitBlock)) {
Vector3 centerPos =
MakeVector3(hitBlock.x + .5f, hitBlock.y + .5f, hitBlock.z + .5f);
float dist = (centerPos - muzzle).GetPoweredLength();
brightness = dist * 0.02f; // 1/7/7
brightness = dist * (1.0 / float((RayLength - 1) * (RayLength - 1)));
if (brightness > 1.f)
brightness = 1.f;
}
@ -189,8 +163,7 @@ namespace spades {
sum += brightness;
}
sum *= 1.f / (float)NumRays;
sum *= (float)numDirections / 4.f;
sum = std::min(sum * (2.f / (float)NumRays), 1.0f);
return sum;
}
@ -201,7 +174,8 @@ namespace spades {
return;
}
Invalidate(x - 8, y - 8, z - 8, x + 8, y + 8, z + 8);
Invalidate(x - RayLength, y - RayLength, z - RayLength, x + RayLength, y + RayLength,
z + RayLength);
}
void GLAmbientShadowRenderer::Invalidate(int minX, int minY, int minZ, int maxX, int maxY,
@ -289,7 +263,7 @@ namespace spades {
if (!c.transferDone.exchange(true)) {
device.TexSubImage3D(IGLDevice::Texture3D, 0, c.cx * ChunkSize,
c.cy * ChunkSize, c.cz * ChunkSize + 1, ChunkSize,
ChunkSize, ChunkSize, IGLDevice::Red, IGLDevice::FloatType,
ChunkSize, ChunkSize, IGLDevice::RG, IGLDevice::FloatType,
c.data);
}
}
@ -366,15 +340,166 @@ namespace spades {
int originY = cy * ChunkSize;
int originZ = cz * ChunkSize;
// Compute the slightly larger volume for blurring
constexpr int padding = 2;
float wData[ChunkSize + padding * 2][ChunkSize + padding * 2][ChunkSize + padding * 2]
[2];
std::uint8_t wFlags[ChunkSize + padding * 2][ChunkSize + padding * 2]
[ChunkSize + padding * 2];
int wOriginX = originX - padding;
int wOriginY = originY - padding;
int wOriginZ = originZ - padding;
int wDirtyMinX = c.dirtyMinX;
int wDirtyMinY = c.dirtyMinY;
int wDirtyMinZ = c.dirtyMinZ;
int wDirtyMaxX = c.dirtyMaxX + padding * 2;
int wDirtyMaxY = c.dirtyMaxY + padding * 2;
int wDirtyMaxZ = c.dirtyMaxZ + padding * 2;
auto b = [](int i) -> std::uint8_t { return (std::uint8_t)1 << i; };
auto to_b = [](bool b, int i) -> std::uint8_t { return (std::uint8_t)b << i; };
for (int z = wDirtyMinZ; z <= wDirtyMaxZ; z++)
for (int y = wDirtyMinY; y <= wDirtyMaxY; y++)
for (int x = wDirtyMinX; x <= wDirtyMaxX; x++) {
IntVector3 pos{
x + wOriginX,
y + wOriginY,
z + wOriginZ,
};
if (map->IsSolidWrapped(pos.x, pos.y, pos.z)) {
wData[z][y][x][0] = 0.0;
wData[z][y][x][1] = 0.0;
} else {
wData[z][y][x][0] = Evaluate(pos);
wData[z][y][x][1] = 1.0;
}
// bit 0: solids
// bit 1: contact (by-surface voxel)
wFlags[z][y][x] =
to_b(map->IsSolidWrapped(pos.x, pos.y, pos.z), 0) |
to_b(map->IsSolidWrapped(pos.x - 1, pos.y - 1, pos.z - 1) |
map->IsSolidWrapped(pos.x - 1, pos.y - 1, pos.z) |
map->IsSolidWrapped(pos.x - 1, pos.y - 1, pos.z + 1) |
map->IsSolidWrapped(pos.x - 1, pos.y, pos.z - 1) |
map->IsSolidWrapped(pos.x - 1, pos.y, pos.z) |
map->IsSolidWrapped(pos.x - 1, pos.y, pos.z + 1) |
map->IsSolidWrapped(pos.x - 1, pos.y + 1, pos.z - 1) |
map->IsSolidWrapped(pos.x - 1, pos.y + 1, pos.z) |
map->IsSolidWrapped(pos.x - 1, pos.y + 1, pos.z + 1) |
map->IsSolidWrapped(pos.x - 1, pos.y - 1, pos.z - 1) |
map->IsSolidWrapped(pos.x, pos.y - 1, pos.z) |
map->IsSolidWrapped(pos.x, pos.y - 1, pos.z + 1) |
map->IsSolidWrapped(pos.x, pos.y, pos.z - 1) |
map->IsSolidWrapped(pos.x, pos.y, pos.z + 1) |
map->IsSolidWrapped(pos.x, pos.y + 1, pos.z - 1) |
map->IsSolidWrapped(pos.x, pos.y + 1, pos.z) |
map->IsSolidWrapped(pos.x, pos.y + 1, pos.z + 1) |
map->IsSolidWrapped(pos.x + 1, pos.y - 1, pos.z - 1) |
map->IsSolidWrapped(pos.x + 1, pos.y - 1, pos.z) |
map->IsSolidWrapped(pos.x + 1, pos.y - 1, pos.z + 1) |
map->IsSolidWrapped(pos.x + 1, pos.y, pos.z - 1) |
map->IsSolidWrapped(pos.x + 1, pos.y, pos.z) |
map->IsSolidWrapped(pos.x + 1, pos.y, pos.z + 1) |
map->IsSolidWrapped(pos.x + 1, pos.y + 1, pos.z - 1) |
map->IsSolidWrapped(pos.x + 1, pos.y + 1, pos.z) |
map->IsSolidWrapped(pos.x + 1, pos.y + 1, pos.z + 1),
1);
}
// The AO terms are sampled 0.5 blocks away from the terrain surface,
// which leads to under-shadowing. Compensate for this effect.
for (int z = wDirtyMinZ; z <= wDirtyMaxZ; z++)
for (int y = wDirtyMinY; y <= wDirtyMaxY; y++)
for (int x = wDirtyMinX; x <= wDirtyMaxX; x++) {
float &d = wData[z][y][x][0];
d *= d * d + 1.0f - d;
}
// Blur the result to remove noise
//
// | this | neighbor |
// | solid | contact | solid | contact | blur
// | 0 0 | 0 x | 1
// | 0 1 | 0 0 | 0 (prevent under-shadowing)
// | 0 1 | 0 1 | 1
// | 0 x | 1 x | 0 (solid voxel's value is zero)
// | 1 x | 0 x | 0 (solid voxel's value must remain zero)
// | 1 x | 1 x | x
//
//
// this voxel
//
// solid
// /-------\ .
// +---+---+---+---+
// | 1 | 0 | 0 | 0 |
// +---+---+---+---+\ .
// | 1 | 1 | 0 | 0 | |
// /+---+---+---+---+ | contact neighbor
// | | 0 | 0 | | | |
// solid | +---+---+---+---+/
// | | 0 | 0 | | |
// \+---+---+---+---+
// \-------/
// contact
//
static const float divider[] = {1.0f, 1.0f / 2.0f, 1.0f / 3.0f};
auto mask = [](bool b, float x) { return b ? x : 0.0f; };
auto shouldBlur = [=](std::uint8_t thisFlags, std::uint8_t neighborFlags) {
return ((neighborFlags & b(0)) | ((~thisFlags | neighborFlags) & b(1))) == 0b10;
};
for (int blurPass = 0; blurPass < 2; ++blurPass) {
for (int z = wDirtyMinZ; z <= wDirtyMaxZ; z++)
for (int y = wDirtyMinY; y <= wDirtyMaxY; y++)
for (int x = wDirtyMinX + 1; x < wDirtyMaxX; x++) {
if (wFlags[z][y][x] & b(0)) {
continue;
}
// Do not blur between by-surface voxels and
// in-the-air voxels
bool m1 = shouldBlur(wFlags[z][y][x], wFlags[z][y][x - 1]);
bool m2 = shouldBlur(wFlags[z][y][x], wFlags[z][y][x + 1]);
wData[z][y][x][0] =
(wData[z][y][x][0] + mask(m1, wData[z][y][x - 1][0]) +
mask(m2, wData[z][y][x + 1][0])) *
divider[(int)m1 + (int)m2];
}
for (int z = wDirtyMinZ; z <= wDirtyMaxZ; z++)
for (int y = wDirtyMinY + 1; y < wDirtyMaxY; y++)
for (int x = wDirtyMinX; x <= wDirtyMaxX; x++) {
if (wFlags[z][y][x] & b(0)) {
continue;
}
bool m1 = shouldBlur(wFlags[z][y][x], wFlags[z][y - 1][x]);
bool m2 = shouldBlur(wFlags[z][y][x], wFlags[z][y + 1][x]);
wData[z][y][x][0] =
(wData[z][y][x][0] + mask(m1, wData[z][y - 1][x][0]) +
mask(m2, wData[z][y + 1][x][0])) *
divider[(int)m1 + (int)m2];
}
for (int z = wDirtyMinZ + 1; z < wDirtyMaxZ; z++)
for (int y = wDirtyMinY; y <= wDirtyMaxY; y++)
for (int x = wDirtyMinX; x <= wDirtyMaxX; x++) {
if (wFlags[z][y][x] & b(0)) {
continue;
}
bool m1 = shouldBlur(wFlags[z][y][x], wFlags[z - 1][y][x]);
bool m2 = shouldBlur(wFlags[z][y][x], wFlags[z + 1][y][x]);
wData[z][y][x][0] =
(wData[z][y][x][0] + mask(m1, wData[z - 1][y][x][0]) +
mask(m2, wData[z + 1][y][x][0])) *
divider[(int)m1 + (int)m2];
}
}
// Copy the result to `c.data`
for (int z = c.dirtyMinZ; z <= c.dirtyMaxZ; z++)
for (int y = c.dirtyMinY; y <= c.dirtyMaxY; y++)
for (int x = c.dirtyMinX; x <= c.dirtyMaxX; x++) {
IntVector3 pos;
pos.x = (x + originX);
pos.y = (y + originY);
pos.z = (z + originZ);
c.data[z][y][x] = Evaluate(pos);
c.data[z][y][x][0] = wData[z + padding][y + padding][x + padding][0];
c.data[z][y][x][1] = wData[z + padding][y + padding][x + padding][1];
}
c.dirty = false;

View File

@ -42,6 +42,7 @@ namespace spades {
static constexpr int NumRays = 16;
static constexpr int ChunkSizeBits = 4;
static constexpr int ChunkSize = 1 << ChunkSizeBits;
static constexpr int RayLength = 16;
GLRenderer &renderer;
IGLDevice &device;
@ -50,7 +51,7 @@ namespace spades {
struct Chunk {
int cx, cy, cz;
float data[ChunkSize][ChunkSize][ChunkSize];
float data[ChunkSize][ChunkSize][ChunkSize][2];
bool dirty = true;
int dirtyMinX = 0, dirtyMaxX = ChunkSize - 1;
int dirtyMinY = 0, dirtyMaxY = ChunkSize - 1;

View File

@ -222,10 +222,6 @@ namespace spades {
void GLBasicShadowMapRenderer::Render() {
SPADES_MARK_FUNCTION();
IGLDevice::Integer lastFb = device.GetInteger(IGLDevice::FramebufferBinding);
// client::SceneDefinition def = GetRenderer().GetSceneDef();
float nearDist = 0.f;
for (int i = 0; i < NumSlices; i++) {
@ -244,18 +240,6 @@ namespace spades {
BuildMatrix(nearDist, farDist);
matrices[i] = matrix;
/*
printf("m[%d]=\n[%f,%f,%f,%f]\n[%f,%f,%f,%f]\n[%f,%f,%f,%f]\n[%f,%f,%f,%f]\n",
i, matrix.m[0], matrix.m[4], matrix.m[8], matrix.m[12],
matrix.m[1], matrix.m[5], matrix.m[9], matrix.m[13],
matrix.m[2], matrix.m[6], matrix.m[10], matrix.m[14],
matrix.m[3], matrix.m[7], matrix.m[11], matrix.m[15]);*/
/*
matrix = Matrix4::Identity();
matrix = Matrix4::Scale(1.f / 16.f);
matrix = matrix * Matrix4::Rotate(MakeVector3(1, 0, 0), M_PI / 4.f);
matrix = matrix * Matrix4::Translate(-def.viewOrigin);
matrix = Matrix4::Scale(1,1,16.f / 70.f) * matrix;*/
device.BindFramebuffer(IGLDevice::Framebuffer, framebuffer[i]);
device.Viewport(0, 0, textureSize, textureSize);
@ -266,10 +250,6 @@ namespace spades {
nearDist = farDist;
}
device.BindFramebuffer(IGLDevice::Framebuffer, lastFb);
device.Viewport(0, 0, device.ScreenWidth(), device.ScreenHeight());
}
bool GLBasicShadowMapRenderer::Cull(const spades::AABB3 &) {

View File

@ -56,7 +56,8 @@ namespace spades {
return acosf(v);
}
GLColorBuffer GLCameraBlurFilter::Filter(GLColorBuffer input, float radialBlur) {
GLColorBuffer GLCameraBlurFilter::Filter(GLColorBuffer input, float intensity,
float radialBlur) {
SPADES_MARK_FUNCTION();
if (radialBlur > 0.f)
@ -114,14 +115,14 @@ namespace spades {
}
float movePixels = MyACos(diffMatrix.m[0]);
float shutterTimeScale = .3f;
float shutterTimeScale = intensity;
movePixels = std::max(movePixels, MyACos(diffMatrix.m[5]));
movePixels = std::max(movePixels, MyACos(diffMatrix.m[10]));
movePixels = tanf(movePixels) / tanf(def.fovX * .5f);
movePixels *= (float)dev.ScreenWidth() * .5f;
movePixels *= (float)renderer.GetRenderWidth() * .5f;
movePixels *= shutterTimeScale;
movePixels = std::max(movePixels, (1.f - radialBlur) * dev.ScreenWidth() * 0.5f);
movePixels = std::max(movePixels, (1.f - radialBlur) * renderer.GetRenderWidth() * 0.5f);
if (movePixels < 1.f) {
// too less change, skip camera blur

View File

@ -34,7 +34,7 @@ namespace spades {
public:
GLCameraBlurFilter(GLRenderer &);
GLColorBuffer Filter(GLColorBuffer, float radialBlur = 0.f);
GLColorBuffer Filter(GLColorBuffer, float intensity, float radialBlur = 0.f);
};
} // namespace draw
} // namespace spades

View File

@ -19,6 +19,7 @@
*/
#include <vector>
#include <cmath>
#include "GLColorCorrectionFilter.h"
#include "GLProgram.h"
@ -36,28 +37,75 @@ namespace spades {
GLColorCorrectionFilter::GLColorCorrectionFilter(GLRenderer &renderer)
: renderer(renderer), settings(renderer.GetSettings()) {
lens = renderer.RegisterProgram("Shaders/PostFilters/ColorCorrection.program");
gaussProgram = renderer.RegisterProgram("Shaders/PostFilters/Gauss1D.program");
}
GLColorBuffer GLColorCorrectionFilter::Filter(GLColorBuffer input, Vector3 tintVal) {
GLColorBuffer GLColorCorrectionFilter::Filter(GLColorBuffer input, Vector3 tintVal,
float fogLuminance) {
SPADES_MARK_FUNCTION();
IGLDevice &dev = renderer.GetGLDevice();
GLQuadRenderer qr(dev);
GLColorBuffer output = input.GetManager()->CreateBufferHandle();
float sharpeningFinalGainValue =
std::max(std::min(settings.r_sharpen.operator float(), 1.0f), 0.0f);
GLColorBuffer blurredInput = input;
if (sharpeningFinalGainValue > 0.0f) {
// Apply a 1D gaussian blur on the horizontal direction.
// (The vertical direction blur is done by the final program)
static GLProgramAttribute blur_positionAttribute("positionAttribute");
static GLProgramUniform blur_textureUniform("mainTexture");
static GLProgramUniform blur_unitShift("unitShift");
gaussProgram->Use();
blur_positionAttribute(gaussProgram);
blur_textureUniform(gaussProgram);
blur_unitShift(gaussProgram);
blur_textureUniform.SetValue(0);
dev.ActiveTexture(0);
qr.SetCoordAttributeIndex(blur_positionAttribute());
dev.Enable(IGLDevice::Blend, false);
blurredInput = renderer.GetFramebufferManager()->CreateBufferHandle();
dev.BindTexture(IGLDevice::Texture2D, input.GetTexture());
dev.BindFramebuffer(IGLDevice::Framebuffer, blurredInput.GetFramebuffer());
blur_unitShift.SetValue(1.0f / (float)input.GetWidth(), 0.f);
qr.Draw();
}
float sharpeningFloor = 0.0f;
// If temporal AA is enabled, enable the sharpening effect regardless of
// the current fog color to offset the blurring caused by the temporal AA.
if (settings.r_temporalAA) {
sharpeningFloor = 1.5f;
}
static GLProgramAttribute lensPosition("positionAttribute");
static GLProgramUniform lensTexture("mainTexture");
static GLProgramUniform blurredTexture("blurredTexture");
static GLProgramUniform saturation("saturation");
static GLProgramUniform enhancement("enhancement");
static GLProgramUniform tint("tint");
static GLProgramUniform sharpening("sharpening");
static GLProgramUniform sharpeningFinalGain("sharpeningFinalGain");
static GLProgramUniform blurPixelShift("blurPixelShift");
saturation(lens);
enhancement(lens);
tint(lens);
sharpening(lens);
sharpeningFinalGain(lens);
blurPixelShift(lens);
dev.Enable(IGLDevice::Blend, false);
lensPosition(lens);
lensTexture(lens);
blurredTexture(lens);
lens->Use();
@ -87,11 +135,75 @@ namespace spades {
}
lensTexture.SetValue(0);
blurredTexture.SetValue(1);
// Calculate the sharpening factor
//
// One reason to do this is for aesthetic reasons. Another reason is to offset
// OpenSpades' denser fog compared to the vanilla client. Technically, the fog density
// function is mostly identical between these two clients. However, OpenSpades applies
// the fog color in the linear color space, which is physically accurate but has an
// unexpected consequence of somewhat strengthening the effect.
//
// (`r_volumetricFog` completely changes the density function, which we leave out from
// this discussion.)
//
// Given an object color o (only one color channel is discussed here), fog color f, and
// fog density d, the output color c_voxlap and c_os for the vanilla client and
// OpenSpades, respectively, is calculated by:
//
// c_voxlap = o^(1/2)(1-d) + f^(1/2)d
// c_os = (o(1-d) + fd)^(1/2)
//
// Here the sRGB transfer function is approximated by an exact gamma = 2 power law.
// o and f are in the linear color space, whereas c_voxlap and c_os are in the sRGB
// color space (because that's how `ColorCorrection.fs` is implemented).
//
// The contrast reduction by the fog can be calculated by differentiating each of them
// by o:
//
// c_voxlap' = (1-d) / sqrt(o) / 2
// c_os' = (1-d) / sqrt(o(1-d) + fd) / 2
//
// Now we find out the amount of color contrast we must recover by dividing c_voxlap' by
// c_os'. Since it's objects around the fog end distance that concern the users, let
// d = 1:
//
// c_voxlap' / c_os' = sqrt(o(1-d) + fd) / sqrt(o)
// = sqrt(f) / sqrt(o)
//
// (Turns out, the result so far does not change whichever color space c_voxlap and c_os
// are represented in.)
//
// This is a function over an object color o and fog color f. Let us calculate the
// average of this function assuming a uniform distribution of o over the interval
// [o_min, o_max]:
//
// ∫[c_voxlap' / c_os', {o, o_min, o_max}]
// = 2sqrt(f)(sqrt(o_max) - sqrt(o_min)) / (o_max - o_min)
//
// Since the pixels aren't usually fully lit nor completely dark, let us arbitrarily
// assume o_min = 0.001 and o_max = 0.5 (I think this is reasonable for a deuce hiding
// in a shady corridor) (and let it be `r_offset`):
//
// r_offset
// = 2sqrt(f)(sqrt(o_max) - sqrt(o_min)) / (o_max - o_min)
// ≈ 2.70 sqrt(f)
//
// So if this value is higher than 1, we need enhance the rendered image. Otherwise,
// we will maintain the status quo for now. (In most servers I have encountered, the fog
// color was a bright color, so this status quo won't be a problem, I think. No one has
// complained about it so far.)
sharpening.SetValue(std::max(std::sqrt(fogLuminance) * 2.7f, sharpeningFloor));
sharpeningFinalGain.SetValue(sharpeningFinalGainValue);
blurPixelShift.SetValue(1.0f / (float)input.GetHeight());
// composite to the final image
GLColorBuffer output = input.GetManager()->CreateBufferHandle();
qr.SetCoordAttributeIndex(lensPosition());
dev.ActiveTexture(1);
dev.BindTexture(IGLDevice::Texture2D, blurredInput.GetTexture());
dev.ActiveTexture(0);
dev.BindTexture(IGLDevice::Texture2D, input.GetTexture());
dev.BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer());
dev.Viewport(0, 0, output.GetWidth(), output.GetHeight());

View File

@ -30,11 +30,15 @@ namespace spades {
class GLColorCorrectionFilter {
GLRenderer &renderer;
GLSettings &settings;
GLProgram *gaussProgram;
GLProgram *lens;
public:
GLColorCorrectionFilter(GLRenderer &);
GLColorBuffer Filter(GLColorBuffer, Vector3 tint);
/**
* @param fogLuminance The luminance of the fog color. Must be in the sRGB color space.
*/
GLColorBuffer Filter(GLColorBuffer, Vector3 tint, float fogLuminance);
};
} // namespace draw
} // namespace spades

View File

@ -168,7 +168,6 @@ namespace spades {
GLColorBuffer cocBlur = BlurCoC(coc, 1.f);
// mix
GLColorBuffer coc2 = renderer.GetFramebufferManager()->CreateBufferHandle(w2, h2, 1);
{
@ -262,6 +261,8 @@ namespace spades {
int w = buffer1.GetWidth();
int h = buffer1.GetHeight();
GLColorBuffer buf2 = renderer.GetFramebufferManager()->CreateBufferHandle(w, h, false);
static GLProgramAttribute blur_positionAttribute("positionAttribute");
static GLProgramUniform blur_textureUniform1("texture1");
static GLProgramUniform blur_textureUniform2("texture2");
@ -291,7 +292,6 @@ namespace spades {
dev.Enable(IGLDevice::Blend, false);
// x-direction
GLColorBuffer buf2 = renderer.GetFramebufferManager()->CreateBufferHandle(w, h, false);
dev.BindFramebuffer(IGLDevice::Framebuffer, buf2.GetFramebuffer());
qr.Draw();
return buf2;
@ -307,6 +307,8 @@ namespace spades {
int w = tex.GetWidth();
int h = tex.GetHeight();
GLColorBuffer buf2 = renderer.GetFramebufferManager()->CreateBufferHandle(w, h, false);
static GLProgramAttribute blur_positionAttribute("positionAttribute");
static GLProgramUniform blur_textureUniform1("mainTexture");
static GLProgramUniform blur_textureUniform2("blurTexture1");
@ -343,7 +345,6 @@ namespace spades {
dev.Enable(IGLDevice::Blend, false);
// x-direction
GLColorBuffer buf2 = renderer.GetFramebufferManager()->CreateBufferHandle(w, h, false);
dev.BindFramebuffer(IGLDevice::Framebuffer, buf2.GetFramebuffer());
qr.Draw();
return buf2;
@ -358,6 +359,9 @@ namespace spades {
int w = tex.GetWidth();
int h = tex.GetHeight();
GLColorBuffer buf2 =
renderer.GetFramebufferManager()->CreateBufferHandle(w / 2, h / 2, false);
static GLProgramAttribute blur_positionAttribute("positionAttribute");
static GLProgramUniform blur_textureUniform("mainTexture");
static GLProgramUniform blur_colorUniform("colorUniform");
@ -379,8 +383,6 @@ namespace spades {
qr.SetCoordAttributeIndex(blur_positionAttribute());
dev.Enable(IGLDevice::Blend, false);
GLColorBuffer buf2 =
renderer.GetFramebufferManager()->CreateBufferHandle(w / 2, h / 2, false);
dev.Viewport(0, 0, w / 2, h / 2);
dev.BindFramebuffer(IGLDevice::Framebuffer, buf2.GetFramebuffer());
qr.Draw();
@ -395,8 +397,8 @@ namespace spades {
IGLDevice &dev = renderer.GetGLDevice();
GLQuadRenderer qr(dev);
int w = dev.ScreenWidth();
int h = dev.ScreenHeight();
int w = input.GetWidth();
int h = input.GetHeight();
dev.Enable(IGLDevice::Blend, false);

View File

@ -41,6 +41,8 @@ namespace spades {
IGLDevice &dev = renderer.GetGLDevice();
GLQuadRenderer qr(dev);
GLColorBuffer output = input.GetManager()->CreateBufferHandle();
static GLProgramAttribute lensPosition("positionAttribute");
static GLProgramUniform lensTexture("mainTexture");
static GLProgramUniform inverseVP("inverseVP");
@ -53,11 +55,10 @@ namespace spades {
lens->Use();
inverseVP.SetValue(1.f / dev.ScreenWidth(), 1.f / dev.ScreenHeight());
inverseVP.SetValue(1.f / input.GetWidth(), 1.f / input.GetHeight());
lensTexture.SetValue(0);
// composite to the final image
GLColorBuffer output = input.GetManager()->CreateBufferHandle();
qr.SetCoordAttributeIndex(lensPosition());
dev.BindTexture(IGLDevice::Texture2D, input.GetTexture());

View File

@ -56,8 +56,13 @@ namespace spades {
SPRaise("OpenGL Framebuffer completeness check failed: %s", type.c_str());
}
GLFramebufferManager::GLFramebufferManager(IGLDevice &dev, GLSettings &settings)
: device(dev), settings(settings), doingPostProcessing(false) {
GLFramebufferManager::GLFramebufferManager(IGLDevice &dev, GLSettings &settings,
int renderWidth, int renderHeight)
: device(dev),
settings(settings),
doingPostProcessing(false),
renderWidth(renderWidth),
renderHeight(renderHeight) {
SPADES_MARK_FUNCTION();
SPLog("Initializing framebuffer manager");
@ -84,8 +89,7 @@ namespace spades {
multisampledDepthRenderbuffer = dev.GenRenderbuffer();
dev.BindRenderbuffer(IGLDevice::Renderbuffer, multisampledDepthRenderbuffer);
dev.RenderbufferStorage(IGLDevice::Renderbuffer, (int)settings.r_multisamples,
IGLDevice::DepthComponent24, dev.ScreenWidth(),
dev.ScreenHeight());
IGLDevice::DepthComponent24, renderWidth, renderHeight);
SPLog("MSAA Depth Buffer Allocated");
dev.FramebufferRenderbuffer(IGLDevice::Framebuffer, IGLDevice::DepthAttachment,
@ -97,8 +101,7 @@ namespace spades {
SPLog("Creating MSAA Color Buffer with SRGB8_ALPHA");
useHighPrec = false;
dev.RenderbufferStorage(IGLDevice::Renderbuffer, (int)settings.r_multisamples,
IGLDevice::SRGB8Alpha, dev.ScreenWidth(),
dev.ScreenHeight());
IGLDevice::SRGB8Alpha, renderWidth, renderHeight);
SPLog("MSAA Color Buffer Allocated");
@ -120,7 +123,7 @@ namespace spades {
dev.RenderbufferStorage(IGLDevice::Renderbuffer,
(int)settings.r_multisamples,
useHdr ? IGLDevice::RGBA16F : IGLDevice::RGB10A2,
dev.ScreenWidth(), dev.ScreenHeight());
renderWidth, renderHeight);
SPLog("MSAA Color Buffer Allocated");
dev.FramebufferRenderbuffer(
@ -140,7 +143,7 @@ namespace spades {
settings.r_hdr = 0;
dev.RenderbufferStorage(IGLDevice::Renderbuffer,
(int)settings.r_multisamples, IGLDevice::RGBA8,
dev.ScreenWidth(), dev.ScreenHeight());
renderWidth, renderHeight);
SPLog("MSAA Color Buffer Allocated");
@ -171,8 +174,8 @@ namespace spades {
renderDepthTexture = dev.GenTexture();
dev.BindTexture(IGLDevice::Texture2D, renderDepthTexture);
dev.TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::DepthComponent24, dev.ScreenWidth(),
dev.ScreenHeight(), 0, IGLDevice::DepthComponent, IGLDevice::UnsignedInt,
dev.TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::DepthComponent24, renderWidth,
renderHeight, 0, IGLDevice::DepthComponent, IGLDevice::UnsignedInt,
NULL);
SPLog("Depth Buffer Allocated");
dev.TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter, IGLDevice::Nearest);
@ -188,9 +191,8 @@ namespace spades {
if (settings.r_srgb) {
SPLog("Creating Non-MSAA SRGB buffer");
useHighPrec = false;
dev.TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::SRGB8Alpha, dev.ScreenWidth(),
dev.ScreenHeight(), 0, IGLDevice::RGBA, IGLDevice::UnsignedByte,
NULL);
dev.TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::SRGB8Alpha, renderWidth,
renderHeight, 0, IGLDevice::RGBA, IGLDevice::UnsignedByte, NULL);
SPLog("Color Buffer Allocated");
dev.TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
IGLDevice::Linear);
@ -216,10 +218,9 @@ namespace spades {
SPLog("RGB10A2/HDR disabled");
SPRaise("jump to catch(...)");
}
dev.TexImage2D(IGLDevice::Texture2D, 0,
useHdr ? IGLDevice::RGBA16F : IGLDevice::RGB10A2,
dev.ScreenWidth(), dev.ScreenHeight(), 0, IGLDevice::RGBA,
IGLDevice::UnsignedByte, NULL);
dev.TexImage2D(
IGLDevice::Texture2D, 0, useHdr ? IGLDevice::RGBA16F : IGLDevice::RGB10A2,
renderWidth, renderHeight, 0, IGLDevice::RGBA, IGLDevice::UnsignedByte, NULL);
SPLog("Color Buffer Allocated");
dev.TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
IGLDevice::Linear);
@ -244,8 +245,8 @@ namespace spades {
useHighPrec = false;
useHdr = false;
settings.r_hdr = 0;
dev.TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::RGBA8, dev.ScreenWidth(),
dev.ScreenHeight(), 0, IGLDevice::RGBA, IGLDevice::UnsignedByte,
dev.TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::RGBA8, renderWidth,
renderHeight, 0, IGLDevice::RGBA, IGLDevice::UnsignedByte,
NULL);
SPLog("Color Buffer Allocated");
dev.TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
@ -277,9 +278,8 @@ namespace spades {
mirrorColorTexture = dev.GenTexture();
dev.BindTexture(IGLDevice::Texture2D, mirrorColorTexture);
SPLog("Creating Mirror texture");
dev.TexImage2D(IGLDevice::Texture2D, 0, fbInternalFormat, dev.ScreenWidth(),
dev.ScreenHeight(), 0, IGLDevice::RGBA, IGLDevice::UnsignedByte,
NULL);
dev.TexImage2D(IGLDevice::Texture2D, 0, fbInternalFormat, renderWidth,
renderHeight, 0, IGLDevice::RGBA, IGLDevice::UnsignedByte, NULL);
SPLog("Color Buffer Allocated");
dev.TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
@ -297,9 +297,9 @@ namespace spades {
SPLog("Creating Mirror depth texture");
mirrorDepthTexture = dev.GenTexture();
dev.BindTexture(IGLDevice::Texture2D, mirrorDepthTexture);
dev.TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::DepthComponent24,
dev.ScreenWidth(), dev.ScreenHeight(), 0, IGLDevice::DepthComponent,
IGLDevice::UnsignedInt, NULL);
dev.TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::DepthComponent24, renderWidth,
renderHeight, 0, IGLDevice::DepthComponent, IGLDevice::UnsignedInt,
NULL);
SPLog("Depth Buffer Allocated");
dev.TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
@ -331,8 +331,8 @@ namespace spades {
buf.framebuffer = renderFramebufferWithoutDepth;
buf.texture = renderColorTexture;
buf.refCount = 0;
buf.w = device.ScreenWidth();
buf.h = device.ScreenHeight();
buf.w = renderWidth;
buf.h = renderHeight;
buf.internalFormat = fbInternalFormat;
buffers.push_back(buf);
@ -341,8 +341,38 @@ namespace spades {
}
GLFramebufferManager::~GLFramebufferManager() {
// maybe framebuffers are released automatically when
// application quits...
if (multisampledFramebuffer) {
device.DeleteFramebuffer(multisampledFramebuffer);
}
if (multisampledColorRenderbuffer) {
device.DeleteRenderbuffer(multisampledColorRenderbuffer);
}
if (multisampledDepthRenderbuffer) {
device.DeleteRenderbuffer(multisampledDepthRenderbuffer);
}
if (renderFramebuffer) {
device.DeleteFramebuffer(renderFramebuffer);
}
if (renderColorTexture) {
device.DeleteTexture(renderColorTexture);
}
if (renderDepthTexture) {
device.DeleteTexture(renderDepthTexture);
}
if (mirrorFramebuffer) {
device.DeleteFramebuffer(mirrorFramebuffer);
}
if (mirrorColorTexture) {
device.DeleteTexture(mirrorColorTexture);
}
if (mirrorDepthTexture) {
device.DeleteTexture(mirrorDepthTexture);
}
for (const Buffer &buffer : buffers) {
device.DeleteFramebuffer(buffer.framebuffer);
device.DeleteTexture(buffer.texture);
}
buffers.clear();
}
void GLFramebufferManager::PrepareSceneRendering() {
@ -364,7 +394,7 @@ namespace spades {
device.Enable(IGLDevice::DepthTest, true);
device.DepthMask(true);
device.Viewport(0, 0, device.ScreenWidth(), device.ScreenHeight());
device.Viewport(0, 0, renderWidth, renderHeight);
}
GLColorBuffer
@ -387,8 +417,8 @@ namespace spades {
IGLDevice::Texture2D, handle.GetTexture(), 0);
// downsample
int w = device.ScreenWidth();
int h = device.ScreenHeight();
int w = renderWidth;
int h = renderHeight;
if (settings.r_blitFramebuffer) {
if (useMultisample) {
@ -429,7 +459,7 @@ namespace spades {
void GLFramebufferManager::ClearMirrorTexture(spades::Vector3 bgCol) {
device.BindFramebuffer(IGLDevice::Framebuffer, mirrorFramebuffer);
device.Viewport(0, 0, device.ScreenWidth(), device.ScreenHeight());
device.Viewport(0, 0, renderWidth, renderHeight);
device.ClearColor(bgCol.x, bgCol.y, bgCol.z, 1.f);
device.Clear((IGLDevice::Enum)(IGLDevice::ColorBufferBit | IGLDevice::DepthBufferBit));
@ -445,8 +475,8 @@ namespace spades {
void GLFramebufferManager::CopyToMirrorTexture(IGLDevice::UInteger fb) {
SPADES_MARK_FUNCTION();
int w = device.ScreenWidth();
int h = device.ScreenHeight();
int w = renderWidth;
int h = renderHeight;
if (fb == 0) {
fb = useMultisample ? multisampledFramebuffer : renderFramebuffer;
}
@ -458,10 +488,13 @@ namespace spades {
if (settings.r_blitFramebuffer) {
device.BindFramebuffer(IGLDevice::ReadFramebuffer, fb);
device.BindFramebuffer(IGLDevice::DrawFramebuffer, mirrorFramebuffer);
device.BlitFramebuffer(0, 0, w, h, 0, 0, w, h,
IGLDevice::ColorBufferBit |
(needsDepth ? IGLDevice::DepthBufferBit : 0),
device.BlitFramebuffer(0, 0, w, h, 0, 0, w, h, IGLDevice::ColorBufferBit,
IGLDevice::Nearest);
if (needsDepth) {
device.BindFramebuffer(IGLDevice::ReadFramebuffer, renderFramebuffer);
device.BlitFramebuffer(0, 0, w, h, 0, 0, w, h, IGLDevice::DepthBufferBit,
IGLDevice::Nearest);
}
device.BindFramebuffer(IGLDevice::ReadFramebuffer, 0);
device.BindFramebuffer(IGLDevice::DrawFramebuffer, 0);
} else {
@ -478,10 +511,13 @@ namespace spades {
if (settings.r_blitFramebuffer) {
device.BindFramebuffer(IGLDevice::ReadFramebuffer, fb);
device.BindFramebuffer(IGLDevice::DrawFramebuffer, mirrorFramebuffer);
device.BlitFramebuffer(0, 0, w, h, 0, 0, w, h,
IGLDevice::ColorBufferBit |
(needsDepth ? IGLDevice::DepthBufferBit : 0),
device.BlitFramebuffer(0, 0, w, h, 0, 0, w, h, IGLDevice::ColorBufferBit,
IGLDevice::Nearest);
if (needsDepth) {
device.BindFramebuffer(IGLDevice::ReadFramebuffer, renderFramebuffer);
device.BlitFramebuffer(0, 0, w, h, 0, 0, w, h, IGLDevice::DepthBufferBit,
IGLDevice::Nearest);
}
device.BindFramebuffer(IGLDevice::ReadFramebuffer, 0);
device.BindFramebuffer(IGLDevice::DrawFramebuffer, 0);
} else {
@ -518,8 +554,8 @@ namespace spades {
if (useMultisample) {
// downsample
int w = device.ScreenWidth();
int h = device.ScreenHeight();
int w = renderWidth;
int h = renderHeight;
if (settings.r_blitFramebuffer) {
device.BindFramebuffer(IGLDevice::ReadFramebuffer, multisampledFramebuffer);
device.BindFramebuffer(IGLDevice::DrawFramebuffer, renderFramebuffer);
@ -571,9 +607,9 @@ namespace spades {
SPADES_MARK_FUNCTION();
if (w < 0)
w = device.ScreenWidth();
w = renderWidth;
if (h < 0)
h = device.ScreenHeight();
h = renderHeight;
// During the main rendering pass the first buffer is allocated to the render target
// and cannot be allocated for pre/postprocessing pass

View File

@ -71,29 +71,32 @@ namespace spades {
bool doingPostProcessing;
IGLDevice::UInteger multisampledFramebuffer;
int renderWidth;
int renderHeight;
IGLDevice::UInteger multisampledFramebuffer = 0;
// for multisample
IGLDevice::UInteger multisampledColorRenderbuffer;
IGLDevice::UInteger multisampledDepthRenderbuffer;
IGLDevice::UInteger multisampledColorRenderbuffer = 0;
IGLDevice::UInteger multisampledDepthRenderbuffer = 0;
// common
IGLDevice::UInteger renderFramebuffer;
IGLDevice::UInteger renderColorTexture;
IGLDevice::UInteger renderDepthTexture;
IGLDevice::UInteger renderFramebuffer = 0;
IGLDevice::UInteger renderColorTexture = 0;
IGLDevice::UInteger renderDepthTexture = 0;
IGLDevice::UInteger renderFramebufferWithoutDepth;
IGLDevice::UInteger renderFramebufferWithoutDepth = 0;
IGLDevice::Enum fbInternalFormat;
IGLDevice::UInteger mirrorFramebuffer;
IGLDevice::UInteger mirrorColorTexture;
IGLDevice::UInteger mirrorDepthTexture;
IGLDevice::UInteger mirrorFramebuffer = 0;
IGLDevice::UInteger mirrorColorTexture = 0;
IGLDevice::UInteger mirrorDepthTexture = 0;
std::vector<Buffer> buffers;
public:
GLFramebufferManager(IGLDevice &, GLSettings &);
GLFramebufferManager(IGLDevice &, GLSettings &, int renderWidth, int renderHeight);
~GLFramebufferManager();
/** setups device for scene rendering. */
@ -106,7 +109,19 @@ namespace spades {
void MakeSureAllBuffersReleased();
IGLDevice::UInteger GetDepthTexture() { return renderDepthTexture; }
IGLDevice::Enum GetMainInternalFormat() { return fbInternalFormat; }
/**
* Creates BufferHandle with a given size and format.
* Might clobber the current framebuffer and texture bindings.
*/
BufferHandle CreateBufferHandle(int w = -1, int h = -1, bool alpha = false);
/**
* Creates BufferHandle with a given size and format.
* Might clobber the current framebuffer and texture bindings.
*/
BufferHandle CreateBufferHandle(int w, int h, IGLDevice::Enum internalFormat);
void CopyToMirrorTexture(IGLDevice::UInteger fb = 0);

View File

@ -63,6 +63,9 @@ namespace spades {
int w = tex.GetWidth();
int h = tex.GetHeight();
GLColorBuffer buf2 = renderer.GetFramebufferManager()->CreateBufferHandle(
(w + 1) / 2, (h + 1) / 2, false);
static GLProgramAttribute blur_positionAttribute("positionAttribute");
static GLProgramUniform blur_textureUniform("mainTexture");
static GLProgramUniform blur_colorUniform("colorUniform");
@ -94,8 +97,6 @@ namespace spades {
dev.Enable(IGLDevice::Blend, false);
}
GLColorBuffer buf2 =
renderer.GetFramebufferManager()->CreateBufferHandle((w + 1) / 2, (h + 1) / 2, false);
dev.Viewport(0, 0, buf2.GetWidth(), buf2.GetHeight());
dev.BindFramebuffer(IGLDevice::Framebuffer, buf2.GetFramebuffer());
qr.Draw();
@ -110,6 +111,8 @@ namespace spades {
int w = tex.GetWidth();
int h = tex.GetHeight();
GLColorBuffer buf2 = renderer.GetFramebufferManager()->CreateBufferHandle(w, h, false);
static GLProgramAttribute blur_positionAttribute("positionAttribute");
static GLProgramUniform blur_textureUniform("mainTexture");
static GLProgramUniform blur_unitShift("unitShift");
@ -127,7 +130,6 @@ namespace spades {
qr.SetCoordAttributeIndex(blur_positionAttribute());
dev.Enable(IGLDevice::Blend, false);
GLColorBuffer buf2 = renderer.GetFramebufferManager()->CreateBufferHandle(w, h, false);
dev.Viewport(0, 0, buf2.GetWidth(), buf2.GetHeight());
dev.BindFramebuffer(IGLDevice::Framebuffer, buf2.GetFramebuffer());
qr.Draw();
@ -272,8 +274,8 @@ namespace spades {
dust->Use();
float facX = renderer.ScreenWidth() / 128.f;
float facY = renderer.ScreenHeight() / 128.f;
float facX = renderer.GetRenderWidth() / 128.f;
float facY = renderer.GetRenderHeight() / 128.f;
dustNoiseTexCoordFactor.SetValue(facX, facY, facX / 128.f, facY / 128.f);
// composite to the final image

View File

@ -41,6 +41,8 @@ namespace spades {
IGLDevice &dev = renderer.GetGLDevice();
GLQuadRenderer qr(dev);
GLColorBuffer output = input.GetManager()->CreateBufferHandle();
static GLProgramAttribute lensPosition("positionAttribute");
static GLProgramUniform lensTexture("mainTexture");
static GLProgramUniform lensFov("fov");
@ -58,7 +60,6 @@ namespace spades {
lensTexture.SetValue(0);
// composite to the final image
GLColorBuffer output = input.GetManager()->CreateBufferHandle();
qr.SetCoordAttributeIndex(lensPosition());
dev.BindTexture(IGLDevice::Texture2D, input.GetTexture());

View File

@ -242,7 +242,7 @@ namespace spades {
visibilityTexture.SetValue(0);
qr.SetCoordAttributeIndex(positionAttribute());
dev.Viewport(0, 0, dev.ScreenWidth(), dev.ScreenHeight());
dev.Viewport(0, 0, renderer.GetRenderWidth(), renderer.GetRenderHeight());
/* render flare */

View File

@ -41,6 +41,8 @@ namespace spades {
IGLDevice &dev = renderer.GetGLDevice();
GLQuadRenderer qr(dev);
GLColorBuffer output = input.GetManager()->CreateBufferHandle();
static GLProgramAttribute lensPosition("positionAttribute");
static GLProgramUniform lensTexture("mainTexture");
@ -58,7 +60,6 @@ namespace spades {
lensGamma.SetValue(1.f / (float)renderer.GetSettings().r_hdrGamma);
// composite to the final image
GLColorBuffer output = input.GetManager()->CreateBufferHandle();
qr.SetCoordAttributeIndex(lensPosition());
dev.BindTexture(IGLDevice::Texture2D, input.GetTexture());

View File

@ -28,8 +28,12 @@
#include <Core/ConcurrentDispatch.h>
#include <Core/Settings.h>
#ifdef __APPLE__
#if defined(__APPLE__)
#if defined(__x86_64__)
#include <xmmintrin.h>
#else
#include <arm_neon.h>
#endif
#endif
#include "GLProfiler.h"

View File

@ -50,12 +50,14 @@
#include "GLProgramUniform.h"
#include "GLRadiosityRenderer.h"
#include "GLRenderer.h"
#include "GLResampleBicubicFilter.h"
#include "GLSSAOFilter.h"
#include "GLSettings.h"
#include "GLShadowMapShader.h"
#include "GLSoftLitSpriteRenderer.h"
#include "GLSoftSpriteRenderer.h"
#include "GLSpriteRenderer.h"
#include "GLTemporalAAFilter.h"
#include "GLVoxelModel.h"
#include "GLWaterRenderer.h"
#include "IGLDevice.h"
@ -73,7 +75,6 @@ namespace spades {
GLRenderer::GLRenderer(Handle<IGLDevice> _device)
: device(std::move(_device)),
fbManager(NULL),
map(NULL),
inited(false),
sceneUsedInThisFrame(false),
@ -87,7 +88,6 @@ namespace spades {
modelRenderer(NULL),
spriteRenderer(NULL),
longSpriteRenderer(NULL),
waterRenderer(NULL),
ambientShadowRenderer(NULL),
radiosityRenderer(NULL),
cameraBlur(NULL),
@ -104,7 +104,9 @@ namespace spades {
SPLog("GLRenderer bootstrap");
fbManager = new GLFramebufferManager(*device, settings);
renderWidth = renderHeight = -1;
UpdateRenderSize();
programManager = new GLProgramManager(*device, shadowMapRenderer.get(), settings);
imageManager = new GLImageManager(*device);
@ -127,6 +129,33 @@ namespace spades {
Shutdown();
}
void GLRenderer::UpdateRenderSize() {
float renderScale = settings.r_scale;
renderScale = std::max(0.2f, renderScale);
if (!(renderScale < 1.0f)) { // eliminates NaN
renderScale = 1.0f;
}
int screenWidth = device->ScreenWidth();
int screenHeight = device->ScreenHeight();
int newRenderWidth = static_cast<int>(screenWidth * renderScale);
int newRenderHeight = static_cast<int>(screenHeight * renderScale);
if (newRenderWidth != renderWidth || newRenderHeight != renderHeight) {
SPLog("Render size has changed");
renderWidth = newRenderWidth;
renderHeight = newRenderHeight;
fbManager.reset(
new GLFramebufferManager(*device, settings, renderWidth, renderHeight));
if (waterRenderer) {
SPLog("Creating Water Renderer");
waterRenderer.reset(new GLWaterRenderer(*this, map));
}
}
}
void GLRenderer::Init() {
if (modelManager != NULL) {
// already initialized
@ -156,6 +185,9 @@ namespace spades {
if (settings.r_cameraBlur) {
cameraBlur = new GLCameraBlurFilter(*this);
}
if (settings.r_temporalAA) {
temporalAAFilter.reset(new GLTemporalAAFilter(*this));
}
if (settings.r_fogShadow) {
GLFogFilter(*this);
@ -185,6 +217,10 @@ namespace spades {
GLFXAAFilter(*this);
}
if (settings.r_scaleFilter.operator int() == 2) {
GLResampleBicubicFilter(*this);
}
if (settings.r_depthOfField) {
GLDepthOfFieldFilter(*this);
}
@ -198,6 +234,7 @@ namespace spades {
SPLog("GLRender finalizing");
SetGameMap(nullptr);
temporalAAFilter.reset();
delete autoExposureFilter;
autoExposureFilter = NULL;
delete lensDustFilter;
@ -212,8 +249,7 @@ namespace spades {
mapShadowRenderer = NULL;
delete mapRenderer;
mapRenderer = NULL;
delete waterRenderer;
waterRenderer = NULL;
waterRenderer.reset();
delete ambientShadowRenderer;
ambientShadowRenderer = NULL;
shadowMapRenderer.reset();
@ -221,8 +257,6 @@ namespace spades {
cameraBlur = NULL;
delete longSpriteRenderer;
longSpriteRenderer = NULL;
delete waterRenderer;
waterRenderer = NULL;
delete modelRenderer;
modelRenderer = NULL;
delete spriteRenderer;
@ -235,8 +269,7 @@ namespace spades {
programManager = NULL;
delete imageManager;
imageManager = NULL;
delete fbManager;
fbManager = NULL;
fbManager.reset();
profiler.reset();
SPLog("GLRenderer finalized");
}
@ -301,8 +334,7 @@ namespace spades {
flatMapRenderer = NULL;
delete mapShadowRenderer;
mapShadowRenderer = NULL;
delete waterRenderer;
waterRenderer = NULL;
waterRenderer.reset();
delete ambientShadowRenderer;
ambientShadowRenderer = NULL;
@ -316,7 +348,7 @@ namespace spades {
SPLog("Creating Minimap Renderer");
flatMapRenderer = new GLFlatMapRenderer(*this, *newMap);
SPLog("Creating Water Renderer");
waterRenderer = new GLWaterRenderer(*this, newMap.get_pointer());
waterRenderer.reset(new GLWaterRenderer(*this, newMap.get_pointer()));
if (settings.r_radiosity) {
SPLog("Creating Ray-traced Ambient Occlusion Renderer");
@ -395,6 +427,16 @@ namespace spades {
mat.m[13] = 0.f;
mat.m[14] = -(far * near * 2.f) / c;
mat.m[15] = 0.f;
if (settings.r_temporalAA && temporalAAFilter) {
float jitterX = 1.0f / GetRenderWidth();
float jitterY = 1.0f / GetRenderHeight();
Vector2 jitter = temporalAAFilter->GetProjectionMatrixJitter();
jitterX *= jitter.x * 1.3f;
jitterY *= jitter.y * 1.3f;
mat = Matrix4::Translate(jitterX, jitterY, 0.0f) * mat;
}
projectionMatrix = mat;
}
@ -925,9 +967,22 @@ namespace spades {
}
if (settings.r_cameraBlur && !sceneDef.denyCameraBlur) {
if (!cameraBlur) {
cameraBlur = new GLCameraBlurFilter(*this);
}
GLProfiler::Context p(*profiler, "Camera Blur");
// FIXME: better (correctly constructed) radial blur algorithm
handle = cameraBlur->Filter(handle, sceneDef.radialBlur);
handle = cameraBlur->Filter(
handle, std::min(settings.r_cameraBlur * 0.2f, 1.0f), sceneDef.radialBlur);
}
if (settings.r_temporalAA) {
if (!temporalAAFilter) {
temporalAAFilter.reset(new GLTemporalAAFilter(*this));
}
GLProfiler::Context p(*profiler, "Temporal AA");
handle = temporalAAFilter->Filter(handle, settings.r_fxaa);
}
if (settings.r_bloom) {
@ -935,7 +990,7 @@ namespace spades {
handle = lensDustFilter->Filter(handle);
}
// do r_fxaa before lens filter so that color aberration looks nice
// Do r_fxaa before lens filter so that color aberration looks nice.
if (settings.r_fxaa) {
GLProfiler::Context p(*profiler, "FXAA");
handle = GLFXAAFilter(*this).Filter(handle);
@ -1015,18 +1070,41 @@ namespace spades {
tint = Mix(tint, MakeVector3(1.f, 1.f, 1.f), 0.2f);
tint *= 1.f / std::min(std::min(tint.x, tint.y), tint.z);
float fogLuminance = (fogColor.x + fogColor.y + fogColor.z) * (1.0f / 3.0f);
float exposure = powf(2.f, (float)settings.r_exposureValue * 0.5f);
handle = GLColorCorrectionFilter(*this).Filter(handle, tint * exposure);
handle =
GLColorCorrectionFilter(*this).Filter(handle, tint * exposure, fogLuminance);
// update smoothed fog color
smoothedFogColor = Mix(smoothedFogColor, fogColor, 0.002f);
}
}
// Resample the rendered image using a non-trivial filter if such
// a filter is selected.
int scaleFilter = settings.r_scaleFilter;
bool scalingMayBeNeeded = GetRenderWidth() != device->ScreenWidth() ||
GetRenderHeight() != device->ScreenHeight();
if (scaleFilter == 0) {
// Nearest neighbor - trivial
} else if (scaleFilter == 1) {
// Bi-linear - trivial
} else if (scaleFilter == 2) {
// Bi-cubic - non-trivial
handle = GLResampleBicubicFilter{*this}.Filter(handle, device->ScreenWidth(),
device->ScreenHeight());
scaleFilter = 0;
} else {
// I don't know this filter.
scaleFilter = 1;
}
if (settings.r_srgb && settings.r_srgb2D) {
// in gamma corrected mode,
// 2d drawings are done on gamma-corrected FB
// see also: FrameDone
// TODO: Handle the case where `scaleFilter == 0`
lastColorBufferTexture = handle.GetTexture();
device->BindFramebuffer(IGLDevice::Framebuffer, handle.GetFramebuffer());
device->Enable(IGLDevice::FramebufferSRGB, true);
@ -1038,15 +1116,34 @@ namespace spades {
GLProfiler::Context p(*profiler, "Copying to WM-given Framebuffer");
if (scaleFilter == 0) {
// Temporarily change the textute filter to NN
device->BindTexture(IGLDevice::Texture2D, handle.GetTexture());
device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
IGLDevice::Nearest);
device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter,
IGLDevice::Nearest);
}
device->BindFramebuffer(IGLDevice::Framebuffer, 0);
device->Enable(IGLDevice::Blend, false);
device->Viewport(0, 0, handle.GetWidth(), handle.GetHeight());
auto image = Handle<GLImage>::New(handle.GetTexture(), device.GetPointerOrNull(),
handle.GetWidth(), handle.GetHeight(), false);
device->Viewport(0, 0, device->ScreenWidth(), device->ScreenHeight());
Handle<GLImage> image(new GLImage(handle.GetTexture(), device.GetPointerOrNull(),
handle.GetWidth(), handle.GetHeight(), false),
false);
SetColorAlphaPremultiplied(MakeVector4(1, 1, 1, 1));
DrawImage(*image,
AABB2(0, handle.GetHeight(), handle.GetWidth(), -handle.GetHeight()));
DrawImage(*image, AABB2(0, device->ScreenHeight(), device->ScreenWidth(),
-device->ScreenHeight()));
imageRenderer->Flush();
if (scaleFilter == 0) {
// Reset the texture filter
device->BindTexture(IGLDevice::Texture2D, handle.GetTexture());
device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
IGLDevice::Linear);
device->TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter,
IGLDevice::Linear);
}
}
handle.Release();
@ -1058,9 +1155,7 @@ namespace spades {
modelRenderer->Clear();
// prepare for 2d drawing
device->BlendFunc(IGLDevice::One, IGLDevice::OneMinusSrcAlpha, IGLDevice::Zero,
IGLDevice::One);
device->Enable(IGLDevice::Blend, true);
Prepare2DRendering(true);
}
//#pragma mark - 2D Drawings
@ -1246,9 +1341,7 @@ namespace spades {
lastTime = sceneDef.time;
// ready for 2d draw of next frame
device->BlendFunc(IGLDevice::One, IGLDevice::OneMinusSrcAlpha, IGLDevice::Zero,
IGLDevice::One);
device->Enable(IGLDevice::Blend, true);
Prepare2DRendering(true);
profiler->EndFrame();
}
@ -1259,6 +1352,16 @@ namespace spades {
EnsureSceneNotStarted();
device->Swap();
UpdateRenderSize();
}
void GLRenderer::Prepare2DRendering(bool reset) {
device->BlendFunc(IGLDevice::One, IGLDevice::OneMinusSrcAlpha, IGLDevice::Zero,
IGLDevice::One);
device->Enable(IGLDevice::Blend, true);
device->BindFramebuffer(IGLDevice::Framebuffer, 0);
device->Viewport(0, 0, device->ScreenWidth(), device->ScreenHeight());
}
Handle<Bitmap> GLRenderer::ReadBitmap() {

View File

@ -55,6 +55,7 @@ namespace spades {
class GLLensDustFilter;
class GLSoftLitSpriteRenderer;
class GLAutoExposureFilter;
class GLTemporalAAFilter;
class GLProfiler;
class GLRenderer : public client::IRenderer, public client::IGameMapListener {
@ -69,10 +70,13 @@ namespace spades {
};
Handle<IGLDevice> device;
GLFramebufferManager *fbManager;
std::unique_ptr<GLFramebufferManager> fbManager;
client::GameMap *map; // TODO: get rid of raw pointers
GLSettings settings;
int renderWidth;
int renderHeight;
std::unique_ptr<GLProfiler> profiler;
bool inited;
@ -97,13 +101,14 @@ namespace spades {
GLModelRenderer *modelRenderer;
IGLSpriteRenderer *spriteRenderer;
GLLongSpriteRenderer *longSpriteRenderer;
GLWaterRenderer *waterRenderer;
std::unique_ptr<GLWaterRenderer> waterRenderer;
GLAmbientShadowRenderer *ambientShadowRenderer;
GLRadiosityRenderer *radiosityRenderer;
GLCameraBlurFilter *cameraBlur;
GLLensDustFilter *lensDustFilter;
GLAutoExposureFilter *autoExposureFilter;
std::unique_ptr<GLTemporalAAFilter> temporalAAFilter;
// used when r_ssao = 1. only valid while rendering objects
IGLDevice::UInteger ssaoBufferTexture;
@ -142,6 +147,10 @@ namespace spades {
void EnsureSceneStarted();
void EnsureSceneNotStarted();
void UpdateRenderSize();
void Prepare2DRendering(bool reset = false);
protected:
~GLRenderer();
@ -208,10 +217,13 @@ namespace spades {
float ScreenWidth() override;
float ScreenHeight() override;
int GetRenderWidth() const { return renderWidth; }
int GetRenderHeight() const { return renderHeight; }
GLSettings &GetSettings() { return settings; }
IGLDevice &GetGLDevice() { return *device; }
GLProfiler &GetGLProfiler() { return *profiler; }
GLFramebufferManager *GetFramebufferManager() { return fbManager; }
GLFramebufferManager *GetFramebufferManager() { return fbManager.get(); }
IGLShadowMapRenderer *GetShadowMapRenderer() { return shadowMapRenderer.get(); }
GLAmbientShadowRenderer *GetAmbientShadowRenderer() { return ambientShadowRenderer; }
GLMapShadowRenderer *GetMapShadowRenderer() { return mapShadowRenderer; }

View File

@ -0,0 +1,74 @@
/*
Copyright (c) 2021 yvt
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
#include <vector>
#include "GLProgram.h"
#include "GLProgramAttribute.h"
#include "GLProgramUniform.h"
#include "GLQuadRenderer.h"
#include "GLRenderer.h"
#include "GLResampleBicubicFilter.h"
#include "IGLDevice.h"
#include <Core/Debug.h>
#include <Core/Math.h>
namespace spades {
namespace draw {
GLResampleBicubicFilter::GLResampleBicubicFilter(GLRenderer &renderer)
: renderer(renderer) {
lens = renderer.RegisterProgram("Shaders/PostFilters/ResampleBicubic.program");
}
GLColorBuffer GLResampleBicubicFilter::Filter(GLColorBuffer input, int outputWidth,
int outputHeight) {
SPADES_MARK_FUNCTION();
IGLDevice &dev = renderer.GetGLDevice();
GLQuadRenderer qr(dev);
GLColorBuffer output =
input.GetManager()->CreateBufferHandle(outputWidth, outputHeight);
static GLProgramAttribute lensPosition("positionAttribute");
static GLProgramUniform lensTexture("mainTexture");
static GLProgramUniform inverseVP("inverseVP");
dev.Enable(IGLDevice::Blend, false);
lensPosition(lens);
lensTexture(lens);
inverseVP(lens);
lens->Use();
inverseVP.SetValue(1.f / input.GetWidth(), 1.f / input.GetHeight());
lensTexture.SetValue(0);
qr.SetCoordAttributeIndex(lensPosition());
dev.BindTexture(IGLDevice::Texture2D, input.GetTexture());
dev.BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer());
dev.Viewport(0, 0, output.GetWidth(), output.GetHeight());
qr.Draw();
dev.BindTexture(IGLDevice::Texture2D, 0);
return output;
}
} // namespace draw
} // namespace spades

View File

@ -0,0 +1,38 @@
/*
Copyright (c) 2013 yvt
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "GLFramebufferManager.h"
namespace spades {
namespace draw {
class GLRenderer;
class GLProgram;
class GLResampleBicubicFilter {
GLRenderer &renderer;
GLProgram *lens;
public:
GLResampleBicubicFilter(GLRenderer &);
GLColorBuffer Filter(GLColorBuffer, int outputWidth, int outputHeight);
};
} // namespace draw
} // namespace spades

View File

@ -85,7 +85,7 @@ namespace spades {
float kernelSize = std::max(1.0f, std::min(width, height) * 0.0018f);
sampleOffsetScale.SetValue(kernelSize / (float)width, kernelSize / (float)height);
if (width < dev.ScreenWidth()) {
if (width < renderer.GetRenderWidth()) {
// 2x downsampling
texCoordRange.SetValue(0.25f / width, 0.25f / height, 1.f, 1.f);
} else {
@ -127,6 +127,8 @@ namespace spades {
int w = width == -1 ? tex.GetWidth() : width;
int h = height == -1 ? tex.GetHeight() : height;
GLColorBuffer buf2 = renderer.GetFramebufferManager()->CreateBufferHandle(w, h, 1);
static GLProgramAttribute positionAttribute("positionAttribute");
static GLProgramUniform inputTexture("inputTexture");
static GLProgramUniform depthTexture("depthTexture");
@ -171,8 +173,6 @@ namespace spades {
zNearFar.SetValue(def.zNear, def.zFar);
qr.SetCoordAttributeIndex(positionAttribute());
GLColorBuffer buf2 = renderer.GetFramebufferManager()->CreateBufferHandle(w, h, 1);
dev.Viewport(0, 0, w, h);
dev.BindFramebuffer(IGLDevice::Framebuffer, buf2.GetFramebuffer());
qr.Draw();
@ -189,8 +189,8 @@ namespace spades {
IGLDevice &dev = renderer.GetGLDevice();
int width = dev.ScreenWidth();
int height = dev.ScreenHeight();
int width = renderer.GetRenderWidth();
int height = renderer.GetRenderHeight();
dev.Enable(IGLDevice::Blend, false);

View File

@ -57,12 +57,16 @@ DEFINE_SPADES_SETTING(r_optimizedVoxelModel, "1");
DEFINE_SPADES_SETTING(r_physicalLighting, "0");
DEFINE_SPADES_SETTING(r_radiosity, "0");
DEFINE_SPADES_SETTING(r_saturation, "1");
DEFINE_SPADES_SETTING(r_scale, "1");
DEFINE_SPADES_SETTING(r_scaleFilter, "1");
DEFINE_SPADES_SETTING(r_shadowMapSize, "2048");
DEFINE_SPADES_SETTING(r_sharpen, "1");
DEFINE_SPADES_SETTING(r_softParticles, "1");
DEFINE_SPADES_SETTING(r_sparseShadowMaps, "1");
DEFINE_SPADES_SETTING(r_srgb, "0");
DEFINE_SPADES_SETTING(r_srgb2D, "1");
DEFINE_SPADES_SETTING(r_ssao, "0");
DEFINE_SPADES_SETTING(r_temporalAA, "0");
DEFINE_SPADES_SETTING(r_water, "2");
namespace spades {

View File

@ -30,7 +30,7 @@ namespace spades {
// clang-format off
TypedItemHandle<bool> r_blitFramebuffer { *this, "r_blitFramebuffer" };
TypedItemHandle<bool> r_bloom { *this, "r_bloom" };
TypedItemHandle<bool> r_cameraBlur { *this, "r_cameraBlur", ItemFlags::Latch };
TypedItemHandle<float> r_cameraBlur { *this, "r_cameraBlur" };
TypedItemHandle<bool> r_colorCorrection { *this, "r_colorCorrection" };
TypedItemHandle<bool> r_debugTiming { *this, "r_debugTiming" };
TypedItemHandle<bool> r_debugTimingOutputScreen { *this, "r_debugTimingOutputScreen" };
@ -65,12 +65,16 @@ namespace spades {
TypedItemHandle<bool> r_physicalLighting { *this, "r_physicalLighting", ItemFlags::Latch };
TypedItemHandle<int> r_radiosity { *this, "r_radiosity", ItemFlags::Latch };
TypedItemHandle<float> r_saturation { *this, "r_saturation" };
TypedItemHandle<float> r_scale { *this, "r_scale" };
TypedItemHandle<int> r_scaleFilter { *this, "r_scaleFilter" };
TypedItemHandle<int> r_shadowMapSize { *this, "r_shadowMapSize", ItemFlags::Latch };
TypedItemHandle<int> r_softParticles { *this, "r_softParticles" };
TypedItemHandle<float> r_sharpen { *this, "r_sharpen" };
TypedItemHandle<int> r_softParticles { *this, "r_softParticles", ItemFlags::Latch };
TypedItemHandle<bool> r_sparseShadowMaps { *this, "r_sparseShadowMaps", ItemFlags::Latch };
TypedItemHandle<bool> r_srgb { *this, "r_srgb", ItemFlags::Latch };
TypedItemHandle<bool> r_srgb2D { *this, "r_srgb2D", ItemFlags::Latch };
TypedItemHandle<int> r_ssao { *this, "r_ssao", ItemFlags::Latch };
TypedItemHandle<bool> r_temporalAA { *this, "r_temporalAA" };
TypedItemHandle<int> r_water { *this, "r_water", ItemFlags::Latch };
// clang-format on
};

View File

@ -289,8 +289,8 @@ namespace spades {
ssaoTexture.SetValue(texStage);
texStage++;
ssaoTextureUVScale.SetValue(1.0f / renderer->ScreenWidth(),
1.0f / renderer->ScreenHeight());
ssaoTextureUVScale.SetValue(1.0f / renderer->GetRenderWidth(),
1.0f / renderer->GetRenderHeight());
}
}

View File

@ -321,7 +321,7 @@ namespace spades {
// low-res sprites
IGLDevice::UInteger lastFb = device.GetInteger(IGLDevice::FramebufferBinding);
int sW = device.ScreenWidth(), sH = device.ScreenHeight();
int sW = renderer.GetRenderWidth(), sH = renderer.GetRenderHeight();
int lW = (sW + 3) / 4, lH = (sH + 3) / 4;
int numLowResSprites = 0;
GLColorBuffer buf = renderer.GetFramebufferManager()->CreateBufferHandle(lW, lH, true);

View File

@ -214,7 +214,7 @@ namespace spades {
// low-res sprites
IGLDevice::UInteger lastFb = device.GetInteger(IGLDevice::FramebufferBinding);
int sW = device.ScreenWidth(), sH = device.ScreenHeight();
int sW = renderer.GetRenderWidth(), sH = renderer.GetRenderHeight();
int lW = (sW + 3) / 4, lH = (sH + 3) / 4;
int numLowResSprites = 0;
GLColorBuffer buf = renderer.GetFramebufferManager()->CreateBufferHandle(lW, lH, true);

View File

@ -240,10 +240,6 @@ namespace spades {
void GLSparseShadowMapRenderer::Render() {
SPADES_MARK_FUNCTION();
IGLDevice::Integer lastFb = device.GetInteger(IGLDevice::FramebufferBinding);
// client::SceneDefinition def = GetRenderer().GetSceneDef();
float nearDist = 0.f;
float farDist = 150.f;
@ -255,10 +251,6 @@ namespace spades {
device.Clear(IGLDevice::DepthBufferBit);
RenderShadowMapPass();
device.BindFramebuffer(IGLDevice::Framebuffer, lastFb);
device.Viewport(0, 0, device.ScreenWidth(), device.ScreenHeight());
}
#pragma mark - Sparse Processor

View File

@ -0,0 +1,381 @@
/*
Copyright (c) 2017 yvt
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
#include <vector>
#include "GLFXAAFilter.h"
#include "GLProfiler.h"
#include "GLProgram.h"
#include "GLProgramAttribute.h"
#include "GLProgramUniform.h"
#include "GLQuadRenderer.h"
#include "GLRenderer.h"
#include "GLTemporalAAFilter.h"
#include "IGLDevice.h"
#include <Core/Debug.h>
#include <Core/Math.h>
namespace spades {
namespace draw {
GLTemporalAAFilter::GLTemporalAAFilter(GLRenderer &renderer) : renderer(renderer) {
prevMatrix = Matrix4::Identity();
prevViewOrigin = Vector3(0.0f, 0.0f, 0.0f);
program = renderer.RegisterProgram("Shaders/PostFilters/TemporalAA.program");
// Preload
GLFXAAFilter{renderer};
}
GLTemporalAAFilter::~GLTemporalAAFilter() { DeleteHistoryBuffer(); }
void GLTemporalAAFilter::DeleteHistoryBuffer() {
if (!historyBuffer.valid) {
return;
}
IGLDevice &dev = renderer.GetGLDevice();
dev.DeleteFramebuffer(historyBuffer.framebuffer);
dev.DeleteTexture(historyBuffer.texture);
historyBuffer.valid = false;
}
GLColorBuffer GLTemporalAAFilter::Filter(GLColorBuffer input, bool useFxaa) {
SPADES_MARK_FUNCTION();
IGLDevice &dev = renderer.GetGLDevice();
GLQuadRenderer qr(dev);
// Calculate the current view-projection matrix.
const client::SceneDefinition &def = renderer.GetSceneDef();
Matrix4 newMatrix = Matrix4::Identity();
Vector3 axes[] = {def.viewAxis[0], def.viewAxis[1], def.viewAxis[2]};
newMatrix.m[0] = axes[0].x;
newMatrix.m[1] = axes[1].x;
newMatrix.m[2] = -axes[2].x;
newMatrix.m[4] = axes[0].y;
newMatrix.m[5] = axes[1].y;
newMatrix.m[6] = -axes[2].y;
newMatrix.m[8] = axes[0].z;
newMatrix.m[9] = axes[1].z;
newMatrix.m[10] = -axes[2].z;
Matrix4 projectionMatrix;
{
// From `GLRenderer::BuildProjectionMatrix`
float near = def.zNear;
float far = def.zFar;
float t = near * std::tan(def.fovY * .5f);
float r = near * std::tan(def.fovX * .5f);
float a = r * 2.f, b = t * 2.f, c = far - near;
Matrix4 &mat = projectionMatrix;
mat.m[0] = near * 2.f / a;
mat.m[1] = 0.f;
mat.m[2] = 0.f;
mat.m[3] = 0.f;
mat.m[4] = 0.f;
mat.m[5] = near * 2.f / b;
mat.m[6] = 0.f;
mat.m[7] = 0.f;
mat.m[8] = 0.f;
mat.m[9] = 0.f;
mat.m[10] = -(far + near) / c;
mat.m[11] = -1.f;
mat.m[12] = 0.f;
mat.m[13] = 0.f;
mat.m[14] = -(far * near * 2.f) / c;
mat.m[15] = 0.f;
}
newMatrix = projectionMatrix * newMatrix;
// In `y = newMatrix * x`, the coordinate space `y` belongs to must
// cover the clip region by range `[0, 1]` (like texture coordinates)
// instead of `[-1, 1]` (like OpenGL clip coordinates)
newMatrix = Matrix4::Translate(1.0f, 1.0f, 1.0f) * newMatrix;
newMatrix = Matrix4::Scale(0.5f, 0.5f, 0.5f) * newMatrix;
// Camera translation must be incorporated into the calculation
// separately to avoid numerical errors. (You'd be suprised to see
// how visible the visual artifacts can be.)
Matrix4 translationMatrix = Matrix4::Translate(def.viewOrigin - prevViewOrigin);
// Compute the reprojection matrix
Matrix4 inverseNewMatrix = newMatrix.Inversed();
Matrix4 diffMatrix = prevMatrix * translationMatrix * inverseNewMatrix;
prevMatrix = newMatrix;
prevViewOrigin = def.viewOrigin;
if (!historyBuffer.valid || historyBuffer.width != input.GetWidth() ||
historyBuffer.height != input.GetHeight()) {
DeleteHistoryBuffer();
historyBuffer.width = input.GetWidth();
historyBuffer.height = input.GetHeight();
auto internalFormat = renderer.GetFramebufferManager()->GetMainInternalFormat();
historyBuffer.framebuffer = dev.GenFramebuffer();
dev.BindFramebuffer(IGLDevice::Framebuffer, historyBuffer.framebuffer);
historyBuffer.texture = dev.GenTexture();
dev.BindTexture(IGLDevice::Texture2D, historyBuffer.texture);
historyBuffer.valid = true;
SPLog("Creating a history buffer");
dev.TexImage2D(IGLDevice::Texture2D, 0, internalFormat, historyBuffer.width,
historyBuffer.height, 0, IGLDevice::RGBA, IGLDevice::UnsignedByte,
NULL);
SPLog("History buffer allocated");
dev.TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
IGLDevice::Linear);
dev.TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMinFilter,
IGLDevice::Linear);
dev.TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapS,
IGLDevice::ClampToEdge);
dev.TexParamater(IGLDevice::Texture2D, IGLDevice::TextureWrapT,
IGLDevice::ClampToEdge);
dev.FramebufferTexture2D(IGLDevice::Framebuffer, IGLDevice::ColorAttachment0,
IGLDevice::Texture2D, historyBuffer.texture, 0);
IGLDevice::Enum status = dev.CheckFramebufferStatus(IGLDevice::Framebuffer);
if (status != IGLDevice::FramebufferComplete) {
SPRaise("Failed to create a history buffer.");
}
SPLog("Created a history framebuffer");
// Initialize the history buffer with the latest input
dev.BindFramebuffer(IGLDevice::DrawFramebuffer, historyBuffer.framebuffer);
dev.BindFramebuffer(IGLDevice::ReadFramebuffer, input.GetFramebuffer());
dev.BlitFramebuffer(0, 0, input.GetWidth(), input.GetHeight(), 0, 0,
input.GetWidth(), input.GetHeight(), IGLDevice::ColorBufferBit,
IGLDevice::Nearest);
dev.BindFramebuffer(IGLDevice::ReadFramebuffer, 0);
dev.BindFramebuffer(IGLDevice::DrawFramebuffer, 0);
// Reset the blending factor
dev.BindFramebuffer(IGLDevice::Framebuffer, historyBuffer.framebuffer);
dev.ColorMask(false, false, false, true);
dev.ClearColor(0.0f, 0.0f, 0.0f, 0.5f);
dev.Clear(IGLDevice::ColorBufferBit);
dev.ColorMask(true, true, true, true);
if (useFxaa) {
return GLFXAAFilter{renderer}.Filter(input);
}
return input;
}
GLColorBuffer output = input.GetManager()->CreateBufferHandle();
GLColorBuffer processedInput = input;
/* // this didn't work well:
GLColorBuffer processedInput =
useFxaa ? [&] {
GLProfiler::Context p(renderer.GetGLProfiler(), "FXAA");
return GLFXAAFilter{renderer}.Filter(input);
}() : input; */
static GLProgramAttribute positionAttribute("positionAttribute");
static GLProgramUniform inputTexture("inputTexture");
static GLProgramUniform depthTexture("depthTexture");
static GLProgramUniform previousTexture("previousTexture");
static GLProgramUniform processedInputTexture("processedInputTexture");
static GLProgramUniform reprojectionMatrix("reprojectionMatrix");
static GLProgramUniform inverseVP("inverseVP");
dev.Enable(IGLDevice::Blend, false);
positionAttribute(program);
inputTexture(program);
depthTexture(program);
previousTexture(program);
processedInputTexture(program);
reprojectionMatrix(program);
inverseVP(program);
program->Use();
inputTexture.SetValue(0);
previousTexture.SetValue(1);
processedInputTexture.SetValue(2);
depthTexture.SetValue(3);
reprojectionMatrix.SetValue(diffMatrix);
inverseVP.SetValue(1.f / input.GetWidth(), 1.f / input.GetHeight());
// Perform temporal AA
// TODO: pre/post tone mapping to prevent aliasing near overbright area
qr.SetCoordAttributeIndex(positionAttribute());
dev.ActiveTexture(0);
dev.BindTexture(IGLDevice::Texture2D, input.GetTexture());
dev.ActiveTexture(1);
dev.BindTexture(IGLDevice::Texture2D, historyBuffer.texture);
dev.ActiveTexture(2);
dev.BindTexture(IGLDevice::Texture2D, processedInput.GetTexture());
dev.ActiveTexture(3);
dev.BindTexture(IGLDevice::Texture2D,
renderer.GetFramebufferManager()->GetDepthTexture());
dev.ActiveTexture(0);
dev.BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer());
dev.Viewport(0, 0, output.GetWidth(), output.GetHeight());
qr.Draw();
dev.BindTexture(IGLDevice::Texture2D, 0);
// Copy the result to the history buffer
dev.BindFramebuffer(IGLDevice::DrawFramebuffer, historyBuffer.framebuffer);
dev.BindFramebuffer(IGLDevice::ReadFramebuffer, output.GetFramebuffer());
dev.BlitFramebuffer(0, 0, input.GetWidth(), input.GetHeight(), 0, 0, input.GetWidth(),
input.GetHeight(), IGLDevice::ColorBufferBit, IGLDevice::Nearest);
dev.BindFramebuffer(IGLDevice::ReadFramebuffer, 0);
dev.BindFramebuffer(IGLDevice::DrawFramebuffer, 0);
return output;
}
Vector2 GLTemporalAAFilter::GetProjectionMatrixJitter() {
// Obtained from Hyper3D (MIT licensed)
static const std::vector<float> jitterTable = {
0.281064, 0.645281, -0.167313, 0.685935, -0.160711, -0.113289,
1.08453, -0.0970135, -0.3655, -0.51894, 0.275308, -0.000830889,
-0.0431051, 0.574405, -0.163071, -0.30989, 0.372959, -0.0161521,
0.131741, 0.456781, 0.0165477, -0.0975113, -0.273682, -0.509164,
0.573244, -0.714618, -0.479023, 0.0525875, 0.316595, -0.148211,
-0.423713, -0.22462, -0.528986, 0.390866, 0.0439115, -0.274567,
0.106133, -0.377686, 0.481055, 0.398664, 0.314325, 0.839894,
-0.625382, 0.0543475, -0.201899, 0.198677, 0.0182834, 0.621111,
0.128773, -0.265686, 0.602337, 0.296946, 0.773769, 0.0479956,
-0.132997, -0.0410526, -0.254838, 0.326185, 0.347585, -0.580061,
0.405482, 0.101755, -0.201249, 0.306534, 0.469578, -0.111657,
-0.796765, -0.0773768, -0.538891, 0.206104, -0.0794146, 0.098465,
0.413728, 0.0259771, -0.823897, 0.0925169, 0.88273, -0.184931,
-0.134422, -0.247737, -0.682095, 0.177566, 0.299386, -0.329205,
0.0488276, 0.504052, 0.268825, 0.395508, -1.10225, 0.101069,
-0.0408943, -0.580797, -0.00804806, -0.402047, -0.418787, 0.697977,
-0.308492, -0.122199, 0.628944, 0.54588, 0.0622768, -0.488552,
0.0474367, 0.215963, -0.679212, 0.311237, -0.000920773, -0.721814,
0.579613, -0.0458724, -0.467233, 0.268248, 0.246741, -0.15576,
0.0473638, 0.0246596, -0.572414, -0.419131, -0.357526, 0.452787,
-0.112269, 0.710673, -0.41551, 0.429337, 0.0882859, -0.433878,
-0.0818105, -0.180361, 0.36754, -0.49486, 0.449489, -0.837214,
-1.09047, 0.168766, -0.163687, 0.256186, 0.633943, -0.012522,
0.631576, -0.27161, -0.15392, -0.471082, -0.071748, -0.275351,
-0.134404, 0.126987, -0.478438, -0.144772, -0.38336, 0.37449,
-0.458729, -0.318997, -0.313852, 0.081244, -0.287645, 0.200266,
-0.45997, 0.108317, -0.216842, -0.165177, -0.296687, 0.771041,
0.933613, 0.617833, -0.263007, -0.236543, -0.406302, 0.241173,
-0.225985, -0.108225, 0.087069, -0.0444767, 0.645569, -0.112983,
-0.689477, 0.498425, 0.0738087, 0.447277, 0.0972104, -0.314627,
0.393365, -0.0919185, -0.32199, -0.193414, -0.126091, 0.185217,
0.318475, 0.140509, -0.115877, -0.911059, 0.336104, -0.645395,
0.00686884, -0.172296, -0.513633, -0.302956, -1.20699, 0.148284,
0.357629, 0.58123, 0.106886, -0.872183, -0.49183, -0.202535,
-0.869357, 0.0371933, -0.0869231, 0.22624, 0.198995, 0.191016,
0.151591, 0.347114, 0.056674, -0.213039, -0.228541, -0.473257,
-0.574876, -0.0826995, -0.730448, 0.343791, 0.795006, 0.366191,
0.419235, -1.11688, 0.227321, -0.0937171, 0.156708, -0.3307,
0.328026, -0.454046, 0.432153, -0.189323, 0.31821, 0.312532,
0.0963759, 0.126471, -0.396326, 0.0353236, -0.366891, -0.279321,
0.106791, 0.0697961, 0.383726, 0.260039, 0.00297499, 0.45812,
-0.544967, -0.230453, -0.150821, -0.374241, -0.739835, 0.462278,
-0.76681, -0.455701, 0.261229, 0.274824, 0.161605, -0.402379,
0.571192, 0.0844102, -0.47416, 0.683535, 0.144919, -0.134556,
-0.0414159, 0.357005, -0.643226, -0.00324917, -0.173286, 0.770447,
0.261563, 0.707628, 0.131681, 0.539707, -0.367105, 0.150912,
-0.310055, -0.270554, 0.686523, 0.195065, 0.282361, 0.569649,
0.106642, 0.296521, 0.185682, 0.124763, 0.182832, 0.42824,
-0.489455, 0.55954, 0.383582, 0.52804, -0.236162, -0.356153,
0.70445, -0.300133, 1.06101, 0.0289559, 0.4671, -0.0455821,
-1.18106, 0.26797, 0.223324, 0.793996, -0.833809, -0.412982,
-0.443497, -0.634181, -0.000902414, -0.319155, 0.629076, -0.378669,
-0.230422, 0.489184, 0.122302, 0.397895, 0.421496, -0.41475,
0.192182, -0.477254, -0.32989, 0.285264, -0.0248513, -0.224073,
0.520192, 0.138148, 0.783388, 0.540348, -0.468401, 0.189778,
0.327808, 0.387399, 0.0163817, 0.340137, -0.174623, -0.560019,
-0.32246, 0.353305, 0.513422, -0.472848, -0.0151656, 0.0802364,
-0.0833406, 0.000303745, -0.359159, -0.666926, 0.446711, -0.254889,
-0.263977, 0.534997, 0.555322, -0.315034, -0.62762, -0.14342,
-0.78082, 0.29739, 0.0783401, -0.665565, -0.177726, 0.62018,
-0.723053, 0.108446, 0.550657, 0.00324011, 0.387362, -0.251661,
-0.616413, -0.260163, -0.798613, 0.0174665, -0.208833, -0.0398486,
-0.506167, 0.00121689, -0.75707, -0.0326216, 0.30282, 0.085227,
-0.27267, 0.25662, 0.182456, -0.184061, -0.577699, -0.685311,
0.587003, 0.35393, -0.276868, -0.0617566, -0.365888, 0.673723,
-0.0476918, -0.0914235, 0.560627, -0.387913, -0.194537, 0.135256,
-0.0808623, 0.315394, -0.0383463, 0.267406, 0.545766, -0.659403,
-0.410556, 0.305285, 0.0364261, 0.396365, -0.284096, 0.137003,
0.611792, 0.191185, 0.440866, 0.87738, 0.470405, -0.372227,
-0.84977, 0.676291, -0.0709138, -0.456707, 0.222892, -0.728947,
0.2414, 0.109269, 0.707531, 0.027894, -0.381266, -0.1872,
-0.674006, -0.441284, -0.151681, -0.695721, 0.360165, -0.397063,
0.02772, 0.271526, -0.170258, -0.198509, 0.524165, 0.29589,
-0.895699, -0.266005, 0.0971003, 0.640709, -0.169635, 0.0263381,
-0.779951, -0.37692, -0.703577, 0.00526047, -0.822414, -0.152364,
0.10004, 0.194787, 0.453202, -0.495236, 1.01192, -0.682168,
-0.453866, 0.387515, -0.355192, 0.214262, 0.2677, -0.263514,
0.334733, 0.683574, 0.181592, 0.599759, -0.182972, 0.402297,
-0.319075, 0.553958, -0.990873, -0.143754, 0.506054, 0.0535431,
-0.647583, 0.53928, -0.510285, 0.452258, -0.796479, 0.186279,
-0.0960782, -0.124537, 0.509105, -0.1712, 0.219554, -0.528307,
-0.377211, -0.447177, -0.0283537, 0.856948, -0.128052, 0.482509,
0.528981, -0.785958, 0.816482, 0.213728, -0.433917, -0.0413878,
-0.997625, 0.228201, -0.113198, 0.425206, 0.0261474, 0.68678,
0.224967, 0.48489, 0.53184, 0.572936, -0.419627, -0.70428,
-0.216836, 0.57302, 0.640487, -0.172722, 0.237492, -0.390903,
0.0717416, 0.852097, -0.0422118, 0.151465, -0.638427, 0.132246,
-0.0552788, 0.436714, -0.281931, 0.411517, -0.340499, -0.725834,
-0.478547, 0.332275, -0.0243354, -0.499295, 0.238681, -0.324647,
-0.182754, 0.520306, -0.0762625, 0.631812, -0.652095, -0.504378,
-0.534564, 0.118165, -0.384134, 0.611485, 0.635868, 0.100705,
0.25619, 0.197184, 0.328731, -0.0750947, -0.763023, 0.516191,
0.375317, -0.17778, 0.880709, 0.668956, 0.376694, 0.425053,
-0.930982, 0.0534644, -0.0423658, 0.695356, 0.352989, 0.0400925,
0.383482, 0.188746, 0.0193305, 0.128885, -0.23603, -0.288163,
-0.311799, -0.425027, -0.297739, -0.349681, -0.278894, 0.00934887,
-0.38221, 0.542819, 0.234533, -0.213422, 0.198418, 0.694582,
-0.43395, -0.417672, 0.553686, -0.10748, -0.352711, -0.0115025,
0.0581546, 0.962054, 0.210576, 0.339536, -0.0818458, -0.358587,
-0.342001, -0.0689676, 0.0470595, -0.3791, 0.212149, -0.00608754,
0.318279, 0.246769, 0.514428, 0.457749, 0.759536, 0.236433,
0.422228, 0.571146, -0.247402, 0.667306, -0.558038, -0.158556,
-0.369374, -0.341798, 0.30697, -0.535024, -0.487844, -0.0888073,
0.404439, -0.580029, 0.457389, 0.297961, -0.0356712, 0.508803,
0.325652, -0.239089, -0.743984, 0.21902, 0.455838, 0.149938,
-0.150058, 0.342239, 0.147549, -0.044282, -0.634129, 0.266822,
-0.764306, -0.13691, -0.59542, -0.503302, -0.581097, 0.455914,
0.193022, -0.255091, 0.0782733, 0.354385, 0.181455, -0.579845,
-0.597151, -0.747541, -0.471478, -0.257622, 0.80429, 0.908564,
0.11331, -0.210526, 0.893246, -0.354708, -0.581153, 0.366957,
0.000682831, 1.05443, 0.310998, 0.455284, -0.251732, -0.567471,
-0.660306, -0.202108, 0.836359, -0.467352, -0.20453, 0.0710459,
0.0628843, -0.132979, -0.755594, 0.0600963, 0.725805, -0.221625,
0.133578, -0.802764, 0.00850201, 0.748137, -0.411616, -0.136451,
0.0531707, -0.977616, 0.162951, 0.0394506, -0.0480862, 0.797194,
0.52012, 0.238174, 0.169073, 0.249234, 0.00133944, -0.01138,
0.107195, 0.0101681, -0.247766, -0.415877, -0.450288, 0.800731};
jitterTableIndex += 2;
if (jitterTableIndex == jitterTable.size()) {
jitterTableIndex = 0;
}
return Vector2{jitterTable[jitterTableIndex], jitterTable[jitterTableIndex + 1]};
}
} // namespace draw
} // namespace spades

View File

@ -0,0 +1,62 @@
/*
Copyright (c) 2017 yvt
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "GLFramebufferManager.h"
namespace spades {
namespace draw {
class GLRenderer;
class GLProgram;
/**
* Implementation of the temporal anti-aliasing filter.
*
* The current implementation requires `BlitFramebuffer` for simplicity.
*/
class GLTemporalAAFilter {
GLRenderer &renderer;
GLProgram *program;
struct HistoryBuffer {
bool valid = false;
int width, height;
IGLDevice::UInteger framebuffer;
IGLDevice::UInteger texture;
} historyBuffer;
Matrix4 prevMatrix;
Vector3 prevViewOrigin;
std::size_t jitterTableIndex = 0;
void DeleteHistoryBuffer();
public:
GLTemporalAAFilter(GLRenderer &);
~GLTemporalAAFilter();
Vector2 GetProjectionMatrixJitter();
GLColorBuffer Filter(GLColorBuffer, bool useFxaa);
};
}
}

View File

@ -472,7 +472,7 @@ namespace spades {
tempDepthTexture = device.GenTexture();
device.BindTexture(IGLDevice::Texture2D, tempDepthTexture);
device.TexImage2D(IGLDevice::Texture2D, 0, IGLDevice::DepthComponent24,
device.ScreenWidth(), device.ScreenHeight(), 0,
renderer.GetRenderWidth(), renderer.GetRenderHeight(), 0,
IGLDevice::DepthComponent, IGLDevice::UnsignedInt, NULL);
device.TexParamater(IGLDevice::Texture2D, IGLDevice::TextureMagFilter,
IGLDevice::Nearest);

Some files were not shown because too many files have changed in this diff Show More