diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/debian/changelog rbdoom3bfg-1.2.0+dfsg~git20181013/debian/changelog --- rbdoom3bfg-1.2.0+dfsg~git20180605/debian/changelog 2018-11-24 01:04:12.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/debian/changelog 2018-12-30 00:40:24.000000000 +0000 @@ -1,8 +1,11 @@ -rbdoom3bfg (1.2.0+dfsg~git20180605-1build1) disco; urgency=medium +rbdoom3bfg (1.2.0+dfsg~git20181013-1) unstable; urgency=medium - * No-change rebuild against latest glew + * New upstream git snaphot. + - Removing applied patches: 50-system-rapidjson and 90-gcc-fix. + - Refresh patch 10-lowercase-executable. + * Bump SV to 4.3.0 -- no changes required - -- Jeremy Bicha Fri, 23 Nov 2018 20:04:12 -0500 + -- Tobias Frost Sun, 30 Dec 2018 01:40:24 +0100 rbdoom3bfg (1.2.0+dfsg~git20180605-1) unstable; urgency=medium diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/debian/control rbdoom3bfg-1.2.0+dfsg~git20181013/debian/control --- rbdoom3bfg-1.2.0+dfsg~git20180605/debian/control 2018-08-12 10:22:56.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/debian/control 2018-12-30 00:33:35.000000000 +0000 @@ -16,7 +16,7 @@ libswscale-dev, rapidjson-dev, zlib1g-dev -Standards-Version: 4.1.4 +Standards-Version: 4.3.0 Homepage: https://github.com/RobertBeckebans/RBDOOM-3-BFG VCS-Browser: https://salsa.debian.org/games-team/rbdoom3bfg VCS-Git: https://salsa.debian.org/games-team/rbdoom3bfg.git diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/debian/patches/10-lowercase-executable.patch rbdoom3bfg-1.2.0+dfsg~git20181013/debian/patches/10-lowercase-executable.patch --- rbdoom3bfg-1.2.0+dfsg~git20180605/debian/patches/10-lowercase-executable.patch 2018-08-12 10:22:56.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/debian/patches/10-lowercase-executable.patch 2018-12-30 00:09:44.000000000 +0000 @@ -2,10 +2,10 @@ Fix CMake to lowercase the binary name to rbdoom3bfg Author: Tobias Frost Forwarded: no, Debian specific -Last-Update: 2014-10-07 +Last-Update: 2018-12-30 --- a/neo/CMakeLists.txt +++ b/neo/CMakeLists.txt -@@ -1492,14 +1492,14 @@ +@@ -1524,14 +1524,14 @@ add_dependencies(precomp_header_rbdoom3bfg idlib) endif() @@ -23,7 +23,7 @@ endif() if(NOT WIN32) -@@ -1507,7 +1507,7 @@ +@@ -1539,7 +1539,7 @@ set(RT_LIBRARY rt) endif() diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/debian/patches/50-system-rapidjson.patch rbdoom3bfg-1.2.0+dfsg~git20181013/debian/patches/50-system-rapidjson.patch --- rbdoom3bfg-1.2.0+dfsg~git20180605/debian/patches/50-system-rapidjson.patch 2018-08-12 10:22:56.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/debian/patches/50-system-rapidjson.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,152 +0,0 @@ -Description: Patch to be able to use Debian's rapidjson - This patch adds the CMake-snippet and the necessary changes to be able to - compile with the pacakged rapidjson. -Author: Tobias Frost -Forwarded: https://github.com/RobertBeckebans/RBDOOM-3-BFG/pull/351 -Last-Update: 2016-10-11 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ ---- a/neo/CMakeLists.txt -+++ b/neo/CMakeLists.txt -@@ -41,6 +41,9 @@ - - option(USE_SYSTEM_LIBGLEW - "Use the system libglew instead of the bundled one" OFF) -+ -+option(USE_SYSTEM_RAPIDJSON -+ "Use the system rapidjson instead of the bundled one" OFF) - - set(CPU_TYPE "" CACHE STRING "When set, passes this string as CPU-ID which will be embedded into the binary.") - -@@ -273,6 +276,17 @@ - add_definitions(-DGLEW_STATIC) - endif (GLEW_FOUND) - -+if(USE_SYSTEM_RAPIDJSON) -+find_package(rapidjson REQUIRED) -+endif(USE_SYSTEM_RAPIDJSON) -+ -+if (RAPIDJSON_FOUND) -+ include_directories("${RAPIDJSON_INCLUDE_DIRS}") -+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RAPIDJSON_CXX_FLAGS}") -+else (RAPIDJSON_FOUND) -+ include_directories("libs/rapidjson/include") -+endif (RAPIDJSON_FOUND) -+ - add_subdirectory(idlib) - - file(GLOB AAS_INCLUDES aas/*.h) ---- /dev/null -+++ b/neo/cmake/Findrapidjson.cmake -@@ -0,0 +1,97 @@ -+# Copyright (c) 2011 Milo Yip (miloyip@gmail.com) -+# Copyright (c) 2013 Rafal Jeczalik (rjeczalik@gmail.com) -+# Distributed under the MIT License (see license.txt file) -+ -+# ----------------------------------------------------------------------------------- -+# -+# Finds the rapidjson library -+# -+# ----------------------------------------------------------------------------------- -+# -+# Variables used by this module, they can change the default behaviour. -+# Those variables need to be either set before calling find_package -+# or exported as environment variables before running CMake: -+# -+# RAPIDJSON_INCLUDEDIR - Set custom include path, useful when rapidjson headers are -+# outside system paths -+# RAPIDJSON_USE_SSE2 - Configure rapidjson to take advantage of SSE2 capabilities -+# RAPIDJSON_USE_SSE42 - Configure rapidjson to take advantage of SSE4.2 capabilities -+# -+# ----------------------------------------------------------------------------------- -+# -+# Variables defined by this module: -+# -+# RAPIDJSON_FOUND - True if rapidjson was found -+# RAPIDJSON_INCLUDE_DIRS - Path to rapidjson include directory -+# RAPIDJSON_CXX_FLAGS - Extra C++ flags required for compilation with rapidjson -+# -+# ----------------------------------------------------------------------------------- -+# -+# Example usage: -+# -+# set(RAPIDJSON_USE_SSE2 ON) -+# set(RAPIDJSON_INCLUDEDIR "/opt/github.com/rjeczalik/rapidjson/include") -+# -+# find_package(rapidjson REQUIRED) -+# -+# include_directories("${RAPIDJSON_INCLUDE_DIRS}") -+# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RAPIDJSON_CXX_FLAGS}") -+# add_executable(foo foo.cc) -+# -+# ----------------------------------------------------------------------------------- -+ -+foreach(opt RAPIDJSON_INCLUDEDIR RAPIDJSON_USE_SSE2 RAPIDJSON_USE_SSE42) -+ if(${opt} AND DEFINED ENV{${opt}} AND NOT ${opt} STREQUAL "$ENV{${opt}}") -+ message(WARNING "Conflicting ${opt} values: ignoring environment variable and using CMake cache entry.") -+ elseif(DEFINED ENV{${opt}} AND NOT ${opt}) -+ set(${opt} "$ENV{${opt}}") -+ endif() -+endforeach() -+ -+find_path( -+ RAPIDJSON_INCLUDE_DIRS -+ NAMES rapidjson/rapidjson.h -+ PATHS ${RAPIDJSON_INCLUDEDIR} -+ DOC "Include directory for the rapidjson library." -+) -+ -+mark_as_advanced(RAPIDJSON_INCLUDE_DIRS) -+ -+if(RAPIDJSON_INCLUDE_DIRS) -+ set(RAPIDJSON_FOUND TRUE) -+endif() -+ -+mark_as_advanced(RAPIDJSON_FOUND) -+ -+if(RAPIDJSON_USE_SSE42) -+ set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE42") -+ if(MSVC) -+ set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE4.2") -+ else() -+ set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse4.2") -+ endif() -+else() -+ if(RAPIDJSON_USE_SSE2) -+ set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE2") -+ if(MSVC) -+ set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE2") -+ else() -+ set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse2") -+ endif() -+ endif() -+endif() -+ -+mark_as_advanced(RAPIDJSON_CXX_FLAGS) -+ -+if(RAPIDJSON_FOUND) -+ if(NOT rapidjson_FIND_QUIETLY) -+ message(STATUS "Found rapidjson header files in ${RAPIDJSON_INCLUDE_DIRS}") -+ if(DEFINED RAPIDJSON_CXX_FLAGS) -+ message(STATUS "Found rapidjson C++ extra compilation flags: ${RAPIDJSON_CXX_FLAGS}") -+ endif() -+ endif() -+elseif(rapidjson_FIND_REQUIRED) -+ message(FATAL_ERROR "Could not find rapidjson") -+else() -+ message(STATUS "Optional package rapidjson was not found") -+endif() ---- a/neo/idlib/precompiled.h -+++ b/neo/idlib/precompiled.h -@@ -105,7 +105,10 @@ - #include "../ui/UserInterface.h" - - // RB: required for SWF extensions --#include "../libs/rapidjson/include/rapidjson/document.h" -+//#include "../libs/rapidjson/include/rapidjson/document.h" -+#include "rapidjson/document.h" -+ -+ - - #include "../swf/SWF.h" - diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/debian/patches/90-gcc-fix.patch rbdoom3bfg-1.2.0+dfsg~git20181013/debian/patches/90-gcc-fix.patch --- rbdoom3bfg-1.2.0+dfsg~git20180605/debian/patches/90-gcc-fix.patch 2018-08-20 17:09:13.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/debian/patches/90-gcc-fix.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -Description: Compilation failure due to -Werror=format-overflow with g++ 8.1.0 -Origin: https://github.com/RobertBeckebans/RBDOOM-3-BFG/issues/419 -Last-Update: 2018-08-20 - ---- rbdoom3bfg-1.1.0~preview3+dfsg+git20180204.orig/doomclassic/doom/p_setup.cpp -+++ rbdoom3bfg-1.1.0~preview3+dfsg+git20180204/doomclassic/doom/p_setup.cpp -@@ -656,9 +656,9 @@ P_SetupLevel - if ( ::g->gamemode == commercial) - { - if (map<10) -- sprintf (lumpname,"map0%i", map); -+ sprintf (lumpname,"map0%i", map % 100); - else -- sprintf (lumpname,"map%i", map); -+ sprintf (lumpname,"map%i", map % 100); - } - else - { diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/debian/patches/series rbdoom3bfg-1.2.0+dfsg~git20181013/debian/patches/series --- rbdoom3bfg-1.2.0+dfsg~git20180605/debian/patches/series 2018-08-20 16:55:14.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/debian/patches/series 2018-12-30 00:00:27.000000000 +0000 @@ -3,7 +3,5 @@ 20-reproducible.patch #30-init-sdl2.patch 40-libpng16.patch -50-system-rapidjson.patch 60-spelling-errors.patch 80-gcc7.fix -90-gcc-fix.patch diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/doomclassic/doom/p_setup.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/doomclassic/doom/p_setup.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/doomclassic/doom/p_setup.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/doomclassic/doom/p_setup.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -656,9 +656,9 @@ if ( ::g->gamemode == commercial) { if (map<10) - sprintf (lumpname,"map0%i", map); + sprintf (lumpname, "map0%i", map % 100); else - sprintf (lumpname,"map%i", map); + sprintf (lumpname, "map%i", map % 100); } else { diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/doomclassic/doom/r_segs.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/doomclassic/doom/r_segs.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/doomclassic/doom/r_segs.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/doomclassic/doom/r_segs.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -368,7 +368,7 @@ // calculate ::g->rw_distance for scale calculation ::g->rw_normalangle = ::g->curline->angle + ANG90; - offsetangle = abs((long)(::g->rw_normalangle-::g->rw_angle1)); + offsetangle = abs((int)(::g->rw_normalangle-::g->rw_angle1)); if (offsetangle > ANG90) offsetangle = ANG90; diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/cmake/Findrapidjson.cmake rbdoom3bfg-1.2.0+dfsg~git20181013/neo/cmake/Findrapidjson.cmake --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/cmake/Findrapidjson.cmake 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/cmake/Findrapidjson.cmake 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,97 @@ +# Copyright (c) 2011 Milo Yip (miloyip@gmail.com) +# Copyright (c) 2013 Rafal Jeczalik (rjeczalik@gmail.com) +# Distributed under the MIT License (see license.txt file) + +# ----------------------------------------------------------------------------------- +# +# Finds the rapidjson library +# +# ----------------------------------------------------------------------------------- +# +# Variables used by this module, they can change the default behaviour. +# Those variables need to be either set before calling find_package +# or exported as environment variables before running CMake: +# +# RAPIDJSON_INCLUDEDIR - Set custom include path, useful when rapidjson headers are +# outside system paths +# RAPIDJSON_USE_SSE2 - Configure rapidjson to take advantage of SSE2 capabilities +# RAPIDJSON_USE_SSE42 - Configure rapidjson to take advantage of SSE4.2 capabilities +# +# ----------------------------------------------------------------------------------- +# +# Variables defined by this module: +# +# RAPIDJSON_FOUND - True if rapidjson was found +# RAPIDJSON_INCLUDE_DIRS - Path to rapidjson include directory +# RAPIDJSON_CXX_FLAGS - Extra C++ flags required for compilation with rapidjson +# +# ----------------------------------------------------------------------------------- +# +# Example usage: +# +# set(RAPIDJSON_USE_SSE2 ON) +# set(RAPIDJSON_INCLUDEDIR "/opt/github.com/rjeczalik/rapidjson/include") +# +# find_package(rapidjson REQUIRED) +# +# include_directories("${RAPIDJSON_INCLUDE_DIRS}") +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RAPIDJSON_CXX_FLAGS}") +# add_executable(foo foo.cc) +# +# ----------------------------------------------------------------------------------- + +foreach(opt RAPIDJSON_INCLUDEDIR RAPIDJSON_USE_SSE2 RAPIDJSON_USE_SSE42) + if(${opt} AND DEFINED ENV{${opt}} AND NOT ${opt} STREQUAL "$ENV{${opt}}") + message(WARNING "Conflicting ${opt} values: ignoring environment variable and using CMake cache entry.") + elseif(DEFINED ENV{${opt}} AND NOT ${opt}) + set(${opt} "$ENV{${opt}}") + endif() +endforeach() + +find_path( + RAPIDJSON_INCLUDE_DIRS + NAMES rapidjson/rapidjson.h + PATHS ${RAPIDJSON_INCLUDEDIR} + DOC "Include directory for the rapidjson library." +) + +mark_as_advanced(RAPIDJSON_INCLUDE_DIRS) + +if(RAPIDJSON_INCLUDE_DIRS) + set(RAPIDJSON_FOUND TRUE) +endif() + +mark_as_advanced(RAPIDJSON_FOUND) + +if(RAPIDJSON_USE_SSE42) + set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE42") + if(MSVC) + set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE4.2") + else() + set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse4.2") + endif() +else() + if(RAPIDJSON_USE_SSE2) + set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE2") + if(MSVC) + set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE2") + else() + set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse2") + endif() + endif() +endif() + +mark_as_advanced(RAPIDJSON_CXX_FLAGS) + +if(RAPIDJSON_FOUND) + if(NOT rapidjson_FIND_QUIETLY) + message(STATUS "Found rapidjson header files in ${RAPIDJSON_INCLUDE_DIRS}") + if(DEFINED RAPIDJSON_CXX_FLAGS) + message(STATUS "Found rapidjson C++ extra compilation flags: ${RAPIDJSON_CXX_FLAGS}") + endif() + endif() +elseif(rapidjson_FIND_REQUIRED) + message(FATAL_ERROR "Could not find rapidjson") +else() + message(STATUS "Optional package rapidjson was not found") +endif() diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/CMakeLists.txt rbdoom3bfg-1.2.0+dfsg~git20181013/neo/CMakeLists.txt --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/CMakeLists.txt 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/CMakeLists.txt 2018-10-13 10:08:18.000000000 +0000 @@ -19,7 +19,10 @@ "Use OpenAL soft instead of XAudio2" OFF) option(FFMPEG - "Use FMPEG to render Bink videos" ON) + "Use FMPEG to render Bink videos" OFF) + +option(BINKDEC + "Use included libbinkdec to render Bink videos" ON) option(ONATIVE "Optimize for the host CPU" OFF) @@ -42,12 +45,19 @@ option(USE_SYSTEM_LIBGLEW "Use the system libglew instead of the bundled one" OFF) +option(USE_SYSTEM_RAPIDJSON + "Use the system rapidjson instead of the bundled one" OFF) + set(CPU_TYPE "" CACHE STRING "When set, passes this string as CPU-ID which will be embedded into the binary.") set(CPU_OPTIMIZATION "-mmmx -msse -msse2" CACHE STRING "Which CPU specific optimitations should be used beside the compiler's default?") option(USE_INTRINSICS "Compile using intrinsics (e.g mmx, sse, msse2)" ON) +if(FFMPEG AND BINKDEC) + message(FATAL_ERROR "Only one of FFMPEG and BINKDEC (or neither) can be enabled at a time") +endif() + if(UNIX) set(OPENAL TRUE) endif() @@ -97,25 +107,25 @@ add_definitions(-DUSE_EXCEPTIONS) #endif() - # the warnings are used for every profile anyway, so put them in a variable - set(my_warn_flags "-Wno-pragmas -Wno-unused-variable -Wno-switch -Wno-unused-value -Winvalid-pch -Wno-multichar") - + add_compile_options(-Wno-pragmas -Wno-unused-variable -Wno-switch -Wno-unused-value -Winvalid-pch -Wno-multichar) if(CMAKE_C_COMPILER_ID STREQUAL "Clang") - # append clang-specific settings for warnings (the second one make sure clang doesn't complain + # add clang-specific settings for warnings (the second one make sure clang doesn't complain # about unknown -W flags, like -Wno-unused-but-set-variable) - set(my_warn_flags "${my_warn_flags} -Wno-local-type-template-args -Wno-unknown-warning-option -Wno-inline-new-delete -Wno-switch-enum") + add_compile_options(-Wno-local-type-template-args -Wno-unknown-warning-option -Wno-inline-new-delete -Wno-switch-enum) endif() if(NOT CMAKE_CROSSCOMPILING AND ONATIVE) add_definitions(-march=native) endif() - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -O0 -ggdb -fno-strict-aliasing ${my_warn_flags}") - #set(CMAKE_C_FLAGS_DEBUGALL "${CMAKE_C_FLAGS_DEBUGALL} -g -ggdb -D_DEBUG -fno-strict-aliasing ${my_warn_flags}") - #set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_PROFILE} -g -ggdb -D_DEBUG -O1 -fno-omit-frame-pointer -fno-strict-aliasing ${my_warn_flags}") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -ffast-math -fno-unsafe-math-optimizations -fomit-frame-pointer -fno-strict-aliasing ${my_warn_flags}") - set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -g -O3 -ffast-math -fno-unsafe-math-optimizations -fomit-frame-pointer -fno-strict-aliasing ${my_warn_flags}") - set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -Os -ffast-math -fno-unsafe-math-optimizations -fomit-frame-pointer -fno-strict-aliasing ${my_warn_flags}") + add_compile_options(-fno-strict-aliasing) + + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -O0 -ggdb") + #set(CMAKE_C_FLAGS_DEBUGALL "${CMAKE_C_FLAGS_DEBUGALL} -g -ggdb -D_DEBUG") + #set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_PROFILE} -g -ggdb -D_DEBUG -O1 -fno-omit-frame-pointer") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -ffast-math -fno-unsafe-math-optimizations -fomit-frame-pointer") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -g -O3 -ffast-math -fno-unsafe-math-optimizations -fomit-frame-pointer") + set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -Os -ffast-math -fno-unsafe-math-optimizations -fomit-frame-pointer") set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG}) #set(CMAKE_CXX_FLAGS_DEBUGALL ${CMAKE_C_FLAGS_DEBUGALL}) @@ -273,6 +283,17 @@ add_definitions(-DGLEW_STATIC) endif (GLEW_FOUND) +if(USE_SYSTEM_RAPIDJSON) +find_package(rapidjson REQUIRED) +endif(USE_SYSTEM_RAPIDJSON) + +if (RAPIDJSON_FOUND) + include_directories("${RAPIDJSON_INCLUDE_DIRS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RAPIDJSON_CXX_FLAGS}") +else (RAPIDJSON_FOUND) + include_directories("libs/rapidjson/include") +endif (RAPIDJSON_FOUND) + add_subdirectory(idlib) file(GLOB AAS_INCLUDES aas/*.h) @@ -392,6 +413,12 @@ set(ZLIB_SOURCES "") endif (NOT ZLIB_FOUND) +if(BINKDEC) + file(GLOB BINKDEC_INCLUDES libs/libbinkdec/include/*.h) + file(GLOB BINKDEC_SOURCES libs/libbinkdec/src/*.c libs/libbinkdec/src/*.cpp) + add_definitions(-DUSE_BINKDEC) + include_directories("libs/libbinkdec/include") +endif() file(GLOB MINIZIP_INCLUDES libs/zlib/minizip/*.h) file(GLOB MINIZIP_SOURCES libs/zlib/minizip/*.c libs/zlib/minizip/*.cpp) @@ -902,6 +929,9 @@ source_group("libs\\jpeg-6" FILES ${JPEG_INCLUDES}) source_group("libs\\jpeg-6" FILES ${JPEG_SOURCES}) +source_group("libs\\libbinkdec" FILES ${BINKDEC_INCLUDES}) +source_group("libs\\libbinkdec" FILES ${BINKDEC_SOURCES}) + source_group("libs\\png" FILES ${PNG_INCLUDES}) source_group("libs\\png" FILES ${PNG_SOURCES}) @@ -1066,6 +1096,7 @@ ${PNG_INCLUDES} ${ZLIB_INCLUDES} ${MINIZIP_INCLUDES} + ${BINKDEC_INCLUDES} ${GLEW_INCLUDES} ${RAPIDJSON_INCLUDES} #${FREETYPE_SOURCES} @@ -1102,6 +1133,7 @@ ${PNG_SOURCES} ${ZLIB_SOURCES} ${MINIZIP_SOURCES} + ${BINKDEC_SOURCES} ${GLEW_SOURCES} #${FREETYPE_SOURCES} ${SOUND_SOURCES} @@ -1293,7 +1325,7 @@ if(USE_PRECOMPILED_HEADERS) set(RBDOOM3_PRECOMPILED_SOURCES ${RBDOOM3_SOURCES}) - list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${TIMIDITY_SOURCES} ${JPEG_SOURCES} ${PNG_SOURCES} ${ZLIB_SOURCES} ${GLEW_SOURCES}) + list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${TIMIDITY_SOURCES} ${JPEG_SOURCES} ${PNG_SOURCES} ${ZLIB_SOURCES} ${GLEW_SOURCES} ${BINKDEC_SOURCES}) list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/libs/zlib/minizip/ioapi.c) list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/renderer/DXT/DXTDecoder.cpp) list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/renderer/DXT/DXTEncoder.cpp) @@ -1428,7 +1460,7 @@ if(USE_PRECOMPILED_HEADERS) set(RBDOOM3_PRECOMPILED_SOURCES ${RBDOOM3_SOURCES}) - list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${TIMIDITY_SOURCES} ${JPEG_SOURCES} ${PNG_SOURCES} ${ZLIB_SOURCES} ${GLEW_SOURCES}) + list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${TIMIDITY_SOURCES} ${JPEG_SOURCES} ${PNG_SOURCES} ${ZLIB_SOURCES} ${GLEW_SOURCES} ${BINKDEC_SOURCES}) list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/libs/zlib/minizip/ioapi.c) list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/renderer/DXT/DXTDecoder.cpp) list(REMOVE_ITEM RBDOOM3_PRECOMPILED_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/renderer/DXT/DXTEncoder.cpp) diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/d3xp/menus/MenuScreen.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/d3xp/menus/MenuScreen.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/d3xp/menus/MenuScreen.h 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/d3xp/menus/MenuScreen.h 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #ifndef __MENUSCREEN_H__ #define __MENUSCREEN_H__ -#include "../../renderer/tr_local.h" +#include "../../renderer/RenderCommon.h" enum mainMenuTransition_t { diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/d3xp/menus/MenuScreen_Shell_Resolution.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/d3xp/menus/MenuScreen_Shell_Resolution.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/d3xp/menus/MenuScreen_Shell_Resolution.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/d3xp/menus/MenuScreen_Shell_Resolution.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -28,7 +28,7 @@ #pragma hdrstop #include "precompiled.h" #include "../Game_local.h" -#include "../../renderer/tr_local.h" +#include "../../renderer/RenderCommon.h" const static int NUM_SETTING_OPTIONS = 7; diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/framework/Common.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/framework/Common.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/framework/Common.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/framework/Common.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -827,16 +827,6 @@ /* ================= -Com_StartBuild_f -================= -*/ -CONSOLE_COMMAND( startBuild, "prepares to make a build", NULL ) -{ - globalImages->StartBuild(); -} - -/* -================= Com_FinishBuild_f ================= */ @@ -846,7 +836,6 @@ { game->CacheDictionaryMedia( NULL ); } - globalImages->FinishBuild( ( args.Argc() > 1 ) ); } /* diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/framework/common_frame.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/framework/common_frame.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/framework/common_frame.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/framework/common_frame.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -33,7 +33,6 @@ #include "Common_local.h" #include "../renderer/Image.h" // now I did it! -#include "../renderer/ImageOpts.h" // RB begin #if defined(USE_DOOMCLASSIC) @@ -65,7 +64,7 @@ idCVar com_fixedTic( "com_fixedTic", DEFAULT_FIXED_TIC, CVAR_BOOL, "run a single game frame per render frame" ); idCVar com_noSleep( "com_noSleep", DEFAULT_NO_SLEEP, CVAR_BOOL, "don't sleep if the game is running too fast" ); -idCVar com_smp( "com_smp", "1", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "run the game and draw code in a separate thread" ); +idCVar com_smp( "com_smp", "1", CVAR_INTEGER | CVAR_SYSTEM | CVAR_NOCHEAT, "run the game and draw code in a separate thread" ); idCVar com_aviDemoSamples( "com_aviDemoSamples", "16", CVAR_SYSTEM, "" ); idCVar com_aviDemoWidth( "com_aviDemoWidth", "256", CVAR_SYSTEM, "" ); idCVar com_aviDemoHeight( "com_aviDemoHeight", "256", CVAR_SYSTEM, "" ); @@ -195,7 +194,7 @@ numGameFrames = numGameFrames_; // start the thread going - if( com_smp.GetBool() == false ) + if( com_smp.GetInteger() <= 0 ) { // run it in the main thread so PIX profiling catches everything Run(); @@ -555,10 +554,15 @@ // This may block if the GPU isn't finished renderng the previous frame. frameTiming.startSyncTime = Sys_Microseconds(); const emptyCommand_t* renderCommands = NULL; - if( com_smp.GetBool() ) + if( com_smp.GetInteger() > 0 ) { renderCommands = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu ); } + else if( com_smp.GetInteger() < 0 ) + { + // RB: this is the same as Doom 3 renderSystem->BeginFrame() + renderCommands = renderSystem->SwapCommandBuffers_FinishCommandBuffers(); + } else { // the GPU will stay idle through command generation for minimal @@ -779,7 +783,12 @@ // start the game / draw command generation thread going in the background gameReturn_t ret = gameThread.RunGameAndDraw( numGameFrames, userCmdMgr, IsClient(), gameFrame - numGameFrames ); - if( !com_smp.GetBool() ) + if( com_smp.GetInteger() < 0 ) + { + // RB: this is the same as Doom 3 renderSystem->EndFrame() + renderSystem->SwapCommandBuffers_FinishRendering( &time_frontend, &time_backend, &time_shadows, &time_gpu ); + } + else if( com_smp.GetInteger() == 0 ) { // in non-smp mode, run the commands we just generated, instead of // frame-delayed ones from a background thread diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/idlib/precompiled.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/idlib/precompiled.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/idlib/precompiled.h 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/idlib/precompiled.h 2018-10-13 10:08:18.000000000 +0000 @@ -105,7 +105,7 @@ #include "../ui/UserInterface.h" // RB: required for SWF extensions -#include "../libs/rapidjson/include/rapidjson/document.h" +#include "rapidjson/document.h" #include "../swf/SWF.h" diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/idlib/sys/sys_defines.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/idlib/sys/sys_defines.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/idlib/sys/sys_defines.h 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/idlib/sys/sys_defines.h 2018-10-13 10:08:18.000000000 +0000 @@ -108,7 +108,7 @@ #if defined(__i386__) #define CPUSTRING "x86" #elif defined(__x86_64__) -#define CPUSTRING "x86_86" +#define CPUSTRING "x86_64" #else #error unknown CPU #endif diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/COPYING rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/COPYING --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/COPYING 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/COPYING 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/avfft.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/avfft.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/avfft.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/avfft.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,99 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVFFT_H +#define AVCODEC_AVFFT_H + +typedef float FFTSample; + +typedef struct FFTComplex { + FFTSample re, im; +} FFTComplex; + +typedef struct FFTContext FFTContext; + +/** + * Set up a complex FFT. + * @param nbits log2 of the length of the input array + * @param inverse if 0 perform the forward transform, if 1 perform the inverse + */ +FFTContext *av_fft_init(int nbits, int inverse); + +/** + * Do the permutation needed BEFORE calling ff_fft_calc(). + */ +void av_fft_permute(FFTContext *s, FFTComplex *z); + +/** + * Do a complex FFT with the parameters defined in av_fft_init(). The + * input data must be permuted before. No 1.0/sqrt(n) normalization is done. + */ +void av_fft_calc(FFTContext *s, FFTComplex *z); + +void av_fft_end(FFTContext *s); + +FFTContext *av_mdct_init(int nbits, int inverse, double scale); +void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_end(FFTContext *s); + +/* Real Discrete Fourier Transform */ + +enum RDFTransformType { + DFT_R2C, + IDFT_C2R, + IDFT_R2C, + DFT_C2R, +}; + +typedef struct RDFTContext RDFTContext; + +/** + * Set up a real FFT. + * @param nbits log2 of the length of the input array + * @param trans the type of transform + */ +RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans); +void av_rdft_calc(RDFTContext *s, FFTSample *data); +void av_rdft_end(RDFTContext *s); + +/* Discrete Cosine Transform */ + +typedef struct DCTContext DCTContext; + +enum DCTTransformType { + DCT_II = 0, + DCT_III, + DCT_I, + DST_I, +}; + +/** + * Set up DCT. + * @param nbits size of the input array: + * (1 << nbits) for DCT-II, DCT-III and DST-I + * (1 << nbits) + 1 for DCT-I + * + * @note the first element of the input of DST-I is ignored + */ +DCTContext *av_dct_init(int nbits, enum DCTTransformType type); +void av_dct_calc(DCTContext *s, FFTSample *data); +void av_dct_end (DCTContext *s); + +#endif /* AVCODEC_AVFFT_H */ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/BinkAudio.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/BinkAudio.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/BinkAudio.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/BinkAudio.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BinkAudio_h_ +#define _BinkAudio_h_ + +#include +#include + +extern "C" { +#include "rdft.h" +#include "dct.h" +} + +// audio transform type +enum eTransformType { + kTransformTypeRDFT = 0, + kTransformTypeDCT = 1 +}; + +const int kMaxChannels = 2; +const int kBlockMaxSize = kMaxChannels << 11; + +static const int kNumCriticalFrequencies = 25; +static const uint16_t criticalFrequencies[kNumCriticalFrequencies] = +{ + 100, 200, 300, 400, + 510, 630, 770, 920, + 1080, 1270, 1480, 1720, + 2000, 2320, 2700, 3150, + 3700, 4400, 5300, 6400, + 7700, 9500, 12000, 15500, + 24500 +}; + +static const int kNumRLEentries = 16; +static const uint8_t RLEentries[kNumRLEentries] = +{ + 2, 3, 4, 5, + 6, 8, 9, 10, + 11, 12, 13, 14, + 15, 16, 32, 64 +}; + +struct AudioTrack +{ + uint32_t sampleRate; + uint32_t nChannels; // internal use only + uint32_t nChannelsReal; // number of channels you should pass to your audio API + + eTransformType transformType; + int frameLenBits; + int frameLength; // transform size (samples) + int overlapLength; // overlap size (samples) + int blockSize; + uint32_t sampleRateHalf; + uint32_t nBands; + bool first; + float root; + + union { + RDFTContext rdft; + DCTContext dct; + } trans; + + std::vector bands; + + float coeffs[kBlockMaxSize]; + int16_t previous[kBlockMaxSize / 16]; // coeffs from previous audio block + + float *coeffsPtr[kMaxChannels]; // pointers to the coeffs arrays for float_to_int16_interleave + + int16_t *blockBuffer; + uint32_t blockBufferSize; + + uint8_t *buffer; + uint32_t bufferSize; // size in bytes + + uint32_t bytesReadThisFrame; +}; + +#endif \ No newline at end of file diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/binkdata.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/binkdata.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/binkdata.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/binkdata.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,655 @@ +/* + * Bink video decoder + * Copyright (C) 2009 Kostya Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_BINKDATA_H +#define AVCODEC_BINKDATA_H + +#include + +/** Bink DCT and residue 8x8 block scan order */ +static const uint8_t bink_scan[64] = { + 0, 1, 8, 9, 2, 3, 10, 11, + 4, 5, 12, 13, 6, 7, 14, 15, + 20, 21, 28, 29, 22, 23, 30, 31, + 16, 17, 24, 25, 32, 33, 40, 41, + 34, 35, 42, 43, 48, 49, 56, 57, + 50, 51, 58, 59, 18, 19, 26, 27, + 36, 37, 44, 45, 38, 39, 46, 47, + 52, 53, 60, 61, 54, 55, 62, 63 +}; + +static const uint8_t bink_tree_bits[16][16] = { + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }, + { + 0x00, 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, + 0x0F, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F, + }, + { + 0x00, 0x02, 0x01, 0x09, 0x05, 0x15, 0x0D, 0x1D, + 0x03, 0x13, 0x0B, 0x1B, 0x07, 0x17, 0x0F, 0x1F, + }, + { + 0x00, 0x02, 0x06, 0x01, 0x09, 0x05, 0x0D, 0x1D, + 0x03, 0x13, 0x0B, 0x1B, 0x07, 0x17, 0x0F, 0x1F, + }, + { + 0x00, 0x04, 0x02, 0x06, 0x01, 0x09, 0x05, 0x0D, + 0x03, 0x13, 0x0B, 0x1B, 0x07, 0x17, 0x0F, 0x1F, + }, + { + 0x00, 0x04, 0x02, 0x0A, 0x06, 0x0E, 0x01, 0x09, + 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x17, 0x0F, 0x1F, + }, + { + 0x00, 0x02, 0x0A, 0x06, 0x0E, 0x01, 0x09, 0x05, + 0x0D, 0x03, 0x0B, 0x1B, 0x07, 0x17, 0x0F, 0x1F, + }, + { + 0x00, 0x01, 0x05, 0x03, 0x13, 0x0B, 0x1B, 0x3B, + 0x07, 0x27, 0x17, 0x37, 0x0F, 0x2F, 0x1F, 0x3F, + }, + { + 0x00, 0x01, 0x03, 0x13, 0x0B, 0x2B, 0x1B, 0x3B, + 0x07, 0x27, 0x17, 0x37, 0x0F, 0x2F, 0x1F, 0x3F, + }, + { + 0x00, 0x01, 0x05, 0x0D, 0x03, 0x13, 0x0B, 0x1B, + 0x07, 0x27, 0x17, 0x37, 0x0F, 0x2F, 0x1F, 0x3F, + }, + { + 0x00, 0x02, 0x01, 0x05, 0x0D, 0x03, 0x13, 0x0B, + 0x1B, 0x07, 0x17, 0x37, 0x0F, 0x2F, 0x1F, 0x3F, + }, + { + 0x00, 0x01, 0x09, 0x05, 0x0D, 0x03, 0x13, 0x0B, + 0x1B, 0x07, 0x17, 0x37, 0x0F, 0x2F, 0x1F, 0x3F, + }, + { + 0x00, 0x02, 0x01, 0x03, 0x13, 0x0B, 0x1B, 0x3B, + 0x07, 0x27, 0x17, 0x37, 0x0F, 0x2F, 0x1F, 0x3F, + }, + { + 0x00, 0x01, 0x05, 0x03, 0x07, 0x27, 0x17, 0x37, + 0x0F, 0x4F, 0x2F, 0x6F, 0x1F, 0x5F, 0x3F, 0x7F, + }, + { + 0x00, 0x01, 0x05, 0x03, 0x07, 0x17, 0x37, 0x77, + 0x0F, 0x4F, 0x2F, 0x6F, 0x1F, 0x5F, 0x3F, 0x7F, + }, + { + 0x00, 0x02, 0x01, 0x05, 0x03, 0x07, 0x27, 0x17, + 0x37, 0x0F, 0x2F, 0x6F, 0x1F, 0x5F, 0x3F, 0x7F, + }, +}; + +static const uint8_t bink_tree_lens[16][16] = { + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, + { 1, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, + { 2, 2, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, + { 2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, + { 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5 }, + { 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5 }, + { 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5 }, + { 1, 3, 3, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, + { 1, 2, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, + { 1, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6 }, + { 2, 2, 3, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6 }, + { 1, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6 }, + { 2, 2, 2, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, + { 1, 3, 3, 3, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7 }, + { 1, 3, 3, 3, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }, + { 2, 2, 3, 3, 3, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7 }, +}; + +static const uint8_t bink_patterns[16][64] = { + { + 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, + 0x39, 0x31, 0x29, 0x21, 0x19, 0x11, 0x09, 0x01, + 0x02, 0x0A, 0x12, 0x1A, 0x22, 0x2A, 0x32, 0x3A, + 0x3B, 0x33, 0x2B, 0x23, 0x1B, 0x13, 0x0B, 0x03, + 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, 0x34, 0x3C, + 0x3D, 0x35, 0x2D, 0x25, 0x1D, 0x15, 0x0D, 0x05, + 0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, 0x36, 0x3E, + 0x3F, 0x37, 0x2F, 0x27, 0x1F, 0x17, 0x0F, 0x07, + }, + { + 0x3B, 0x3A, 0x39, 0x38, 0x30, 0x31, 0x32, 0x33, + 0x2B, 0x2A, 0x29, 0x28, 0x20, 0x21, 0x22, 0x23, + 0x1B, 0x1A, 0x19, 0x18, 0x10, 0x11, 0x12, 0x13, + 0x0B, 0x0A, 0x09, 0x08, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x0F, 0x0E, 0x0D, 0x0C, + 0x14, 0x15, 0x16, 0x17, 0x1F, 0x1E, 0x1D, 0x1C, + 0x24, 0x25, 0x26, 0x27, 0x2F, 0x2E, 0x2D, 0x2C, + 0x34, 0x35, 0x36, 0x37, 0x3F, 0x3E, 0x3D, 0x3C, + }, + { + 0x19, 0x11, 0x12, 0x1A, 0x1B, 0x13, 0x0B, 0x03, + 0x02, 0x0A, 0x09, 0x01, 0x00, 0x08, 0x10, 0x18, + 0x20, 0x28, 0x30, 0x38, 0x39, 0x31, 0x29, 0x2A, + 0x32, 0x3A, 0x3B, 0x33, 0x2B, 0x23, 0x22, 0x21, + 0x1D, 0x15, 0x16, 0x1E, 0x1F, 0x17, 0x0F, 0x07, + 0x06, 0x0E, 0x0D, 0x05, 0x04, 0x0C, 0x14, 0x1C, + 0x24, 0x2C, 0x34, 0x3C, 0x3D, 0x35, 0x2D, 0x2E, + 0x36, 0x3E, 0x3F, 0x37, 0x2F, 0x27, 0x26, 0x25, + }, + { + 0x03, 0x0B, 0x02, 0x0A, 0x01, 0x09, 0x00, 0x08, + 0x10, 0x18, 0x11, 0x19, 0x12, 0x1A, 0x13, 0x1B, + 0x23, 0x2B, 0x22, 0x2A, 0x21, 0x29, 0x20, 0x28, + 0x30, 0x38, 0x31, 0x39, 0x32, 0x3A, 0x33, 0x3B, + 0x3C, 0x34, 0x3D, 0x35, 0x3E, 0x36, 0x3F, 0x37, + 0x2F, 0x27, 0x2E, 0x26, 0x2D, 0x25, 0x2C, 0x24, + 0x1C, 0x14, 0x1D, 0x15, 0x1E, 0x16, 0x1F, 0x17, + 0x0F, 0x07, 0x0E, 0x06, 0x0D, 0x05, 0x0C, 0x04, + }, + { + 0x18, 0x19, 0x10, 0x11, 0x08, 0x09, 0x00, 0x01, + 0x02, 0x03, 0x0A, 0x0B, 0x12, 0x13, 0x1A, 0x1B, + 0x1C, 0x1D, 0x14, 0x15, 0x0C, 0x0D, 0x04, 0x05, + 0x06, 0x07, 0x0E, 0x0F, 0x16, 0x17, 0x1E, 0x1F, + 0x27, 0x26, 0x2F, 0x2E, 0x37, 0x36, 0x3F, 0x3E, + 0x3D, 0x3C, 0x35, 0x34, 0x2D, 0x2C, 0x25, 0x24, + 0x23, 0x22, 0x2B, 0x2A, 0x33, 0x32, 0x3B, 0x3A, + 0x39, 0x38, 0x31, 0x30, 0x29, 0x28, 0x21, 0x20, + }, + { + 0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0A, 0x0B, + 0x10, 0x11, 0x12, 0x13, 0x18, 0x19, 0x1A, 0x1B, + 0x20, 0x21, 0x22, 0x23, 0x28, 0x29, 0x2A, 0x2B, + 0x30, 0x31, 0x32, 0x33, 0x38, 0x39, 0x3A, 0x3B, + 0x04, 0x05, 0x06, 0x07, 0x0C, 0x0D, 0x0E, 0x0F, + 0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F, + 0x24, 0x25, 0x26, 0x27, 0x2C, 0x2D, 0x2E, 0x2F, + 0x34, 0x35, 0x36, 0x37, 0x3C, 0x3D, 0x3E, 0x3F, + }, + { + 0x06, 0x07, 0x0F, 0x0E, 0x0D, 0x05, 0x0C, 0x04, + 0x03, 0x0B, 0x02, 0x0A, 0x09, 0x01, 0x00, 0x08, + 0x10, 0x18, 0x11, 0x19, 0x12, 0x1A, 0x13, 0x1B, + 0x14, 0x1C, 0x15, 0x1D, 0x16, 0x1E, 0x17, 0x1F, + 0x27, 0x2F, 0x26, 0x2E, 0x25, 0x2D, 0x24, 0x2C, + 0x23, 0x2B, 0x22, 0x2A, 0x21, 0x29, 0x20, 0x28, + 0x31, 0x30, 0x38, 0x39, 0x3A, 0x32, 0x3B, 0x33, + 0x3C, 0x34, 0x3D, 0x35, 0x36, 0x37, 0x3F, 0x3E, + }, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, + }, + { + 0x00, 0x08, 0x09, 0x01, 0x02, 0x03, 0x0B, 0x0A, + 0x12, 0x13, 0x1B, 0x1A, 0x19, 0x11, 0x10, 0x18, + 0x20, 0x28, 0x29, 0x21, 0x22, 0x23, 0x2B, 0x2A, + 0x32, 0x31, 0x30, 0x38, 0x39, 0x3A, 0x3B, 0x33, + 0x34, 0x3C, 0x3D, 0x3E, 0x3F, 0x37, 0x36, 0x35, + 0x2D, 0x2C, 0x24, 0x25, 0x26, 0x2E, 0x2F, 0x27, + 0x1F, 0x17, 0x16, 0x1E, 0x1D, 0x1C, 0x14, 0x15, + 0x0D, 0x0C, 0x04, 0x05, 0x06, 0x0E, 0x0F, 0x07, + }, + { + 0x18, 0x19, 0x10, 0x11, 0x08, 0x09, 0x00, 0x01, + 0x02, 0x03, 0x0A, 0x0B, 0x12, 0x13, 0x1A, 0x1B, + 0x1C, 0x1D, 0x14, 0x15, 0x0C, 0x0D, 0x04, 0x05, + 0x06, 0x07, 0x0E, 0x0F, 0x16, 0x17, 0x1E, 0x1F, + 0x26, 0x27, 0x2E, 0x2F, 0x36, 0x37, 0x3E, 0x3F, + 0x3C, 0x3D, 0x34, 0x35, 0x2C, 0x2D, 0x24, 0x25, + 0x22, 0x23, 0x2A, 0x2B, 0x32, 0x33, 0x3A, 0x3B, + 0x38, 0x39, 0x30, 0x31, 0x28, 0x29, 0x20, 0x21, + }, + { + 0x00, 0x08, 0x01, 0x09, 0x02, 0x0A, 0x03, 0x0B, + 0x13, 0x1B, 0x12, 0x1A, 0x11, 0x19, 0x10, 0x18, + 0x20, 0x28, 0x21, 0x29, 0x22, 0x2A, 0x23, 0x2B, + 0x33, 0x3B, 0x32, 0x3A, 0x31, 0x39, 0x30, 0x38, + 0x3C, 0x34, 0x3D, 0x35, 0x3E, 0x36, 0x3F, 0x37, + 0x2F, 0x27, 0x2E, 0x26, 0x2D, 0x25, 0x2C, 0x24, + 0x1F, 0x17, 0x1E, 0x16, 0x1D, 0x15, 0x1C, 0x14, + 0x0C, 0x04, 0x0D, 0x05, 0x0E, 0x06, 0x0F, 0x07, + }, + { + 0x00, 0x08, 0x10, 0x18, 0x19, 0x1A, 0x1B, 0x13, + 0x0B, 0x03, 0x02, 0x01, 0x09, 0x11, 0x12, 0x0A, + 0x04, 0x0C, 0x14, 0x1C, 0x1D, 0x1E, 0x1F, 0x17, + 0x0F, 0x07, 0x06, 0x05, 0x0D, 0x15, 0x16, 0x0E, + 0x24, 0x2C, 0x34, 0x3C, 0x3D, 0x3E, 0x3F, 0x37, + 0x2F, 0x27, 0x26, 0x25, 0x2D, 0x35, 0x36, 0x2E, + 0x20, 0x28, 0x30, 0x38, 0x39, 0x3A, 0x3B, 0x33, + 0x2B, 0x23, 0x22, 0x21, 0x29, 0x31, 0x32, 0x2A, + }, + { + 0x00, 0x08, 0x09, 0x01, 0x02, 0x03, 0x0B, 0x0A, + 0x13, 0x1B, 0x1A, 0x12, 0x11, 0x10, 0x18, 0x19, + 0x21, 0x20, 0x28, 0x29, 0x2A, 0x22, 0x23, 0x2B, + 0x33, 0x3B, 0x3A, 0x32, 0x31, 0x39, 0x38, 0x30, + 0x34, 0x3C, 0x3D, 0x35, 0x36, 0x3E, 0x3F, 0x37, + 0x2F, 0x27, 0x26, 0x2E, 0x2D, 0x2C, 0x24, 0x25, + 0x1D, 0x1C, 0x14, 0x15, 0x16, 0x1E, 0x1F, 0x17, + 0x0E, 0x0F, 0x07, 0x06, 0x05, 0x0D, 0x0C, 0x04, + }, + { + 0x18, 0x10, 0x08, 0x00, 0x01, 0x02, 0x03, 0x0B, + 0x13, 0x1B, 0x1A, 0x19, 0x11, 0x0A, 0x09, 0x12, + 0x1C, 0x14, 0x0C, 0x04, 0x05, 0x06, 0x07, 0x0F, + 0x17, 0x1F, 0x1E, 0x1D, 0x15, 0x0E, 0x0D, 0x16, + 0x3C, 0x34, 0x2C, 0x24, 0x25, 0x26, 0x27, 0x2F, + 0x37, 0x3F, 0x3E, 0x3D, 0x35, 0x2E, 0x2D, 0x36, + 0x38, 0x30, 0x28, 0x20, 0x21, 0x22, 0x23, 0x2B, + 0x33, 0x3B, 0x3A, 0x39, 0x31, 0x2A, 0x29, 0x32, + }, + { + 0x00, 0x08, 0x09, 0x01, 0x02, 0x0A, 0x12, 0x11, + 0x10, 0x18, 0x19, 0x1A, 0x1B, 0x13, 0x0B, 0x03, + 0x07, 0x06, 0x0E, 0x0F, 0x17, 0x16, 0x15, 0x0D, + 0x05, 0x04, 0x0C, 0x14, 0x1C, 0x1D, 0x1E, 0x1F, + 0x3F, 0x3E, 0x36, 0x37, 0x2F, 0x2E, 0x2D, 0x35, + 0x3D, 0x3C, 0x34, 0x2C, 0x24, 0x25, 0x26, 0x27, + 0x38, 0x30, 0x31, 0x39, 0x3A, 0x32, 0x2A, 0x29, + 0x28, 0x20, 0x21, 0x22, 0x23, 0x2B, 0x33, 0x3B, + }, + { + 0x00, 0x01, 0x08, 0x09, 0x10, 0x11, 0x18, 0x19, + 0x20, 0x21, 0x28, 0x29, 0x30, 0x31, 0x38, 0x39, + 0x3A, 0x3B, 0x32, 0x33, 0x2A, 0x2B, 0x22, 0x23, + 0x1A, 0x1B, 0x12, 0x13, 0x0A, 0x0B, 0x02, 0x03, + 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D, + 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x3C, 0x3D, + 0x3E, 0x3F, 0x36, 0x37, 0x2E, 0x2F, 0x26, 0x27, + 0x1E, 0x1F, 0x16, 0x17, 0x0E, 0x0F, 0x06, 0x07, + } +}; + +static const int32_t bink_intra_quant[16][64] = { +{ + 0x010000, 0x016315, 0x01E83D, 0x02A535, 0x014E7B, 0x016577, 0x02F1E6, 0x02724C, + 0x010000, 0x00EEDA, 0x024102, 0x017F9B, 0x00BE80, 0x00611E, 0x01083C, 0x00A552, + 0x021F88, 0x01DC53, 0x027FAD, 0x01F697, 0x014819, 0x00A743, 0x015A31, 0x009688, + 0x02346F, 0x030EE5, 0x01FBFA, 0x02C096, 0x01D000, 0x028396, 0x019247, 0x01F9AA, + 0x02346F, 0x01FBFA, 0x01DC53, 0x0231B8, 0x012F12, 0x01E06C, 0x00CB10, 0x0119A8, + 0x01C48C, 0x019748, 0x014E86, 0x0122AF, 0x02C628, 0x027F20, 0x0297B5, 0x023F32, + 0x025000, 0x01AB6B, 0x01D122, 0x0159B3, 0x012669, 0x008D43, 0x00EE1F, 0x0075ED, + 0x01490C, 0x010288, 0x00F735, 0x00EF51, 0x00E0F1, 0x0072AD, 0x00A4D8, 0x006517, +}, +{ + 0x015555, 0x01D971, 0x028AFC, 0x0386F1, 0x01BDF9, 0x01DC9F, 0x03ED33, 0x034311, + 0x015555, 0x013E78, 0x030158, 0x01FF7A, 0x00FE00, 0x00817D, 0x01604F, 0x00DC6D, + 0x02D4B5, 0x027B19, 0x0354E7, 0x029E1F, 0x01B577, 0x00DF04, 0x01CD96, 0x00C8B6, + 0x02F095, 0x0413DC, 0x02A54E, 0x03AB73, 0x026AAB, 0x035A1E, 0x02185E, 0x02A238, + 0x02F095, 0x02A54E, 0x027B19, 0x02ECF5, 0x019418, 0x028090, 0x010EC0, 0x01778A, + 0x025B66, 0x021F0B, 0x01BE09, 0x018394, 0x03B2E0, 0x03542A, 0x0374F1, 0x02FEEE, + 0x031555, 0x0239E4, 0x026C2D, 0x01CCEE, 0x01888C, 0x00BC59, 0x013D7E, 0x009D3C, + 0x01B6BB, 0x0158B5, 0x01499C, 0x013F17, 0x012BEC, 0x0098E6, 0x00DBCB, 0x0086C9, +}, +{ + 0x01AAAB, 0x024FCE, 0x032DBB, 0x0468AD, 0x022D78, 0x0253C7, 0x04E87F, 0x0413D5, + 0x01AAAB, 0x018E16, 0x03C1AE, 0x027F58, 0x013D80, 0x00A1DC, 0x01B863, 0x011388, + 0x0389E2, 0x0319DF, 0x042A21, 0x0345A7, 0x0222D4, 0x0116C5, 0x0240FC, 0x00FAE3, + 0x03ACBA, 0x0518D3, 0x034EA1, 0x04964F, 0x030555, 0x0430A5, 0x029E76, 0x034AC5, + 0x03ACBA, 0x034EA1, 0x0319DF, 0x03A833, 0x01F91E, 0x0320B4, 0x015270, 0x01D56D, + 0x02F23F, 0x02A6CE, 0x022D8B, 0x01E479, 0x049F98, 0x042935, 0x04522D, 0x03BEA9, + 0x03DAAB, 0x02C85D, 0x030738, 0x02402A, 0x01EAAF, 0x00EB6F, 0x018CDE, 0x00C48A, + 0x022469, 0x01AEE2, 0x019C02, 0x018EDD, 0x0176E7, 0x00BF20, 0x0112BE, 0x00A87B, +}, +{ + 0x020000, 0x02C62A, 0x03D07A, 0x054A69, 0x029CF6, 0x02CAEF, 0x05E3CC, 0x04E499, + 0x020000, 0x01DDB4, 0x048204, 0x02FF36, 0x017D01, 0x00C23C, 0x021077, 0x014AA3, + 0x043F0F, 0x03B8A6, 0x04FF5A, 0x03ED2E, 0x029032, 0x014E86, 0x02B461, 0x012D11, + 0x0468DF, 0x061DCA, 0x03F7F5, 0x05812C, 0x03A000, 0x05072C, 0x03248D, 0x03F353, + 0x0468DF, 0x03F7F5, 0x03B8A6, 0x046370, 0x025E24, 0x03C0D8, 0x019620, 0x02334F, + 0x038919, 0x032E91, 0x029D0D, 0x02455E, 0x058C50, 0x04FE3F, 0x052F69, 0x047E65, + 0x04A000, 0x0356D6, 0x03A243, 0x02B365, 0x024CD2, 0x011A85, 0x01DC3E, 0x00EBD9, + 0x029218, 0x020510, 0x01EE69, 0x01DEA2, 0x01C1E2, 0x00E559, 0x0149B0, 0x00CA2D, +}, +{ + 0x02AAAB, 0x03B2E3, 0x0515F8, 0x070DE2, 0x037BF2, 0x03B93E, 0x07DA65, 0x068621, + 0x02AAAB, 0x027CF0, 0x0602B1, 0x03FEF3, 0x01FC01, 0x0102FA, 0x02C09F, 0x01B8DA, + 0x05A96A, 0x04F632, 0x06A9CE, 0x053C3E, 0x036AED, 0x01BE09, 0x039B2D, 0x01916B, + 0x05E129, 0x0827B8, 0x054A9C, 0x0756E5, 0x04D555, 0x06B43B, 0x0430BC, 0x05446F, + 0x05E129, 0x054A9C, 0x04F632, 0x05D9EB, 0x032830, 0x050121, 0x021D80, 0x02EF14, + 0x04B6CC, 0x043E16, 0x037C11, 0x030728, 0x0765C0, 0x06A855, 0x06E9E2, 0x05FDDB, + 0x062AAB, 0x0473C8, 0x04D85A, 0x0399DC, 0x031118, 0x0178B2, 0x027AFD, 0x013A77, + 0x036D76, 0x02B16A, 0x029337, 0x027E2E, 0x0257D8, 0x0131CC, 0x01B796, 0x010D91, +}, +{ + 0x038000, 0x04DACA, 0x06ACD5, 0x094238, 0x0492AE, 0x04E322, 0x0A4EA5, 0x08900C, + 0x038000, 0x0343FB, 0x07E388, 0x053E9F, 0x029AC1, 0x0153E8, 0x039CD0, 0x02429E, + 0x076E5B, 0x068322, 0x08BEDE, 0x06DF11, 0x047C57, 0x02496B, 0x04BBAB, 0x020EDD, + 0x07B786, 0x0AB421, 0x06F1ED, 0x09A20D, 0x065800, 0x08CC8E, 0x057FF7, 0x06E9D2, + 0x07B786, 0x06F1ED, 0x068322, 0x07AE04, 0x0424BF, 0x06917B, 0x02C6B8, 0x03D9CB, + 0x062FEB, 0x05917D, 0x0492D7, 0x03F964, 0x09B58C, 0x08BCEF, 0x0912F8, 0x07DD30, + 0x081800, 0x05D7F7, 0x065BF6, 0x04B9F1, 0x040670, 0x01EE69, 0x03416C, 0x019CBC, + 0x047FAA, 0x0388DC, 0x036138, 0x03459C, 0x03134C, 0x01915C, 0x0240F5, 0x0161CF, +}, +{ + 0x040000, 0x058C54, 0x07A0F4, 0x0A94D3, 0x0539EC, 0x0595DD, 0x0BC798, 0x09C932, + 0x040000, 0x03BB68, 0x090409, 0x05FE6D, 0x02FA01, 0x018477, 0x0420EE, 0x029547, + 0x087E1F, 0x07714C, 0x09FEB5, 0x07DA5D, 0x052064, 0x029D0D, 0x0568C3, 0x025A21, + 0x08D1BE, 0x0C3B94, 0x07EFEA, 0x0B0258, 0x074000, 0x0A0E59, 0x06491A, 0x07E6A7, + 0x08D1BE, 0x07EFEA, 0x07714C, 0x08C6E0, 0x04BC48, 0x0781B1, 0x032C3F, 0x04669F, + 0x071232, 0x065D22, 0x053A1A, 0x048ABC, 0x0B18A0, 0x09FC7F, 0x0A5ED3, 0x08FCC9, + 0x094000, 0x06ADAC, 0x074487, 0x0566CA, 0x0499A5, 0x02350B, 0x03B87B, 0x01D7B3, + 0x052430, 0x040A20, 0x03DCD3, 0x03BD45, 0x0383C5, 0x01CAB3, 0x029361, 0x01945A, +}, +{ + 0x050000, 0x06EF69, 0x098931, 0x0D3A07, 0x068867, 0x06FB55, 0x0EB97E, 0x0C3B7E, + 0x050000, 0x04AA42, 0x0B450B, 0x077E08, 0x03B881, 0x01E595, 0x05292A, 0x033A99, + 0x0A9DA7, 0x094D9F, 0x0C7E62, 0x09D0F4, 0x06687D, 0x034450, 0x06C2F4, 0x02F0AA, + 0x0B062D, 0x0F4A78, 0x09EBE4, 0x0DC2EE, 0x091000, 0x0C91EF, 0x07DB61, 0x09E050, + 0x0B062D, 0x09EBE4, 0x094D9F, 0x0AF898, 0x05EB59, 0x09621D, 0x03F74F, 0x058046, + 0x08D6BE, 0x07F46A, 0x0688A0, 0x05AD6B, 0x0DDEC8, 0x0C7B9F, 0x0CF687, 0x0B3BFB, + 0x0B9000, 0x085917, 0x0915A8, 0x06C07D, 0x05C00E, 0x02C24D, 0x04A69A, 0x024D9F, + 0x066D3C, 0x050CA7, 0x04D407, 0x04AC96, 0x0464B6, 0x023D5F, 0x033839, 0x01F971, +}, +{ + 0x060000, 0x08527E, 0x0B716E, 0x0FDF3C, 0x07D6E1, 0x0860CC, 0x11AB63, 0x0EADCB, + 0x060000, 0x05991C, 0x0D860D, 0x08FDA3, 0x047702, 0x0246B3, 0x063165, 0x03DFEA, + 0x0CBD2E, 0x0B29F1, 0x0EFE0F, 0x0BC78B, 0x07B096, 0x03EB93, 0x081D24, 0x038732, + 0x0D3A9C, 0x12595D, 0x0BE7DF, 0x108384, 0x0AE000, 0x0F1585, 0x096DA8, 0x0BD9FA, + 0x0D3A9C, 0x0BE7DF, 0x0B29F1, 0x0D2A50, 0x071A6B, 0x0B4289, 0x04C25F, 0x0699EE, + 0x0A9B4A, 0x098BB2, 0x07D727, 0x06D01A, 0x10A4F0, 0x0EFABE, 0x0F8E3C, 0x0D7B2E, + 0x0DE000, 0x0A0482, 0x0AE6CA, 0x081A2F, 0x06E677, 0x034F90, 0x0594B9, 0x02C38C, + 0x07B649, 0x060F2F, 0x05CB3C, 0x059BE7, 0x0545A7, 0x02B00C, 0x03DD11, 0x025E87, +}, +{ + 0x080000, 0x0B18A8, 0x0F41E8, 0x1529A5, 0x0A73D7, 0x0B2BBB, 0x178F2F, 0x139264, + 0x080000, 0x0776CF, 0x120812, 0x0BFCD9, 0x05F402, 0x0308EF, 0x0841DC, 0x052A8E, + 0x10FC3E, 0x0EE297, 0x13FD69, 0x0FB4B9, 0x0A40C8, 0x053A1A, 0x0AD186, 0x04B442, + 0x11A37B, 0x187727, 0x0FDFD4, 0x1604B0, 0x0E8000, 0x141CB1, 0x0C9235, 0x0FCD4D, + 0x11A37B, 0x0FDFD4, 0x0EE297, 0x118DC0, 0x09788F, 0x0F0362, 0x06587F, 0x08CD3D, + 0x0E2463, 0x0CBA43, 0x0A7434, 0x091577, 0x163140, 0x13F8FE, 0x14BDA5, 0x11F992, + 0x128000, 0x0D5B58, 0x0E890D, 0x0ACD94, 0x093349, 0x046A15, 0x0770F7, 0x03AF65, + 0x0A4861, 0x08143F, 0x07B9A6, 0x077A89, 0x070789, 0x039565, 0x0526C2, 0x0328B4, +}, +{ + 0x0C0000, 0x10A4FD, 0x16E2DB, 0x1FBE78, 0x0FADC3, 0x10C198, 0x2356C7, 0x1D5B96, + 0x0C0000, 0x0B3237, 0x1B0C1A, 0x11FB46, 0x08EE03, 0x048D66, 0x0C62CA, 0x07BFD5, + 0x197A5D, 0x1653E3, 0x1DFC1E, 0x178F16, 0x0F612C, 0x07D727, 0x103A49, 0x070E64, + 0x1A7539, 0x24B2BB, 0x17CFBD, 0x210709, 0x15C000, 0x1E2B0A, 0x12DB4F, 0x17B3F4, + 0x1A7539, 0x17CFBD, 0x1653E3, 0x1A54A0, 0x0E34D7, 0x168513, 0x0984BE, 0x0D33DC, + 0x153695, 0x131765, 0x0FAE4E, 0x0DA033, 0x2149E1, 0x1DF57D, 0x1F1C78, 0x1AF65B, + 0x1BC000, 0x140904, 0x15CD94, 0x10345E, 0x0DCCEE, 0x069F20, 0x0B2972, 0x058718, + 0x0F6C91, 0x0C1E5E, 0x0B9678, 0x0B37CE, 0x0A8B4E, 0x056018, 0x07BA22, 0x04BD0E, +}, +{ + 0x110000, 0x179466, 0x206C0C, 0x2CF87F, 0x16362A, 0x17BCED, 0x321044, 0x299714, + 0x110000, 0x0FDC79, 0x265125, 0x19794E, 0x0CA685, 0x0672FB, 0x118BF4, 0x0AFA6D, + 0x241804, 0x1FA181, 0x2A7A80, 0x21600A, 0x15C9A9, 0x0B1B77, 0x16FD3C, 0x09FF0D, + 0x257B66, 0x33FD33, 0x21BBA2, 0x2EC9F7, 0x1ED000, 0x2ABCF9, 0x1AB6B0, 0x219444, + 0x257B66, 0x21BBA2, 0x1FA181, 0x254D38, 0x142030, 0x1FE730, 0x0D7C0E, 0x12B423, + 0x1E0D52, 0x1B0BCF, 0x1636EE, 0x134D9E, 0x2F28A9, 0x2A711B, 0x2C12FF, 0x263256, + 0x275000, 0x1C621B, 0x1EE33C, 0x16F4DB, 0x138CFB, 0x09616E, 0x0FD00C, 0x07D4B7, + 0x15D9CE, 0x112B06, 0x106A80, 0x0FE464, 0x0EF004, 0x079D77, 0x0AF25B, 0x06B67F, +}, +{ + 0x160000, 0x1E83CF, 0x29F53D, 0x3A3286, 0x1CBE90, 0x1EB842, 0x40C9C2, 0x35D293, + 0x160000, 0x1486BA, 0x319630, 0x20F756, 0x105F06, 0x085891, 0x16B51E, 0x0E3506, + 0x2EB5AA, 0x28EF20, 0x36F8E1, 0x2B30FE, 0x1C3225, 0x0E5FC7, 0x1DC030, 0x0CEFB7, + 0x308193, 0x4347AC, 0x2BA786, 0x3C8CE5, 0x27E000, 0x374EE7, 0x229212, 0x2B7494, + 0x308193, 0x2BA786, 0x28EF20, 0x3045D0, 0x1A0B89, 0x29494D, 0x11735D, 0x183469, + 0x26E410, 0x230039, 0x1CBF8F, 0x18FB09, 0x3D0771, 0x36ECBA, 0x390986, 0x316E52, + 0x32E000, 0x24BB33, 0x27F8E4, 0x1DB557, 0x194D09, 0x0C23BB, 0x1476A6, 0x0A2256, + 0x1C470A, 0x1637AD, 0x153E87, 0x1490FA, 0x1354B9, 0x09DAD6, 0x0E2A94, 0x08AFF0, +}, +{ + 0x1C0000, 0x26D64D, 0x3566AA, 0x4A11C2, 0x249572, 0x27190E, 0x527525, 0x44805E, + 0x1C0000, 0x1A1FD6, 0x3F1C3E, 0x29F4F9, 0x14D607, 0x0A9F44, 0x1CE683, 0x1214F0, + 0x3B72D9, 0x341911, 0x45F6F0, 0x36F889, 0x23E2BB, 0x124B5B, 0x25DD54, 0x1076E9, + 0x3DBC30, 0x55A109, 0x378F64, 0x4D1069, 0x32C000, 0x46646C, 0x2BFFB9, 0x374E8E, + 0x3DBC30, 0x378F64, 0x341911, 0x3D7020, 0x2125F5, 0x348BD6, 0x1635BC, 0x1ECE57, + 0x317F5B, 0x2C8BEB, 0x2496B6, 0x1FCB22, 0x4DAC61, 0x45E778, 0x4897C2, 0x3EE97F, + 0x40C000, 0x2EBFB5, 0x32DFAE, 0x25CF86, 0x203380, 0x0F734B, 0x1A0B5F, 0x0CE5E2, + 0x23FD53, 0x1C46DC, 0x1B09C4, 0x1A2CE1, 0x189A60, 0x0C8AE2, 0x1207A5, 0x0B0E77, +}, +{ + 0x220000, 0x2F28CC, 0x40D818, 0x59F0FE, 0x2C6C53, 0x2F79DA, 0x642089, 0x532E29, + 0x220000, 0x1FB8F1, 0x4CA24B, 0x32F29C, 0x194D09, 0x0CE5F7, 0x2317E8, 0x15F4DB, + 0x483007, 0x3F4303, 0x54F4FF, 0x42C014, 0x2B9351, 0x1636EE, 0x2DFA79, 0x13FE1A, + 0x4AF6CC, 0x67FA67, 0x437743, 0x5D93EE, 0x3DA000, 0x5579F1, 0x356D61, 0x432888, + 0x4AF6CC, 0x437743, 0x3F4303, 0x4A9A70, 0x284060, 0x3FCE60, 0x1AF81B, 0x256845, + 0x3C1AA5, 0x36179D, 0x2C6DDD, 0x269B3C, 0x5E5152, 0x54E237, 0x5825FE, 0x4C64AD, + 0x4EA000, 0x38C437, 0x3DC678, 0x2DE9B5, 0x2719F7, 0x12C2DB, 0x1FA018, 0x0FA96E, + 0x2BB39B, 0x22560C, 0x20D500, 0x1FC8C8, 0x1DE007, 0x0F3AEE, 0x15E4B7, 0x0D6CFE, +}, +{ + 0x2C0000, 0x3D079E, 0x53EA79, 0x74650C, 0x397D20, 0x3D7083, 0x819383, 0x6BA525, + 0x2C0000, 0x290D75, 0x632C61, 0x41EEAC, 0x20BE0C, 0x10B121, 0x2D6A3B, 0x1C6A0C, + 0x5D6B54, 0x51DE40, 0x6DF1C2, 0x5661FB, 0x38644B, 0x1CBF8F, 0x3B8060, 0x19DF6D, + 0x610326, 0x868F57, 0x574F0B, 0x7919CA, 0x4FC000, 0x6E9DCE, 0x452423, 0x56E928, + 0x610326, 0x574F0B, 0x51DE40, 0x608BA0, 0x341713, 0x52929A, 0x22E6BA, 0x3068D2, + 0x4DC821, 0x460071, 0x397F1E, 0x31F611, 0x7A0EE2, 0x6DD974, 0x72130C, 0x62DCA3, + 0x65C000, 0x497665, 0x4FF1C9, 0x3B6AAE, 0x329A12, 0x184776, 0x28ED4D, 0x1444AC, + 0x388E14, 0x2C6F5A, 0x2A7D0F, 0x2921F4, 0x26A973, 0x13B5AD, 0x1C5528, 0x115FDF, +}, +}; + +static const int32_t bink_inter_quant[16][64] = { +{ + 0x010000, 0x017946, 0x01A5A9, 0x0248DC, 0x016363, 0x0152A7, 0x0243EC, 0x0209EA, + 0x012000, 0x00E248, 0x01BBDA, 0x015CBC, 0x00A486, 0x0053E0, 0x00F036, 0x008095, + 0x01B701, 0x016959, 0x01B0B9, 0x0153FD, 0x00F8E7, 0x007EE4, 0x00EA30, 0x007763, + 0x01B701, 0x0260EB, 0x019DE9, 0x023E1B, 0x017000, 0x01FE6E, 0x012DB5, 0x01A27B, + 0x01E0D1, 0x01B0B9, 0x018A33, 0x01718D, 0x00D87A, 0x014449, 0x007B9A, 0x00AB71, + 0x013178, 0x0112EA, 0x00AD08, 0x009BB9, 0x023D97, 0x020437, 0x021CCC, 0x01E6B4, + 0x018000, 0x012DB5, 0x0146D9, 0x0100CE, 0x00CFD2, 0x006E5C, 0x00B0E4, 0x005A2D, + 0x00E9CC, 0x00B7B1, 0x00846F, 0x006B85, 0x008337, 0x0042E5, 0x004A10, 0x002831, +}, +{ + 0x015555, 0x01F708, 0x023237, 0x030BD0, 0x01D9D9, 0x01C389, 0x03053B, 0x02B7E3, + 0x018000, 0x012DB5, 0x024FCE, 0x01D0FA, 0x00DB5D, 0x006FD5, 0x014048, 0x00AB71, + 0x024957, 0x01E1CC, 0x0240F7, 0x01C551, 0x014BDE, 0x00A92F, 0x013840, 0x009F2F, + 0x024957, 0x032BE4, 0x0227E1, 0x02FD7A, 0x01EAAB, 0x02A893, 0x019247, 0x022DF9, + 0x028116, 0x0240F7, 0x020D99, 0x01ECBC, 0x0120A3, 0x01B061, 0x00A4CE, 0x00E497, + 0x01974B, 0x016E8E, 0x00E6B5, 0x00CFA2, 0x02FCC9, 0x02B04A, 0x02D110, 0x0288F1, + 0x020000, 0x019247, 0x01B3CC, 0x015668, 0x011518, 0x009325, 0x00EBDA, 0x00783D, + 0x0137BB, 0x00F4ED, 0x00B093, 0x008F5C, 0x00AEF4, 0x005931, 0x0062BF, 0x003597, +}, +{ + 0x01AAAB, 0x0274CB, 0x02BEC4, 0x03CEC4, 0x02504F, 0x02346C, 0x03C689, 0x0365DC, + 0x01E000, 0x017922, 0x02E3C1, 0x024539, 0x011235, 0x008BCA, 0x01905A, 0x00D64D, + 0x02DBAD, 0x025A40, 0x02D134, 0x0236A5, 0x019ED6, 0x00D37B, 0x018650, 0x00C6FB, + 0x02DBAD, 0x03F6DD, 0x02B1D9, 0x03BCD8, 0x026555, 0x0352B8, 0x01F6D8, 0x02B977, + 0x03215C, 0x02D134, 0x029100, 0x0267EB, 0x0168CC, 0x021C7A, 0x00CE01, 0x011DBD, + 0x01FD1E, 0x01CA31, 0x012062, 0x01038A, 0x03BBFB, 0x035C5C, 0x038554, 0x032B2D, + 0x028000, 0x01F6D8, 0x0220C0, 0x01AC02, 0x015A5E, 0x00B7EF, 0x0126D1, 0x00964C, + 0x0185A9, 0x013228, 0x00DCB8, 0x00B333, 0x00DAB2, 0x006F7D, 0x007B6F, 0x0042FC, +}, +{ + 0x020000, 0x02F28D, 0x034B52, 0x0491B8, 0x02C6C5, 0x02A54E, 0x0487D8, 0x0413D5, + 0x024000, 0x01C48F, 0x0377B5, 0x02B977, 0x01490C, 0x00A7BF, 0x01E06C, 0x01012A, + 0x036E03, 0x02D2B3, 0x036172, 0x02A7FA, 0x01F1CE, 0x00FDC7, 0x01D460, 0x00EEC7, + 0x036E03, 0x04C1D6, 0x033BD1, 0x047C37, 0x02E000, 0x03FCDD, 0x025B6A, 0x0344F5, + 0x03C1A1, 0x036172, 0x031466, 0x02E31B, 0x01B0F5, 0x028892, 0x00F735, 0x0156E2, + 0x0262F1, 0x0225D5, 0x015A10, 0x013772, 0x047B2D, 0x04086E, 0x043998, 0x03CD69, + 0x030000, 0x025B6A, 0x028DB3, 0x02019B, 0x019FA3, 0x00DCB8, 0x0161C7, 0x00B45B, + 0x01D398, 0x016F63, 0x0108DD, 0x00D70A, 0x01066F, 0x0085C9, 0x00941F, 0x005062, +}, +{ + 0x02AAAB, 0x03EE11, 0x04646D, 0x0617A0, 0x03B3B2, 0x038713, 0x060A75, 0x056FC6, + 0x030000, 0x025B6A, 0x049F9B, 0x03A1F4, 0x01B6BB, 0x00DFAA, 0x028090, 0x0156E2, + 0x0492AE, 0x03C399, 0x0481ED, 0x038AA2, 0x0297BD, 0x01525F, 0x027080, 0x013E5E, + 0x0492AE, 0x0657C8, 0x044FC1, 0x05FAF4, 0x03D555, 0x055126, 0x03248D, 0x045BF2, + 0x05022D, 0x0481ED, 0x041B33, 0x03D979, 0x024147, 0x0360C3, 0x01499C, 0x01C92E, + 0x032E96, 0x02DD1C, 0x01CD6A, 0x019F43, 0x05F991, 0x056093, 0x05A220, 0x0511E1, + 0x040000, 0x03248D, 0x036799, 0x02ACCF, 0x022A2F, 0x01264B, 0x01D7B5, 0x00F079, + 0x026F75, 0x01E9D9, 0x016127, 0x011EB8, 0x015DE9, 0x00B262, 0x00C57F, 0x006B2D, +}, +{ + 0x038000, 0x052876, 0x05C3CF, 0x07FF02, 0x04DBD9, 0x04A148, 0x07EDBA, 0x0722B4, + 0x03F000, 0x0317FB, 0x06117C, 0x04C491, 0x023FD5, 0x01258F, 0x0348BD, 0x01C209, + 0x060085, 0x04F0B9, 0x05EA87, 0x04A5F5, 0x036728, 0x01BC1C, 0x0333A8, 0x01A1DB, + 0x060085, 0x085336, 0x05A8AE, 0x07D960, 0x050800, 0x06FA82, 0x041FF9, 0x05B8AE, + 0x0692DA, 0x05EA87, 0x0563B2, 0x050D6E, 0x02F5AD, 0x046F00, 0x01B09C, 0x02580C, + 0x042D25, 0x03C235, 0x025D9B, 0x022108, 0x07D78F, 0x070EC1, 0x0764CA, 0x06A777, + 0x054000, 0x041FF9, 0x0477F9, 0x0382D0, 0x02D75E, 0x018242, 0x026B1D, 0x013B9F, + 0x03324A, 0x0282ED, 0x01CF83, 0x017851, 0x01CB42, 0x00EA21, 0x010336, 0x008CAC, +}, +{ + 0x040000, 0x05E519, 0x0696A4, 0x092370, 0x058D8A, 0x054A9C, 0x090FB0, 0x0827AA, + 0x048000, 0x03891F, 0x06EF69, 0x0572EE, 0x029218, 0x014F7E, 0x03C0D8, 0x020254, + 0x06DC05, 0x05A565, 0x06C2E4, 0x054FF3, 0x03E39B, 0x01FB8E, 0x03A8C0, 0x01DD8D, + 0x06DC05, 0x0983AC, 0x0677A2, 0x08F86E, 0x05C000, 0x07F9B9, 0x04B6D4, 0x0689EB, + 0x078343, 0x06C2E4, 0x0628CC, 0x05C635, 0x0361EA, 0x051124, 0x01EE69, 0x02ADC5, + 0x04C5E1, 0x044BAA, 0x02B41F, 0x026EE5, 0x08F65A, 0x0810DD, 0x087330, 0x079AD1, + 0x060000, 0x04B6D4, 0x051B65, 0x040337, 0x033F47, 0x01B970, 0x02C38F, 0x0168B6, + 0x03A730, 0x02DEC6, 0x0211BA, 0x01AE14, 0x020CDD, 0x010B93, 0x01283E, 0x00A0C4, +}, +{ + 0x050000, 0x075E60, 0x083C4D, 0x0B6C4C, 0x06F0ED, 0x069D43, 0x0B539C, 0x0A3194, + 0x05A000, 0x046B67, 0x08AB44, 0x06CFAA, 0x03369E, 0x01A35E, 0x04B10F, 0x0282E8, + 0x089307, 0x070EBF, 0x08739C, 0x06A3F0, 0x04DC82, 0x027A72, 0x0492F0, 0x0254F0, + 0x089307, 0x0BE497, 0x08158B, 0x0B3689, 0x073000, 0x09F827, 0x05E489, 0x082C66, + 0x096413, 0x08739C, 0x07B2FF, 0x0737C2, 0x043A64, 0x06556D, 0x026A04, 0x035936, + 0x05F75A, 0x055E94, 0x036127, 0x030A9E, 0x0B33F1, 0x0A1514, 0x0A8FFC, 0x098186, + 0x078000, 0x05E489, 0x06623F, 0x050405, 0x040F19, 0x0227CC, 0x037473, 0x01C2E3, + 0x0490FC, 0x039677, 0x029629, 0x021999, 0x029015, 0x014E78, 0x01724E, 0x00C8F5, +}, +{ + 0x060000, 0x08D7A6, 0x09E1F6, 0x0DB528, 0x085450, 0x07EFEA, 0x0D9788, 0x0C3B7E, + 0x06C000, 0x054DAE, 0x0A671E, 0x082C66, 0x03DB24, 0x01F73E, 0x05A145, 0x03037D, + 0x0A4A08, 0x087818, 0x0A2455, 0x07F7ED, 0x05D569, 0x02F955, 0x057D20, 0x02CC54, + 0x0A4A08, 0x0E4582, 0x09B373, 0x0D74A5, 0x08A000, 0x0BF696, 0x07123E, 0x09CEE0, + 0x0B44E4, 0x0A2455, 0x093D32, 0x08A950, 0x0512DF, 0x0799B6, 0x02E59E, 0x0404A7, + 0x0728D2, 0x06717F, 0x040E2F, 0x03A657, 0x0D7187, 0x0C194B, 0x0CACC8, 0x0B683A, + 0x090000, 0x07123E, 0x07A918, 0x0604D2, 0x04DEEA, 0x029629, 0x042556, 0x021D11, + 0x057AC8, 0x044E28, 0x031A97, 0x02851E, 0x03134C, 0x01915C, 0x01BC5D, 0x00F126, +}, +{ + 0x080000, 0x0BCA33, 0x0D2D48, 0x1246E0, 0x0B1B15, 0x0A9538, 0x121F5F, 0x104F53, + 0x090000, 0x07123E, 0x0DDED2, 0x0AE5DD, 0x052430, 0x029EFD, 0x0781B1, 0x0404A7, + 0x0DB80B, 0x0B4ACB, 0x0D85C7, 0x0A9FE7, 0x07C736, 0x03F71D, 0x075180, 0x03BB1A, + 0x0DB80B, 0x130757, 0x0CEF44, 0x11F0DC, 0x0B8000, 0x0FF372, 0x096DA8, 0x0D13D6, + 0x0F0686, 0x0D85C7, 0x0C5198, 0x0B8C6A, 0x06C3D4, 0x0A2248, 0x03DCD3, 0x055B8A, + 0x098BC3, 0x089754, 0x05683E, 0x04DDC9, 0x11ECB4, 0x1021B9, 0x10E661, 0x0F35A3, + 0x0C0000, 0x096DA8, 0x0A36CB, 0x08066E, 0x067E8E, 0x0372E1, 0x05871E, 0x02D16B, + 0x074E60, 0x05BD8B, 0x042374, 0x035C28, 0x0419BB, 0x021726, 0x02507C, 0x014188, +}, +{ + 0x0C0000, 0x11AF4C, 0x13C3EC, 0x1B6A50, 0x10A89F, 0x0FDFD4, 0x1B2F0F, 0x1876FD, + 0x0D8000, 0x0A9B5D, 0x14CE3C, 0x1058CB, 0x07B649, 0x03EE7B, 0x0B4289, 0x0606FB, + 0x149410, 0x10F030, 0x1448AB, 0x0FEFDA, 0x0BAAD2, 0x05F2AB, 0x0AFA40, 0x0598A7, + 0x149410, 0x1C8B03, 0x1366E6, 0x1AE949, 0x114000, 0x17ED2B, 0x0E247C, 0x139DC1, + 0x1689C8, 0x1448AB, 0x127A63, 0x11529F, 0x0A25BE, 0x0F336D, 0x05CB3C, 0x08094E, + 0x0E51A4, 0x0CE2FE, 0x081C5D, 0x074CAE, 0x1AE30E, 0x183296, 0x195991, 0x16D074, + 0x120000, 0x0E247C, 0x0F5230, 0x0C09A5, 0x09BDD5, 0x052C51, 0x084AAC, 0x043A21, + 0x0AF590, 0x089C51, 0x06352E, 0x050A3B, 0x062698, 0x0322B9, 0x0378BA, 0x01E24D, +}, +{ + 0x110000, 0x190DAC, 0x1C0039, 0x26D69C, 0x17998C, 0x167D16, 0x2682AB, 0x22A891, + 0x132000, 0x0F06C3, 0x1D797F, 0x172876, 0x0AECE7, 0x0591D9, 0x0FF398, 0x0889E3, + 0x1D2717, 0x17FEEF, 0x1CBC47, 0x1693CA, 0x108754, 0x086D1D, 0x0F8D30, 0x07ED98, + 0x1D2717, 0x286F9A, 0x1B7C71, 0x261FD3, 0x187000, 0x21E552, 0x140904, 0x1BCA27, + 0x1FEDDC, 0x1CBC47, 0x1A2D62, 0x188A62, 0x0E6022, 0x1588DA, 0x083540, 0x0B6284, + 0x1448FE, 0x124192, 0x0B7D84, 0x0A574B, 0x2616FF, 0x2247AA, 0x23E98D, 0x2051FA, + 0x198000, 0x140904, 0x15B46F, 0x110DAA, 0x0DCCEE, 0x07541E, 0x0BBF1F, 0x05FD04, + 0x0F868B, 0x0C32C8, 0x08CB57, 0x0723D4, 0x08B6AD, 0x047130, 0x04EB08, 0x02AB42, +}, +{ + 0x160000, 0x206C0C, 0x243C86, 0x3242E8, 0x1E8A79, 0x1D1A59, 0x31D646, 0x2CDA25, + 0x18C000, 0x13722A, 0x2624C3, 0x1DF820, 0x0E2385, 0x073537, 0x14A4A7, 0x0B0CCC, + 0x25BA1D, 0x1F0DAE, 0x252FE4, 0x1D37BB, 0x1563D6, 0x0AE78E, 0x142021, 0x0A4288, + 0x25BA1D, 0x345430, 0x2391FB, 0x31565C, 0x1FA000, 0x2BDD7A, 0x19ED8D, 0x23F68C, + 0x2951EF, 0x252FE4, 0x21E061, 0x1FC224, 0x129A87, 0x1BDE47, 0x0A9F44, 0x0EBBBA, + 0x1A4058, 0x17A026, 0x0EDEAB, 0x0D61E9, 0x314AEF, 0x2C5CBE, 0x2E798A, 0x29D380, + 0x210000, 0x19ED8D, 0x1C16AE, 0x1611AE, 0x11DC06, 0x097BEA, 0x0F3391, 0x07BFE7, + 0x141787, 0x0FC93E, 0x0B617F, 0x093D6D, 0x0B46C1, 0x05BFA8, 0x065D55, 0x037437, +}, +{ + 0x1C0000, 0x2943B2, 0x2E1E7C, 0x3FF810, 0x26DEC9, 0x250A43, 0x3F6DCE, 0x3915A3, + 0x1F8000, 0x18BFD8, 0x308BE1, 0x262485, 0x11FEA9, 0x092C75, 0x1A45EB, 0x0E1049, + 0x300425, 0x2785C6, 0x2F5439, 0x252FA8, 0x1B393F, 0x0DE0E4, 0x199D41, 0x0D0EDC, + 0x300425, 0x4299B2, 0x2D456E, 0x3ECB00, 0x284000, 0x37D40F, 0x20FFCB, 0x2DC56D, + 0x3496D3, 0x2F5439, 0x2B1D93, 0x286B74, 0x17AD66, 0x2377FE, 0x0D84E2, 0x12C062, + 0x21692A, 0x1E11A5, 0x12ECDA, 0x110840, 0x3EBC76, 0x387608, 0x3B2652, 0x353BBA, + 0x2A0000, 0x20FFCB, 0x23BFC6, 0x1C1681, 0x16BAF1, 0x0C1213, 0x1358E8, 0x09DCF8, + 0x19924F, 0x141767, 0x0E7C16, 0x0BC28A, 0x0E5A0D, 0x075104, 0x0819B2, 0x04655D, +}, +{ + 0x220000, 0x321B58, 0x380072, 0x4DAD38, 0x2F3318, 0x2CFA2D, 0x4D0556, 0x455122, + 0x264000, 0x1E0D86, 0x3AF2FE, 0x2E50EB, 0x15D9CE, 0x0B23B2, 0x1FE730, 0x1113C7, + 0x3A4E2D, 0x2FFDDF, 0x39788E, 0x2D2795, 0x210EA8, 0x10DA39, 0x1F1A61, 0x0FDB2F, + 0x3A4E2D, 0x50DF33, 0x36F8E1, 0x4C3FA5, 0x30E000, 0x43CAA5, 0x281209, 0x37944D, + 0x3FDBB7, 0x39788E, 0x345AC4, 0x3114C3, 0x1CC044, 0x2B11B4, 0x106A80, 0x16C509, + 0x2891FC, 0x248324, 0x16FB08, 0x14AE97, 0x4C2DFD, 0x448F54, 0x47D31B, 0x40A3F5, + 0x330000, 0x281209, 0x2B68DF, 0x221B53, 0x1B99DB, 0x0EA83B, 0x177E3E, 0x0BFA09, + 0x1F0D17, 0x18658F, 0x1196AE, 0x0E47A8, 0x116D5A, 0x08E260, 0x09D60F, 0x055684, +}, +{ + 0x2C0000, 0x40D818, 0x48790C, 0x6485D0, 0x3D14F2, 0x3A34B2, 0x63AC8D, 0x59B44A, + 0x318000, 0x26E454, 0x4C4986, 0x3BF03F, 0x1C470A, 0x0E6A6E, 0x29494D, 0x161998, + 0x4B743A, 0x3E1B5C, 0x4A5FC7, 0x3A6F75, 0x2AC7AC, 0x15CF1D, 0x284041, 0x148510, + 0x4B743A, 0x68A861, 0x4723F6, 0x62ACB8, 0x3F4000, 0x57BAF3, 0x33DB1A, 0x47ED19, + 0x52A3DE, 0x4A5FC7, 0x43C0C2, 0x3F8448, 0x25350D, 0x37BC8E, 0x153E87, 0x1D7775, + 0x3480B0, 0x2F404C, 0x1DBD56, 0x1AC3D2, 0x6295DE, 0x58B97B, 0x5CF313, 0x53A701, + 0x420000, 0x33DB1A, 0x382D5C, 0x2C235D, 0x23B80D, 0x12F7D4, 0x1E6723, 0x0F7FCF, + 0x282F0E, 0x1F927D, 0x16C2FF, 0x127AD9, 0x168D83, 0x0B7F50, 0x0CBAAA, 0x06E86E, +}, +}; + +static const uint8_t binkb_runbits[64] = { + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 2, 2, 1, 0, +}; + +static const uint8_t binkb_intra_seed[64] = { + 16, 16, 16, 19, 16, 19, 22, 22, + 22, 22, 26, 24, 26, 22, 22, 27, + 27, 27, 26, 26, 26, 29, 29, 29, + 27, 27, 27, 26, 34, 34, 34, 29, + 29, 29, 27, 27, 37, 34, 34, 32, + 32, 29, 29, 38, 37, 35, 35, 34, + 35, 40, 40, 40, 38, 38, 48, 48, + 46, 46, 58, 56, 56, 69, 69, 83, +}; + +static const uint8_t binkb_inter_seed[64] = { + 16, 17, 17, 18, 18, 18, 19, 19, + 19, 19, 20, 20, 20, 20, 20, 21, + 21, 21, 21, 21, 21, 22, 22, 22, + 22, 22, 22, 22, 23, 23, 23, 23, + 23, 23, 23, 23, 24, 24, 24, 25, + 24, 24, 24, 25, 26, 26, 26, 26, + 25, 27, 27, 27, 27, 27, 28, 28, + 28, 28, 30, 30, 30, 31, 31, 33, +}; + +static const uint8_t binkb_num[16] = { + 1, 4, 5, 2, 7, 8, 3, 7, 4, 9, 5, 6, 7, 8, 9, 10 +}; + +static const uint8_t binkb_den[16] = { + 1, 3, 3, 1, 3, 3, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1 +}; + +#endif /* AVCODEC_BINKDATA_H */ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/BinkDecoder.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/BinkDecoder.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/BinkDecoder.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/BinkDecoder.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,222 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This code is based on the Bink decoder from the FFmpeg project which can be obtained from http://www.ffmpeg.org/ + * below is the license from FFmpeg + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Bink video decoder + * Copyright (c) 2009 Konstantin Shishkov + * Copyright (C) 2011 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BinkDecoder_h_ +#define _BinkDecoder_h_ + +#include +#include +#include "FileStream.h" +#include "BinkAudio.h" +#include "BinkVideo.h" +#include "BitReader.h" + +const int kBIKbID = 'BIKb'; // not supported +const int kBIKfID = 'BIKf'; +const int kBIKgID = 'BIKg'; +const int kBIKhID = 'BIKh'; +const int kBIKiID = 'BIKi'; + +const int kFlagAlpha = 0x00100000; +const int kFlagGray = 0x00020000; + +const int kNumTrees = 16; + +// exportable interface +struct BinkHandle +{ + bool isValid; + int instanceIndex; +}; + +struct AudioInfo +{ + uint32_t sampleRate; + uint32_t nChannels; + + uint32_t idealBufferSize; +}; + +struct ImagePlane +{ + uint32_t width; + uint32_t height; + uint32_t pitch; + uint8_t *data; +}; + +typedef ImagePlane YUVbuffer[3]; + +BinkHandle Bink_Open (const char* fileName); +void Bink_Close (BinkHandle &handle); +uint32_t Bink_GetNumAudioTracks (BinkHandle &handle); +void Bink_GetFrameSize (BinkHandle &handle, uint32_t &width, uint32_t &height); +AudioInfo Bink_GetAudioTrackDetails (BinkHandle &handle, uint32_t trackIndex); +uint32_t Bink_GetAudioData (BinkHandle &handle, uint32_t trackIndex, int16_t *data); +float Bink_GetFrameRate (BinkHandle &handle); +uint32_t Bink_GetNumFrames (BinkHandle &handle); +uint32_t Bink_GetCurrentFrameNum (BinkHandle &handle); +uint32_t Bink_GetNextFrame (BinkHandle &handle, YUVbuffer yuv); +void Bink_GotoFrame (BinkHandle &handle, uint32_t frameNum); + +// for internal use only +struct Plane +{ + uint8_t *current; + uint8_t *last; + + uint32_t width; + uint32_t height; + uint32_t pitch; + + bool Init(uint32_t width, uint32_t height) + { + // align to 16 bytes + width += width % 16; + height += height % 16; + + current = new uint8_t[width * height]; + last = new uint8_t[width * height]; + this->width = width; + this->height = height; + this->pitch = width; + + return true; + } + + void Swap() + { + std::swap(current, last); + } +}; + +class BinkDecoder +{ + public: + + uint32_t frameWidth; + uint32_t frameHeight; + + BinkDecoder(); + ~BinkDecoder(); + + bool Open(const std::string &fileName); + uint32_t GetNumFrames(); + uint32_t GetCurrentFrameNum(); + float GetFrameRate(); + void GetNextFrame(YUVbuffer yuv); + void GotoFrame(uint32_t frameNum); + + AudioInfo GetAudioTrackDetails(uint32_t trackIndex); + uint32_t GetNumAudioTracks(); + uint32_t GetAudioData(uint32_t trackIndex, int16_t *audioBuffer); + + private: + + BinkCommon::FileStream file; + + uint32_t signature; + uint32_t fileSize; + + uint32_t nFrames; + uint32_t largestFrameSize; + + uint32_t fpsDividend; + uint32_t fpsDivider; + uint32_t videoFlags; + + bool hasAlpha; + bool swapPlanes; + + uint32_t currentFrame; + + std::vector planes; + + Bundle bundle[BINK_NB_SRC]; + Tree col_high[kNumTrees]; // trees for decoding high nibble in "colours" data type + int col_lastval; // value of last decoded high nibble in "colours" data type + + std::vector frames; + std::vector audioTracks; + uint32_t nAudioTracks; + + // huffman tree functions + void InitTrees(); + void Merge(BinkCommon::BitReader &bits, uint8_t *dst, uint8_t *src, int size); + void ReadTree(BinkCommon::BitReader &bits, Tree *tree); + uint8_t GetHuff(BinkCommon::BitReader &bits); + uint8_t GetHuffSymbol(BinkCommon::BitReader &bits, Tree &tree); + + // video related functions + void InitBundles(); + void FreeBundles(); + void InitLengths(int width, int bw); + void ReadBundle(BinkCommon::BitReader &bits, int bundle_num); + int ReadRuns(BinkCommon::BitReader &bits, Bundle *b); + int ReadMotionValues(BinkCommon::BitReader &bits, Bundle *b); + int ReadBlockTypes(BinkCommon::BitReader &bits, Bundle *b); + int ReadPatterns(BinkCommon::BitReader &bits, Bundle *b); + int ReadColors(BinkCommon::BitReader &bits, Bundle *b); + int ReadDCs(BinkCommon::BitReader &bits, Bundle *b, int start_bits, int has_sign); + int GetValue(int bundle); + int ReadDCTcoeffs(BinkCommon::BitReader &bits, int32_t block[64], const uint8_t *scan, const int32_t quant_matrices[16][64], int q); + int ReadResidue(BinkCommon::BitReader &bits, DCTELEM block[64], int masks_count); + void PutPixels8x8Overlapped(uint8_t *dst, uint8_t *src, int stride); + int DecodePlane(BinkCommon::BitReader &bits, int plane_idx, int is_chroma); + int DecodeFrame(BinkCommon::BitReader &bits); + void PutPixelsTab(uint8_t *dest, uint8_t *prev, uint32_t pitch, uint32_t size); + void FillBlockTab(uint8_t *dest, uint32_t value, uint32_t pitch, uint32_t size); + void AddPixels8(uint8_t *dest, DCTELEM *block, uint32_t stride); + void ClearBlock(DCTELEM *block); + void VideoPacket(uint32_t packetSize); + + // audio functions + float GetAudioFloat(BinkCommon::BitReader &bits); + bool CreateAudioTrack(uint32_t sampleRate, uint16_t flags); + void AudioPacket(uint32_t trackIndex, uint32_t packetSize); + void DecodeAudioBlock(uint32_t trackIndex, BinkCommon::BitReader &bits); +}; + +#endif diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/BinkVideo.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/BinkVideo.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/BinkVideo.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/BinkVideo.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,119 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This code is based on the Bink decoder from the FFmpeg project which can be obtained from http://www.ffmpeg.org/ + * below is the license from FFmpeg + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Bink video decoder + * Copyright (c) 2009 Konstantin Shishkov + * Copyright (C) 2011 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BinkVideo_h_ +#define _BinkVideo_h_ + +#include +#include "HuffmanVLC.h" + +/** number of bits used to store first DC value in bundle */ +const int kDCstartBits = 11; + +/** + * IDs for different data types used in Bink video codec + */ +enum Sources { + BINK_SRC_BLOCK_TYPES = 0, ///< 8x8 block types + BINK_SRC_SUB_BLOCK_TYPES, ///< 16x16 block types (a subset of 8x8 block types) + BINK_SRC_COLORS, ///< pixel values used for different block types + BINK_SRC_PATTERN, ///< 8-bit values for 2-colour pattern fill + BINK_SRC_X_OFF, ///< X components of motion value + BINK_SRC_Y_OFF, ///< Y components of motion value + BINK_SRC_INTRA_DC, ///< DC values for intrablocks with DCT + BINK_SRC_INTER_DC, ///< DC values for interblocks with DCT + BINK_SRC_RUN, ///< run lengths for special fill block + + BINK_NB_SRC +}; + +static BinkCommon::VLCtable bink_trees[16]; + +/** + * data needed to decode 4-bit Huffman-coded value + */ +typedef struct Tree +{ + int vlc_num; ///< tree number (in bink_trees[]) + uint8_t symbols[16]; ///< leaf value to symbol mapping +} Tree; + +/** + * data structure used for decoding single Bink data type + */ +typedef struct Bundle +{ + int len; ///< length of number of entries to decode (in bits) + Tree tree; ///< Huffman tree-related data + uint8_t *data; ///< buffer for decoded symbols + uint8_t *data_end; ///< buffer end + uint8_t *cur_dec; ///< pointer to the not yet decoded part of the buffer + uint8_t *cur_ptr; ///< pointer to the data that is not read from buffer yet +} Bundle; + +/** + * Bink video block types + */ +enum BlockTypes { + SKIP_BLOCK = 0, ///< skipped block + SCALED_BLOCK, ///< block has size 16x16 + MOTION_BLOCK, ///< block is copied from previous frame with some offset + RUN_BLOCK, ///< block is composed from runs of colours with custom scan order + RESIDUE_BLOCK, ///< motion block with some difference added + INTRA_BLOCK, ///< intra DCT block + FILL_BLOCK, ///< block is filled with single colour + INTER_BLOCK, ///< motion block with DCT applied to the difference + PATTERN_BLOCK, ///< block is filled with two colours following custom pattern + RAW_BLOCK, ///< uncoded 8x8 block +}; + +struct VideoFrame +{ + uint32_t offset; + uint32_t keyFrame; + uint32_t size; +}; + +#endif \ No newline at end of file diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/BitReader.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/BitReader.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/BitReader.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/BitReader.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BinkBitReader_h_ +#define _BinkBitReader_h_ + +#include +#include "FileStream.h" + +namespace BinkCommon { + +class BitReader +{ + public: + BitReader(BinkCommon::FileStream &file, uint32_t size); + ~BitReader(); + uint32_t GetBit(); + uint32_t GetBits(uint32_t n); + void SkipBits(uint32_t n); + + uint32_t GetSize(); + uint32_t GetPosition(); + + private: + uint32_t totalSize; + uint32_t currentOffset; + uint32_t bytesRead; + + BinkCommon::FileStream *file; + + uint8_t cache; + uint32_t nCachedBits; + + void FillCache(); +}; + +} // close namespace BinkCommon + +#endif \ No newline at end of file diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/dct32.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/dct32.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/dct32.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/dct32.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,25 @@ +/* + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DCT32_H +#define AVCODEC_DCT32_H + +void ff_dct32_float(float *dst, const float *src); +void ff_dct32_fixed(int *dst, const int *src); + +#endif diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/dct.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/dct.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/dct.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/dct.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * (I)DCT Transforms + * Copyright (c) 2009 Peter Ross + * Copyright (c) 2010 Alex Converse + * Copyright (c) 2010 Vitor Sessak + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DCT_H +#define AVCODEC_DCT_H + +#include "rdft.h" + +struct DCTContext { + int nbits; + int inverse; + RDFTContext rdft; + const float *costab; + FFTSample *csc2; + void (*dct_calc)(struct DCTContext *s, FFTSample *data); + void (*dct32)(FFTSample *out, const FFTSample *in); +}; + +/** + * Set up DCT. + * @param nbits size of the input array: + * (1 << nbits) for DCT-II, DCT-III and DST-I + * (1 << nbits) + 1 for DCT-I + * + * @note the first element of the input of DST-I is ignored + */ +int ff_dct_init(DCTContext *s, int nbits, enum DCTTransformType type); +void ff_dct_end (DCTContext *s); + +void ff_dct_init_mmx(DCTContext *s); + +#endif /* AVCODEC_DCT_H */ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/FFmpeg_includes.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/FFmpeg_includes.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/FFmpeg_includes.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/FFmpeg_includes.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This code is based on the Bink decoder from the FFmpeg project which can be obtained from http://www.ffmpeg.org/ + * below is the license from FFmpeg + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Bink video decoder + * Copyright (c) 2009 Konstantin Shishkov + * Copyright (C) 2011 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _FFmpeg_includes_h_ +#define _FFmpeg_includes_h_ + +#include + +#define av_cold + +// taken from FFmpeg - mem.h +#ifdef _MSC_VER +#define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v +#else // DG: add alternative that should work with at least GCC and clang +#define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v +#endif +#define M_PI 3.14159265358979323846 /* pi */ +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ + +#define HAVE_MMX 0 +#define ARCH_ARM 0 +#define HAVE_ALTIVEC 0 +#define CONFIG_MDCT 1 + +typedef short DCTELEM; + +#endif diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/fft.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/fft.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/fft.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/fft.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,160 @@ +/* + * This file has been modified from its original release by Barry Duncan to comment out header includes for + * 'config.h' and 'libavutil/mem.h', which are both part of FFmpeg but are not present in this project. This + * file has also been modified to add an include for 'FFmpeg_includes.h' which includes the functionality from + * the removed header files this file is otherwise identical to the FFmpeg release. + */ + +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_FFT_H +#define AVCODEC_FFT_H + +#ifndef CONFIG_FFT_FLOAT +#define CONFIG_FFT_FLOAT 1 +#endif + +#include +//#include "config.h" +//#include "libavutil/mem.h" +#include "FFmpeg_includes.h" + +#if CONFIG_FFT_FLOAT + +#include "avfft.h" + +#define FFT_NAME(x) x + +typedef float FFTDouble; + +#else + +#define FFT_NAME(x) x ## _fixed + +typedef int16_t FFTSample; +typedef int FFTDouble; + +typedef struct FFTComplex { + int16_t re, im; +} FFTComplex; + +typedef struct FFTContext FFTContext; + +#endif /* CONFIG_FFT_FLOAT */ + +typedef struct FFTDComplex { + FFTDouble re, im; +} FFTDComplex; + +/* FFT computation */ + +struct FFTContext { + int nbits; + int inverse; + uint16_t *revtab; + FFTComplex *tmp_buf; + int mdct_size; /* size of MDCT (i.e. number of input data * 2) */ + int mdct_bits; /* n = 2^nbits */ + /* pre/post rotation tables */ + FFTSample *tcos; + FFTSample *tsin; + /** + * Do the permutation needed BEFORE calling fft_calc(). + */ + void (*fft_permute)(struct FFTContext *s, FFTComplex *z); + /** + * Do a complex FFT with the parameters defined in ff_fft_init(). The + * input data must be permuted before. No 1.0/sqrt(n) normalization is done. + */ + void (*fft_calc)(struct FFTContext *s, FFTComplex *z); + void (*imdct_calc)(struct FFTContext *s, FFTSample *output, const FFTSample *input); + void (*imdct_half)(struct FFTContext *s, FFTSample *output, const FFTSample *input); + void (*mdct_calc)(struct FFTContext *s, FFTSample *output, const FFTSample *input); + void (*mdct_calcw)(struct FFTContext *s, FFTDouble *output, const FFTSample *input); + int fft_permutation; +#define FF_FFT_PERM_DEFAULT 0 +#define FF_FFT_PERM_SWAP_LSBS 1 +#define FF_FFT_PERM_AVX 2 + int mdct_permutation; +#define FF_MDCT_PERM_NONE 0 +#define FF_MDCT_PERM_INTERLEAVE 1 +}; + +#if CONFIG_HARDCODED_TABLES +#define COSTABLE_CONST const +#else +#define COSTABLE_CONST +#endif + +#define COSTABLE(size) \ + COSTABLE_CONST DECLARE_ALIGNED(32, FFTSample, FFT_NAME(ff_cos_##size))[size/2] + +extern COSTABLE(16); +extern COSTABLE(32); +extern COSTABLE(64); +extern COSTABLE(128); +extern COSTABLE(256); +extern COSTABLE(512); +extern COSTABLE(1024); +extern COSTABLE(2048); +extern COSTABLE(4096); +extern COSTABLE(8192); +extern COSTABLE(16384); +extern COSTABLE(32768); +extern COSTABLE(65536); +extern COSTABLE_CONST FFTSample* const FFT_NAME(ff_cos_tabs)[17]; + +#define ff_init_ff_cos_tabs FFT_NAME(ff_init_ff_cos_tabs) + +/** + * Initialize the cosine table in ff_cos_tabs[index] + * @param index index in ff_cos_tabs array of the table to initialize + */ +void ff_init_ff_cos_tabs(int index); + +#define ff_fft_init FFT_NAME(ff_fft_init) +#define ff_fft_end FFT_NAME(ff_fft_end) + +/** + * Set up a complex FFT. + * @param nbits log2 of the length of the input array + * @param inverse if 0 perform the forward transform, if 1 perform the inverse + */ +int ff_fft_init(FFTContext *s, int nbits, int inverse); + +#if CONFIG_FFT_FLOAT +void ff_fft_init_altivec(FFTContext *s); +void ff_fft_init_mmx(FFTContext *s); +void ff_fft_init_arm(FFTContext *s); +#else +void ff_fft_fixed_init_arm(FFTContext *s); +#endif + +void ff_fft_end(FFTContext *s); + +#define ff_mdct_init FFT_NAME(ff_mdct_init) +#define ff_mdct_end FFT_NAME(ff_mdct_end) + +int ff_mdct_init(FFTContext *s, int nbits, int inverse, double scale); +void ff_mdct_end(FFTContext *s); + +#endif /* AVCODEC_FFT_H */ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/fft-internal.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/fft-internal.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/fft-internal.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/fft-internal.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_FFT_INTERNAL_H +#define AVCODEC_FFT_INTERNAL_H + +#if CONFIG_FFT_FLOAT + +#define FIX15(v) (v) +#define sqrthalf (float)M_SQRT1_2 + +#define BF(x, y, a, b) do { \ + x = a - b; \ + y = a + b; \ + } while (0) + +#define CMUL(dre, dim, are, aim, bre, bim) do { \ + (dre) = (are) * (bre) - (aim) * (bim); \ + (dim) = (are) * (bim) + (aim) * (bre); \ + } while (0) + +#else + +#include "libavutil/intmath.h" +#include "mathops.h" + +void ff_mdct_calcw_c(FFTContext *s, FFTDouble *output, const FFTSample *input); + +#define SCALE_FLOAT(a, bits) lrint((a) * (double)(1 << (bits))) +#define FIX15(a) av_clip(SCALE_FLOAT(a, 15), -32767, 32767) + +#define sqrthalf ((int16_t)((1<<15)*M_SQRT1_2)) + +#define BF(x, y, a, b) do { \ + x = (a - b) >> 1; \ + y = (a + b) >> 1; \ + } while (0) + +#define CMULS(dre, dim, are, aim, bre, bim, sh) do { \ + (dre) = (MUL16(are, bre) - MUL16(aim, bim)) >> sh; \ + (dim) = (MUL16(are, bim) + MUL16(aim, bre)) >> sh; \ + } while (0) + +#define CMUL(dre, dim, are, aim, bre, bim) \ + CMULS(dre, dim, are, aim, bre, bim, 15) + +#define CMULL(dre, dim, are, aim, bre, bim) \ + CMULS(dre, dim, are, aim, bre, bim, 0) + +#endif /* CONFIG_FFT_FLOAT */ + +#define ff_imdct_calc_c FFT_NAME(ff_imdct_calc_c) +#define ff_imdct_half_c FFT_NAME(ff_imdct_half_c) +#define ff_mdct_calc_c FFT_NAME(ff_mdct_calc_c) + +void ff_imdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_mdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input); + +#endif /* AVCODEC_FFT_INTERNAL_H */ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/FileStream.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/FileStream.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/FileStream.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/FileStream.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,66 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BinkFileStream_h_ +#define _BinkFileStream_h_ + +#include +#include +#include +#include + +namespace BinkCommon { + +class FileStream +{ + public: + + bool Open(const std::string &fileName); + bool Is_Open(); + void Close(); + + int32_t ReadBytes(uint8_t *data, uint32_t nBytes); + + uint32_t ReadUint32LE(); + uint32_t ReadUint32BE(); + + uint16_t ReadUint16LE(); + uint16_t ReadUint16BE(); + + uint8_t ReadByte(); + + enum SeekDirection{ + kSeekCurrent = 0, + kSeekStart = 1, + kSeekEnd = 2 + }; + + bool Seek(int32_t offset, SeekDirection = kSeekStart); + bool Skip(int32_t offset); + + int32_t GetPosition(); + bool Is_Eos(); + + private: + std::ifstream file; +}; + +} // close namespace BinkCommon + +#endif diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/HuffmanVLC.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/HuffmanVLC.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/HuffmanVLC.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/HuffmanVLC.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BinkHuffmanVLC_h_ +#define _BinkHuffmanVLC_h_ + +#include +#include "BitReader.h" +#include + +namespace BinkCommon { + +struct VLC +{ + uint8_t symbol; + uint8_t code; +}; + +typedef std::vector > VLCtable; + +uint8_t VLC_GetCodeBits (BinkCommon::BitReader &bits, VLCtable &table); +void VLC_InitTable (VLCtable &table, uint32_t maxLength, uint32_t size, const uint8_t *lengths, const uint8_t *bits); +uint32_t VLC_GetSize (VLCtable &table); + +} // close namespace BinkCommon + +#endif diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/LogError.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/LogError.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/LogError.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/LogError.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BinkLogError_h_ +#define _BinkLogError_h_ + +#include + +namespace BinkCommon { + +void LogError(const std::string &error); + +} // close namespace BinkCommon + +#endif diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/rdft.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/rdft.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/rdft.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/rdft.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,80 @@ +/* + * This file has been modified from its original release by Barry Duncan to comment out an include for header 'config.h' which + * is part of the FFmpeg project. This file is not available in this project and has therefore been unreferenced. This file is + * identical to the original FFmpeg release otherwise. + */ + +/* + * (I)RDFT transforms + * Copyright (c) 2009 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_RDFT_H +#define AVCODEC_RDFT_H + +//#include "config.h" +#include "fft.h" + +#if CONFIG_HARDCODED_TABLES +# define SINTABLE_CONST const +#else +# define SINTABLE_CONST +#endif + +#define SINTABLE(size) \ + SINTABLE_CONST DECLARE_ALIGNED(16, FFTSample, ff_sin_##size)[size/2] + +extern SINTABLE(16); +extern SINTABLE(32); +extern SINTABLE(64); +extern SINTABLE(128); +extern SINTABLE(256); +extern SINTABLE(512); +extern SINTABLE(1024); +extern SINTABLE(2048); +extern SINTABLE(4096); +extern SINTABLE(8192); +extern SINTABLE(16384); +extern SINTABLE(32768); +extern SINTABLE(65536); + +struct RDFTContext { + int nbits; + int inverse; + int sign_convention; + + /* pre/post rotation tables */ + const FFTSample *tcos; + SINTABLE_CONST FFTSample *tsin; + FFTContext fft; + void (*rdft_calc)(struct RDFTContext *s, FFTSample *z); +}; + +/** + * Set up a real FFT. + * @param nbits log2 of the length of the input array + * @param trans the type of transform + */ +int ff_rdft_init(RDFTContext *s, int nbits, enum RDFTransformType trans); +void ff_rdft_end(RDFTContext *s); + +void ff_rdft_init_arm(RDFTContext *s); + + +#endif /* AVCODEC_RDFT_H */ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/Util.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/Util.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/include/Util.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/include/Util.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,27 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BinkUtil_h_ +#define _BinkUtil_h_ + +#include // DG: apparently memcpy(), memset() etc are used in several files including this one + +const int av_log2_c(unsigned int v); + +#endif diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/avfft.c rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/avfft.c --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/avfft.c 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/avfft.c 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,158 @@ +/* + * This file has been modified from its original release by Barry Duncan to comment out header a header include for + * 'libavutil/mem.h' which is part of FFmpeg but is not present in this project. This code has also been modified to include + * 'stdlib.h' to provide similar functionality in its place. All uses of the function 'av_malloc' from FFmpeg have been replaced + * with a standard 'malloc' function call. All uses of the function 'av_freep' from FFmpeg have been replaced with a standard 'free' + * function call. This file is otherwise identical to the FFmpeg original. + */ + +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +//#include "libavutil/mem.h" +#include "avfft.h" +#include "fft.h" +#include "rdft.h" +#include "dct.h" +#include + +/* FFT */ + +FFTContext *av_fft_init(int nbits, int inverse) +{ + FFTContext *s = (FFTContext*)malloc(sizeof(*s)); + + if (s && ff_fft_init(s, nbits, inverse)) { + free(s); + s = 0; + } + + return s; +} + +void av_fft_permute(FFTContext *s, FFTComplex *z) +{ + s->fft_permute(s, z); +} + +void av_fft_calc(FFTContext *s, FFTComplex *z) +{ + s->fft_calc(s, z); +} + +void av_fft_end(FFTContext *s) +{ + if (s) { + ff_fft_end(s); + free(s); + } +} + +#if CONFIG_MDCT + +FFTContext *av_mdct_init(int nbits, int inverse, double scale) +{ + FFTContext *s = (FFTContext*)malloc(sizeof(*s)); + + if (s && ff_mdct_init(s, nbits, inverse, scale)) { + free(s); + s = 0; + } + + return s; +} + +void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + s->imdct_calc(s, output, input); +} + +void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + s->imdct_half(s, output, input); +} + +void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + s->mdct_calc(s, output, input); +} + +void av_mdct_end(FFTContext *s) +{ + if (s) { + ff_mdct_end(s); + free(s); + s = 0; + } +} + +#endif /* CONFIG_MDCT */ + +#if CONFIG_RDFT + +RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans) +{ + RDFTContext *s = av_malloc(sizeof(*s)); + + if (s && ff_rdft_init(s, nbits, trans)) + av_freep(&s); + + return s; +} + +void av_rdft_calc(RDFTContext *s, FFTSample *data) +{ + s->rdft_calc(s, data); +} + +void av_rdft_end(RDFTContext *s) +{ + if (s) { + ff_rdft_end(s); + av_free(s); + } +} + +#endif /* CONFIG_RDFT */ + +#if CONFIG_DCT + +DCTContext *av_dct_init(int nbits, enum DCTTransformType inverse) +{ + DCTContext *s = av_malloc(sizeof(*s)); + + if (s && ff_dct_init(s, nbits, inverse)) + av_freep(&s); + + return s; +} + +void av_dct_calc(DCTContext *s, FFTSample *data) +{ + s->dct_calc(s, data); +} + +void av_dct_end(DCTContext *s) +{ + if (s) { + ff_dct_end(s); + av_free(s); + } +} + +#endif /* CONFIG_DCT */ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/BinkAudio.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/BinkAudio.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/BinkAudio.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/BinkAudio.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,379 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This code is based on the Bink decoder from the FFmpeg project which can be obtained from http://www.ffmpeg.org/ + * below is the license from FFmpeg + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Bink video decoder + * Copyright (c) 2009 Konstantin Shishkov + * Copyright (C) 2011 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "BinkDecoder.h" +#include "BinkAudio.h" +#include "Util.h" +#include // DG: for std::min/max + +const int kAudio16Bits = 0x4000; +const int kAudioStereo = 0x2000; +const int kAudioUseDCT = 0x1000; + +const int kNumBands = 25; + +/** + * Clip a signed integer value into the -32768,32767 range. + * @param a value to clip + * @return clipped value + */ +static /*av_always_inline*/ const int16_t av_clip_int16_c(int a) +{ + if ((a+0x8000) & ~0xFFFF) return (a>>31) ^ 0x7FFF; + else return a; +} + +static /*av_always_inline*/ int float_to_int16_one(const float *src){ + return av_clip_int16_c((int)(*src)); +} + +// from fmtconvert.c +static void float_to_int16_interleave_c(int16_t *dst, const float **src, long len, int channels) +{ + if (channels==2) + { + for (int i = 0; i < len; i++) + { + dst[2*i] = float_to_int16_one(src[0] + i); + dst[2*i+1] = float_to_int16_one(src[1] + i); + } + } + else + { + for (int c = 0; c < channels; c++) + { + for (int i = 0, j = c; i < len; i++, j += channels) + dst[j] = float_to_int16_one(src[c] + i); + } + } +} + +float BinkDecoder::GetAudioFloat(BinkCommon::BitReader &bits) +{ + int power = bits.GetBits(5); + float f = ldexpf((float)bits.GetBits(23), power - 23); + if (bits.GetBit()) + f = -f; + + return f; +} + +bool BinkDecoder::CreateAudioTrack(uint32_t sampleRate, uint16_t flags) +{ + AudioTrack *track = new AudioTrack; + + // determine frame length + uint32_t frameLenBits, nChannels; + + if (sampleRate < 22050) { + frameLenBits = 9; + } + else if (sampleRate < 44100) { + frameLenBits = 10; + } + else { + frameLenBits = 11; + } + + // check nunber of channels + if (flags & kAudioStereo) { + nChannels = 2; + } + else { + nChannels = 1; + } + + track->nChannelsReal = nChannels; + + if (flags & kAudioUseDCT) + { + track->transformType = kTransformTypeDCT; + } + else + { + track->transformType = kTransformTypeRDFT; + + // audio is already interleaved for the RDFT format variant + sampleRate *= nChannels; + frameLenBits += av_log2_c(nChannels); + nChannels = 1; + } + + int frameLength = 1 << frameLenBits; + int overlapLength = frameLength / 16; + int blockSize = (frameLength - overlapLength) * nChannels; + + int sampleRateHalf = (sampleRate + 1) / 2; + float root = 2.0f / sqrt((float)frameLength); + + uint32_t nBands = 0; + + // calculate number of bands + for (nBands = 1; nBands < kNumBands; nBands++) + { + if (sampleRateHalf <= criticalFrequencies[nBands - 1]) + break; + } + + track->bands.resize(nBands + 1); + + // populate bands data + track->bands[0] = 2; + + for (uint32_t i = 1; i < nBands; i++) + { + track->bands[i] = (criticalFrequencies[i - 1] * frameLength / sampleRateHalf) & ~1; + } + + track->bands[nBands] = frameLength; + + // initialise coefficients pointer array + for (uint32_t i = 0; i < nChannels; i++) + { + track->coeffsPtr[i] = track->coeffs + i * frameLength; + } + + if (kTransformTypeRDFT == track->transformType) + ff_rdft_init(&track->trans.rdft, frameLenBits, DFT_C2R); + else if (kTransformTypeDCT == track->transformType) + ff_dct_init(&track->trans.dct, frameLenBits, DCT_III); + else + return false; + + track->blockBufferSize = frameLength * nChannels * sizeof(int16_t); + track->blockBuffer = new int16_t[track->blockBufferSize]; + + track->blockSize = blockSize; + track->frameLenBits = frameLenBits; + track->frameLength = frameLength; + track->nBands = nBands; + track->nChannels = nChannels; + track->overlapLength = overlapLength; + track->root = root; + track->sampleRate = sampleRate; + track->sampleRateHalf = sampleRateHalf; + track->first = true; + + // should contain entire frames worth of audio when frame is decoded + track->bufferSize = 0; + track->buffer = 0; + track->bytesReadThisFrame = 0; + + // add the track to the track vector + audioTracks.push_back(track); + + return true; +} + +void BinkDecoder::AudioPacket(uint32_t trackIndex, uint32_t packetSize) +{ + // create a temp bit reader for this packet + BinkCommon::BitReader bits(file, packetSize); + + AudioTrack *track = audioTracks[trackIndex]; + + uint8_t *bufferPtr = track->buffer; + + // each call to DecodeAudioBlock should produce this many bytes + uint32_t bytesDone = track->blockSize * 2; + + while (bits.GetPosition() < bits.GetSize()) + { + DecodeAudioBlock(trackIndex, bits); + + memcpy(bufferPtr, track->blockBuffer, std::min(track->bufferSize - track->bytesReadThisFrame, bytesDone)); + bufferPtr += bytesDone; + + track->bytesReadThisFrame += bytesDone; + + // align to a 32 bit boundary + int n = (-(int)bits.GetPosition()) & 31; + if (n) bits.SkipBits(n); + } +} + +void BinkDecoder::DecodeAudioBlock(uint32_t trackIndex, BinkCommon::BitReader &bits) +{ + int i, j, k; + float q, quant[25]; + int width, coeff; + + AudioTrack *track = audioTracks[trackIndex]; + + int16_t *out = track->blockBuffer; + + if (kTransformTypeDCT == track->transformType) + bits.SkipBits(2); + + for (uint32_t ch = 0; ch < track->nChannels; ch++) + { + float *coeffs = track->coeffsPtr[ch]; + + coeffs[0] = GetAudioFloat(bits) * track->root; + coeffs[1] = GetAudioFloat(bits) * track->root; + + for (uint32_t b = 0; b < track->nBands; b++) + { + /* constant is result of 0.066399999/log10(M_E) */ + int value = bits.GetBits(8); + quant[b] = expf(std::min(value, (int)95) * 0.15289164787221953823f) * track->root; + } + + k = 0; + q = quant[0]; + + // parse coefficients + i = 2; + while (i < track->frameLength) + { + if (bits.GetBit()) + { + j = i + RLEentries[bits.GetBits(4)] * 8; + } else { + j = i + 8; + } + + j = std::min(j, track->frameLength); + + width = bits.GetBits(4); + if (width == 0) + { + memset(coeffs + i, 0, (j - i) * sizeof(*coeffs)); + i = j; + while (track->bands[k] < i) + q = quant[k++]; + } + else + { + while (i < j) + { + if (track->bands[k] == i) + q = quant[k++]; + coeff = bits.GetBits(width); + if (coeff) + { + if (bits.GetBit()) + coeffs[i] = -q * coeff; + else + coeffs[i] = q * coeff; + } + else + { + coeffs[i] = 0.0f; + } + i++; + } + } + } + + if (kTransformTypeRDFT == track->transformType) + { + track->trans.rdft.rdft_calc(&track->trans.rdft, coeffs); + } + else if (kTransformTypeDCT == track->transformType) + { + coeffs[0] /= 0.5f; + track->trans.dct.dct_calc(&track->trans.dct, coeffs); + + float mul = track->frameLength; + + // vector_fmul_scalar() + for (int i = 0; i < track->frameLength; i++) + coeffs[i] = coeffs[i] * mul; + } + } + + float_to_int16_interleave_c(out, (const float **)track->coeffsPtr, track->frameLength, track->nChannels); + + if (!track->first) { + int count = track->overlapLength * track->nChannels; + int shift = av_log2_c(count); + for (i = 0; i < count; i++) { + out[i] = (track->previous[i] * (count - i) + out[i] * i) >> shift; + } + } + + memcpy(track->previous, out + track->blockSize, track->overlapLength * track->nChannels * sizeof(*out)); + + track->first = false; +} + +uint32_t BinkDecoder::GetNumAudioTracks() +{ + return audioTracks.size(); +} + +AudioInfo BinkDecoder::GetAudioTrackDetails(uint32_t trackIndex) +{ + AudioInfo info; + AudioTrack *track = audioTracks[trackIndex]; + + info.sampleRate = track->sampleRate; + info.nChannels = track->nChannelsReal; + + // undo sample rate adjustment we do internally for RDFT audio + if (kTransformTypeRDFT == track->transformType) + { + info.sampleRate /= track->nChannelsReal; + } + + // audio buffer size in bytes + info.idealBufferSize = track->bufferSize; + + return info; +} + +uint32_t BinkDecoder::GetAudioData(uint32_t trackIndex, int16_t *audioBuffer) +{ + if (!audioBuffer) + return 0; + + AudioTrack *track = audioTracks[trackIndex]; + + if (track->bytesReadThisFrame) + memcpy(audioBuffer, track->buffer, std::min(track->bufferSize, track->bytesReadThisFrame)); + + return track->bytesReadThisFrame; +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/BinkDecoder.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/BinkDecoder.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/BinkDecoder.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/BinkDecoder.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,420 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This code is based on the Bink decoder from the FFmpeg project which can be obtained from http://www.ffmpeg.org/ + * below is the license from FFmpeg + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Bink video decoder + * Copyright (c) 2009 Konstantin Shishkov + * Copyright (C) 2011 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "BinkDecoder.h" +#include "LogError.h" +#include "FFmpeg_includes.h" + +std::vector classInstances; + +BinkHandle Bink_Open(const char* fileName) +{ + BinkHandle newHandle; + newHandle.isValid = false; + newHandle.instanceIndex = -1; + + BinkDecoder *newDecoder = new BinkDecoder(); + if (!newDecoder->Open(fileName)) + { + delete newDecoder; + return newHandle; + } + + // loaded ok, make handle valid + newHandle.isValid = true; +#if 0 + // find a free slot if available + for (int i = 0; i < classInstances.size(); i++) + { + if (!classInstances[i]) + { + class + } + } +#endif + // add instance to global instance vector + classInstances.push_back(newDecoder); + + // get a handle ID + newHandle.instanceIndex = classInstances.size() - 1; + + return newHandle; +} + +void Bink_Close(BinkHandle &handle) +{ + if (!classInstances.at(handle.instanceIndex)) + { + // invalid handle + return; + } + + // close bink decoder + delete classInstances[handle.instanceIndex]; + classInstances[handle.instanceIndex] = 0; + + handle.instanceIndex = -1; + handle.isValid = false; +} + +uint32_t Bink_GetNumAudioTracks(BinkHandle &handle) +{ + if (handle.instanceIndex == -1) + return 0; + else + return classInstances[handle.instanceIndex]->GetNumAudioTracks(); +} + +AudioInfo Bink_GetAudioTrackDetails(BinkHandle &handle, uint32_t trackIndex) +{ + return classInstances[handle.instanceIndex]->GetAudioTrackDetails(trackIndex); +} + +/* Get a frame's worth of audio data. + * + * 'data' needs to be a pointer to allocated memory that this function will fill. + * You can find the size (in bytes) to make this buffer by calling Bink_GetAudioTrackDetails() + * and checking the 'idealBufferSize' member in the returned AudioInfo struct + */ +uint32_t Bink_GetAudioData(BinkHandle &handle, uint32_t trackIndex, int16_t *data) +{ + return classInstances[handle.instanceIndex]->GetAudioData(trackIndex, data); +} + +uint32_t Bink_GetNumFrames(BinkHandle &handle) +{ + return classInstances[handle.instanceIndex]->GetNumFrames(); +} + +void Bink_GetFrameSize(BinkHandle &handle, uint32_t &width, uint32_t &height) +{ + width = classInstances[handle.instanceIndex]->frameWidth; + height = classInstances[handle.instanceIndex]->frameHeight; +} + +uint32_t Bink_GetCurrentFrameNum(BinkHandle &handle) +{ + return classInstances[handle.instanceIndex]->GetCurrentFrameNum(); +} + +uint32_t Bink_GetNextFrame(BinkHandle &handle, YUVbuffer yuv) +{ + BinkDecoder *decoder = classInstances[handle.instanceIndex]; + + uint32_t frameIndex = decoder->GetCurrentFrameNum(); + + decoder->GetNextFrame(yuv); + + return frameIndex; +} + +float Bink_GetFrameRate(BinkHandle &handle) +{ + return classInstances[handle.instanceIndex]->GetFrameRate(); +} + +void Bink_GotoFrame(BinkHandle &handle, uint32_t frameNum) +{ + classInstances[handle.instanceIndex]->GotoFrame(frameNum); +} + +BinkDecoder::BinkDecoder() +{ + nFrames = 0; + currentFrame = 0; +} + +BinkDecoder::~BinkDecoder() +{ + for (uint32_t i = 0; i < planes.size(); i++) + { + delete[] planes[i].current; + delete[] planes[i].last; + } + + for (uint32_t i = 0; i < audioTracks.size(); i++) + { + delete[] audioTracks[i]->buffer; + delete[] audioTracks[i]->blockBuffer; + + if (kTransformTypeRDFT == audioTracks[i]->transformType) + ff_rdft_end(&audioTracks[i]->trans.rdft); + else if (kTransformTypeDCT == audioTracks[i]->transformType) + ff_dct_end(&audioTracks[i]->trans.dct); + + delete audioTracks[i]; + } +} + +uint32_t BinkDecoder::GetNumFrames() +{ + return nFrames; +} + +uint32_t BinkDecoder::GetCurrentFrameNum() +{ + return currentFrame; +} + +float BinkDecoder::GetFrameRate() +{ + return (float)fpsDividend / (float)fpsDivider; +} + +void BinkDecoder::GotoFrame(uint32_t frameNum) +{ + // seek to the desired frame (just set currentFrame) + currentFrame = frameNum; + + // what else? (memset some stuff?) +} + +bool BinkDecoder::Open(const std::string &fileName) +{ + // open the file (read only) + file.Open(fileName); + if (!file.Is_Open()) + { + BinkCommon::LogError("Can't open file " + fileName); + return false; + } + + // check the file signature + signature = file.ReadUint32BE(); + if ((signature != kBIKfID) + && (signature != kBIKgID) + && (signature != kBIKhID) + && (signature != kBIKiID)) + { + BinkCommon::LogError("Unknown Bink signature"); + return false; + } + + fileSize = file.ReadUint32LE() + 8; + + nFrames = file.ReadUint32LE(); + + if (nFrames > 1000000) + { + BinkCommon::LogError("Invalid header, more than 1000000 frames"); + return false; + } + + largestFrameSize = file.ReadUint32LE(); + if (largestFrameSize > fileSize) + { + BinkCommon::LogError("Largest frame size is greater than file size"); + return false; + } + + // skip some unknown data + file.Skip(4); + + frameWidth = file.ReadUint32LE(); + frameHeight = file.ReadUint32LE(); + fpsDividend = file.ReadUint32LE(); + fpsDivider = file.ReadUint32LE(); + videoFlags = file.ReadUint32LE(); + + nAudioTracks = file.ReadUint32LE(); + + // audio is available + if (nAudioTracks) + { + // skip some useless values (unknown and audio channels) + file.Skip(4 * nAudioTracks); + + for (uint32_t i = 0; i < nAudioTracks; i++) + { + uint16_t sampleRate = file.ReadUint16LE(); + uint16_t flags = file.ReadUint16LE(); + + CreateAudioTrack(sampleRate, flags); + } + + // skip the audio track IDs + file.Skip(4 * nAudioTracks); + } + + // read the video frames + frames.resize(nFrames); + + uint32_t pos, nextPos; + + nextPos = file.ReadUint32LE(); + + for (uint32_t i = 0; i < nFrames; i++) + { + pos = nextPos; + if (i == nFrames - 1) + { + nextPos = fileSize; + frames[i].keyFrame = 0; + } + else + { + nextPos = file.ReadUint32LE(); + frames[i].keyFrame = pos & 1; + } + + pos &= ~1; + nextPos &= ~1; + + frames[i].offset = pos; + frames[i].size = nextPos - pos; + } + + // determine buffer sizes for audio tracks + file.Seek(frames[0].offset); + + for (uint32_t trackIndex = 0; trackIndex < audioTracks.size(); trackIndex++) + { + // check for audio + uint32_t audioPacketSize = file.ReadUint32LE(); + + if (audioPacketSize >= 4) + { + // size in bytes of largest decoded audio + uint32_t reportedSize = file.ReadUint32LE(); + + AudioTrack *track = audioTracks[trackIndex]; + + // size in bytes + track->bufferSize = reportedSize; + track->buffer = new uint8_t[reportedSize]; + + // skip to next audio track (and -4 for reportedSize int we read) + file.Skip(audioPacketSize-4); + } + else + { + file.Skip(audioPacketSize); + } + } + + hasAlpha = videoFlags & kFlagAlpha; + swapPlanes = signature >= kBIKhID; + + InitBundles(); + InitTrees(); + + uint32_t width = frameWidth; + uint32_t height = frameHeight; + + // init plane memory + Plane newPlane; + planes.push_back(newPlane); + + // luma plane + planes.back().Init(width, height); + + // chroma planes + width /= 2; + height /= 2; + + // 1 + planes.push_back(newPlane); + planes.back().Init(width, height); + + // 2 + planes.push_back(newPlane); + planes.back().Init(width, height); + + // alpha plane + if (hasAlpha) + { + width *= 2; + height *= 2; + + planes.push_back(newPlane); + planes.back().Init(width, height); + } + + return true; +} + +void BinkDecoder::GetNextFrame(YUVbuffer yuv) +{ + // seek to fame offset + file.Seek(frames[currentFrame].offset); + uint32_t frameSize = frames[currentFrame].size; + + for (uint32_t trackIndex = 0; trackIndex < audioTracks.size(); trackIndex++) + { + // reset bytes read per frame (we might not get any audio for this frame) + audioTracks[trackIndex]->bytesReadThisFrame = 0; + + // check for audio + uint32_t audioPacketSize = file.ReadUint32LE(); + + frameSize -= 4 + audioPacketSize; + + if (audioPacketSize >= 4) + { + uint32_t nSamples = file.ReadUint32LE(); + + AudioPacket(trackIndex, audioPacketSize-4); + } + else + { + file.Skip(audioPacketSize); + } + } + + // get video packet + VideoPacket(frameSize); + + // set planes data + for (uint32_t i = 0; i < planes.size(); i++) + { + yuv[i].width = planes[i].width; + yuv[i].height = planes[i].height; + yuv[i].pitch = planes[i].pitch; + yuv[i].data = planes[i].last; + } + + // frame done + currentFrame++; +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/BinkVideo.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/BinkVideo.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/BinkVideo.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/BinkVideo.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,1173 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This code is based on the Bink decoder from the FFmpeg project which can be obtained from http://www.ffmpeg.org/ + * below is the license from FFmpeg + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Bink video decoder + * Copyright (c) 2009 Konstantin Shishkov + * Copyright (C) 2011 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "BinkDecoder.h" +#include "Util.h" +#include "LogError.h" +#include "binkdata.h" +#include // DG: for std::min/max + +static const uint8_t bink_rlelens[4] = { 4, 8, 12, 32 }; + +static void bink_idct_add_c(uint8_t *dest, int linesize, int32_t *block); +static void bink_idct_put_c(uint8_t *dest, int linesize, int32_t *block); +static void scale_block_c(const uint8_t src[64], uint8_t *dst, int linesize); + +void BinkDecoder::VideoPacket(uint32_t packetSize) +{ + // create a temp bit reader for this packet + BinkCommon::BitReader bits(file, packetSize); + + DecodeFrame(bits); +} + +/** + * Initialize length length in all bundles. + * + * @param c decoder context + * @param width plane width + * @param bw plane width in 8x8 blocks + */ +void BinkDecoder::InitLengths(int width, int bw) +{ + bundle[BINK_SRC_BLOCK_TYPES].len = av_log2_c((width >> 3) + 511) + 1; + + bundle[BINK_SRC_SUB_BLOCK_TYPES].len = av_log2_c((width >> 4) + 511) + 1; + + bundle[BINK_SRC_COLORS].len = av_log2_c(bw*64 + 511) + 1; + + bundle[BINK_SRC_INTRA_DC].len = + bundle[BINK_SRC_INTER_DC].len = + bundle[BINK_SRC_X_OFF].len = + bundle[BINK_SRC_Y_OFF].len = av_log2_c((width >> 3) + 511) + 1; + + bundle[BINK_SRC_PATTERN].len = av_log2_c((bw << 3) + 511) + 1; + + bundle[BINK_SRC_RUN].len = av_log2_c(bw*48 + 511) + 1; +} + +// Allocate memory for bundles. +void BinkDecoder::InitBundles() +{ + int bw = (frameWidth + 7) >> 3; + int bh = (frameHeight + 7) >> 3; + int blocks = bw * bh; + + for (int i = 0; i < BINK_NB_SRC; i++) + { + bundle[i].data = new uint8_t[blocks * 64]; + bundle[i].data_end = bundle[i].data + blocks * 64; + } +} + +void BinkDecoder::FreeBundles() +{ + for (int i = 0; i < BINK_NB_SRC; i++) + delete[] bundle[i].data; +} + +uint8_t BinkDecoder::GetHuffSymbol(BinkCommon::BitReader &bits, Tree &tree) +{ + return tree.symbols[VLC_GetCodeBits(bits, bink_trees[tree.vlc_num])]; +} + +// as per http://michael.dipperstein.com/huffman/#decode - ".. However I have also read that it is faster to store the +// codes for each symbol in an array sorted by code length and search for a match every time a bit is read in." +void BinkDecoder::InitTrees() +{ + for (uint32_t i = 0; i < kNumTrees; i++) + { + // get max code length + const int maxBits = bink_tree_lens[i][15]; + + VLC_InitTable(bink_trees[i], maxBits, 16, &bink_tree_lens[i][0], &bink_tree_bits[i][0]); + } +} + +/** + * Merge two consequent lists of equal size depending on bits read. + * + * @param gb context for reading bits + * @param dst buffer where merged list will be written to + * @param src pointer to the head of the first list (the second lists starts at src+size) + * @param size input lists size + */ +void BinkDecoder::Merge(BinkCommon::BitReader &bits, uint8_t *dst, uint8_t *src, int size) +{ + uint8_t *src2 = src + size; + int size2 = size; + + do { + if (!bits.GetBit()) { + *dst++ = *src++; + size--; + } else { + *dst++ = *src2++; + size2--; + } + } while (size && size2); + + while (size--) + *dst++ = *src++; + while (size2--) + *dst++ = *src2++; +} + +/** + * Read information about Huffman tree used to decode data. + * + * @param gb context for reading bits + * @param tree pointer for storing tree data + */ +void BinkDecoder::ReadTree(BinkCommon::BitReader &bits, Tree *tree) +{ + uint8_t tmp1[16], tmp2[16], *in = tmp1, *out = tmp2; + int i, t, len; + + tree->vlc_num = bits.GetBits(4); + if (!tree->vlc_num) { + for (i = 0; i < 16; i++) + tree->symbols[i] = i; + return; + } + if (bits.GetBit()) { + len = bits.GetBits(3); + memset(tmp1, 0, sizeof(tmp1)); + for (i = 0; i <= len; i++) { + tree->symbols[i] = bits.GetBits(4); + tmp1[tree->symbols[i]] = 1; + } + for (i = 0; i < 16 && len < 16 - 1; i++) + if (!tmp1[i]) + tree->symbols[++len] = i; + } else { + len = bits.GetBits(2); + for (i = 0; i < 16; i++) + in[i] = i; + for (i = 0; i <= len; i++) { + int size = 1 << i; + for (t = 0; t < 16; t += size << 1) + Merge(bits, out + t, in + t, size); + std::swap(in, out); + } + memcpy(tree->symbols, in, 16); + } +} + +/** + * Prepare bundle for decoding data. + * + * @param gb context for reading bits + * @param c decoder context + * @param bundle_num number of the bundle to initialize + */ +void BinkDecoder::ReadBundle(BinkCommon::BitReader &bits, int bundle_num) +{ + if (bundle_num == BINK_SRC_COLORS) { + for (int i = 0; i < 16; i++) + ReadTree(bits, &col_high[i]); + col_lastval = 0; + } + if (bundle_num != BINK_SRC_INTRA_DC && bundle_num != BINK_SRC_INTER_DC) + ReadTree(bits, &bundle[bundle_num].tree); + bundle[bundle_num].cur_dec = + bundle[bundle_num].cur_ptr = bundle[bundle_num].data; +} + +/** + * common check before starting decoding bundle data + * + * @param gb context for reading bits + * @param b bundle + * @param t variable where number of elements to decode will be stored + */ + +int CheckReadVal(BinkCommon::BitReader &bits, Bundle *b, int &t) +{ + if (!b->cur_dec || (b->cur_dec > b->cur_ptr)) + return 0; + + t = bits.GetBits(b->len); + + if (!t) { + b->cur_dec = NULL; + return 0; + } + + return 1; +} + +int BinkDecoder::ReadRuns(BinkCommon::BitReader &bits, Bundle *b) +{ + int t, v; + const uint8_t *dec_end; + + if (CheckReadVal(bits, b, t) == 0) + { + return 0; + } + + dec_end = b->cur_dec + t; + if (dec_end > b->data_end) { + BinkCommon::LogError("Run value went out of bounds"); + return -1; + } + if (bits.GetBit()) { + v = bits.GetBits(4); + memset(b->cur_dec, v, t); + b->cur_dec += t; + } else { + while (b->cur_dec < dec_end) + *b->cur_dec++ = GetHuffSymbol(bits, b->tree); + } + return 0; +} + +int BinkDecoder::ReadMotionValues(BinkCommon::BitReader &bits, Bundle *b) +{ + int t, sign, v; + const uint8_t *dec_end; + + if (CheckReadVal(bits, b, t) == 0) + { + return 0; + } + + dec_end = b->cur_dec + t; + if (dec_end > b->data_end) { + BinkCommon::LogError("Too many motion values"); + return -1; + } + if (bits.GetBit()) { + v = bits.GetBits(4); + if (v) { + sign = -(int)bits.GetBit(); + v = (v ^ sign) - sign; + } + memset(b->cur_dec, v, t); + b->cur_dec += t; + } else { + while (b->cur_dec < dec_end) { + v = GetHuffSymbol(bits, b->tree); + if (v) { + sign = -(int)bits.GetBit(); + v = (v ^ sign) - sign; + } + *b->cur_dec++ = v; + } + } + return 0; +} + +int BinkDecoder::ReadBlockTypes(BinkCommon::BitReader &bits, Bundle *b) +{ + int t, v; + int last = 0; + const uint8_t *dec_end; + + if (CheckReadVal(bits, b, t) == 0) + { + return 0; + } + + dec_end = b->cur_dec + t; + if (dec_end > b->data_end) { + BinkCommon::LogError("Too many block type values"); + return -1; + } + if (bits.GetBit()) { + v = bits.GetBits(4); + memset(b->cur_dec, v, t); + b->cur_dec += t; + } else { + while (b->cur_dec < dec_end) { + v = GetHuffSymbol(bits, b->tree); + if (v < 12) { + last = v; + *b->cur_dec++ = v; + } else { + int run = bink_rlelens[v - 12]; + + if (dec_end - b->cur_dec < run) + return -1; + + memset(b->cur_dec, last, run); + b->cur_dec += run; + } + } + } + return 0; +} + +int BinkDecoder::ReadPatterns(BinkCommon::BitReader &bits, Bundle *b) +{ + int t, v; + const uint8_t *dec_end; + + if (CheckReadVal(bits, b, t) == 0) + { + return 0; + } + + dec_end = b->cur_dec + t; + if (dec_end > b->data_end) { + BinkCommon::LogError("Too many pattern values"); + return -1; + } + while (b->cur_dec < dec_end) { + v = GetHuffSymbol(bits, b->tree); + v |= GetHuffSymbol(bits, b->tree) << 4; + *b->cur_dec++ = v; + } + + return 0; +} + +int BinkDecoder::ReadColors(BinkCommon::BitReader &bits, Bundle *b) +{ + int t, sign, v; + const uint8_t *dec_end; + + if (CheckReadVal(bits, b, t) == 0) + { + return 0; + } + + dec_end = b->cur_dec + t; + + if (dec_end > b->data_end) { + BinkCommon::LogError("Too many color values"); + return -1; + } + if (bits.GetBit()) + { + col_lastval = GetHuffSymbol(bits, col_high[col_lastval]); + v = GetHuffSymbol(bits, b->tree); + v = (col_lastval << 4) | v; + if (signature < kBIKiID) + { + sign = ((int8_t) v) >> 7; + v = ((v & 0x7F) ^ sign) - sign; + v += 0x80; + } + memset(b->cur_dec, v, t); + b->cur_dec += t; + } + else + { + while (b->cur_dec < dec_end) + { + col_lastval = GetHuffSymbol(bits, col_high[col_lastval]); + v = GetHuffSymbol(bits, b->tree); + v = (col_lastval << 4) | v; + + if (signature < kBIKiID) + { + sign = ((int8_t) v) >> 7; + v = ((v & 0x7F) ^ sign) - sign; + v += 0x80; + } + *b->cur_dec++ = v; + } + } + return 0; +} + +int BinkDecoder::ReadDCs(BinkCommon::BitReader &bits, Bundle *b, int start_bits, int has_sign) +{ + int i, j, len, len2, bsize, sign, v, v2; + int16_t *dst = (int16_t*)b->cur_dec; + int16_t *dst_end = (int16_t*)b->data_end; + + if (CheckReadVal(bits, b, len) == 0) + { + return 0; + } + + v = bits.GetBits(start_bits - has_sign); + if (v && has_sign) { + sign = -(int)bits.GetBit(); + v = (v ^ sign) - sign; + } + + if (dst_end - dst < 1) + return -1; + + *dst++ = v; + len--; + for (i = 0; i < len; i += 8) { + len2 = std::min(len - i, (int)8); + if (dst_end - dst < len2) + return -1; + bsize = bits.GetBits(4); + if (bsize) { + for (j = 0; j < len2; j++) { + v2 = bits.GetBits(bsize); + if (v2) { + sign = -(int)bits.GetBit(); + v2 = (v2 ^ sign) - sign; + } + v += v2; + *dst++ = v; + if (v < -32768 || v > 32767) { + BinkCommon::LogError("DC value went out of bounds" + v); + return -1; + } + } + } else { + for (j = 0; j < len2; j++) + *dst++ = v; + } + } + + b->cur_dec = (uint8_t*)dst; + return 0; +} + +/** + * Retrieve next value from bundle. + * + * @param c decoder context + * @param bundle bundle number + */ +int BinkDecoder::GetValue(int bundle) +{ + // TODO - checkme + int ret; + + if (bundle < BINK_SRC_X_OFF || bundle == BINK_SRC_RUN) + return *this->bundle[bundle].cur_ptr++; + if (bundle == BINK_SRC_X_OFF || bundle == BINK_SRC_Y_OFF) + return (int8_t)*this->bundle[bundle].cur_ptr++; + + ret = *(int16_t*)this->bundle[bundle].cur_ptr; + this->bundle[bundle].cur_ptr += 2; + return ret; +} + +/** + * Read 8x8 block of DCT coefficients. + * + * @param gb context for reading bits + * @param block place for storing coefficients + * @param scan scan order table + * @param quant_matrices quantization matrices + * @return 0 for success, negative value in other cases + */ +int BinkDecoder::ReadDCTcoeffs(BinkCommon::BitReader &bits, int32_t block[64], const uint8_t *scan, + const int32_t quant_matrices[16][64], int q) +{ + int coef_list[128]; + int mode_list[128]; + int i, t, mask, nBits, ccoef, mode, sign; + int list_start = 64, list_end = 64, list_pos; + int coef_count = 0; + int coef_idx[64]; + int quant_idx; + const int32_t *quant; + + coef_list[list_end] = 4; mode_list[list_end++] = 0; + coef_list[list_end] = 24; mode_list[list_end++] = 0; + coef_list[list_end] = 44; mode_list[list_end++] = 0; + coef_list[list_end] = 1; mode_list[list_end++] = 3; + coef_list[list_end] = 2; mode_list[list_end++] = 3; + coef_list[list_end] = 3; mode_list[list_end++] = 3; + + nBits = bits.GetBits(4) - 1; + + for (mask = 1 << nBits; nBits >= 0; mask >>= 1, nBits--) { + list_pos = list_start; + while (list_pos < list_end) { + if (!(mode_list[list_pos] | coef_list[list_pos]) || !bits.GetBit()) { + list_pos++; + continue; + } + ccoef = coef_list[list_pos]; + mode = mode_list[list_pos]; + switch (mode) { + case 0: + coef_list[list_pos] = ccoef + 4; + mode_list[list_pos] = 1; + case 2: + if (mode == 2) { + coef_list[list_pos] = 0; + mode_list[list_pos++] = 0; + } + for (i = 0; i < 4; i++, ccoef++) { + if (bits.GetBit()) { + coef_list[--list_start] = ccoef; + mode_list[ list_start] = 3; + } else { + if (!nBits) { + t = 1 - (bits.GetBit() << 1); + } else { + t = bits.GetBits(nBits) | mask; + sign = -(int)bits.GetBit(); + t = (t ^ sign) - sign; + } + block[scan[ccoef]] = t; + coef_idx[coef_count++] = ccoef; + } + } + break; + case 1: + mode_list[list_pos] = 2; + for (i = 0; i < 3; i++) { + ccoef += 4; + coef_list[list_end] = ccoef; + mode_list[list_end++] = 2; + } + break; + case 3: + if (!nBits) { + t = 1 - (bits.GetBit() << 1); + } else { + t = bits.GetBits(nBits) | mask; + sign = -(int)bits.GetBit(); + t = (t ^ sign) - sign; + } + block[scan[ccoef]] = t; + coef_idx[coef_count++] = ccoef; + coef_list[list_pos] = 0; + mode_list[list_pos++] = 0; + break; + } + } + } + + if (q == -1) { + quant_idx = bits.GetBits(4); + } else { + quant_idx = q; + } + + quant = quant_matrices[quant_idx]; + + block[0] = (block[0] * quant[0]) >> 11; + for (i = 0; i < coef_count; i++) { + int idx = coef_idx[i]; + block[scan[idx]] = (block[scan[idx]] * quant[idx]) >> 11; + } + + return 0; +} + +/** + * Read 8x8 block with residue after motion compensation. + * + * @param gb context for reading bits + * @param block place to store read data + * @param masks_count number of masks to decode + * @return 0 on success, negative value in other cases + */ +int BinkDecoder::ReadResidue(BinkCommon::BitReader &bits, DCTELEM block[64], int masks_count) +{ + int coef_list[128]; + int mode_list[128]; + int i, sign, mask, ccoef, mode; + int list_start = 64, list_end = 64, list_pos; + int nz_coeff[64]; + int nz_coeff_count = 0; + + coef_list[list_end] = 4; mode_list[list_end++] = 0; + coef_list[list_end] = 24; mode_list[list_end++] = 0; + coef_list[list_end] = 44; mode_list[list_end++] = 0; + coef_list[list_end] = 0; mode_list[list_end++] = 2; + + for (mask = 1 << bits.GetBits(3); mask; mask >>= 1) { + for (i = 0; i < nz_coeff_count; i++) { + if (!bits.GetBit()) + continue; + if (block[nz_coeff[i]] < 0) + block[nz_coeff[i]] -= mask; + else + block[nz_coeff[i]] += mask; + masks_count--; + if (masks_count < 0) + return 0; + } + list_pos = list_start; + while (list_pos < list_end) { + if (!(coef_list[list_pos] | mode_list[list_pos]) || !bits.GetBit()) { + list_pos++; + continue; + } + ccoef = coef_list[list_pos]; + mode = mode_list[list_pos]; + switch (mode) { + case 0: + coef_list[list_pos] = ccoef + 4; + mode_list[list_pos] = 1; + case 2: + if (mode == 2) { + coef_list[list_pos] = 0; + mode_list[list_pos++] = 0; + } + for (i = 0; i < 4; i++, ccoef++) { + if (bits.GetBit()) { + coef_list[--list_start] = ccoef; + mode_list[ list_start] = 3; + } else { + nz_coeff[nz_coeff_count++] = bink_scan[ccoef]; + sign = -(int)bits.GetBit(); + block[bink_scan[ccoef]] = (mask ^ sign) - sign; + masks_count--; + if (masks_count < 0) + return 0; + } + } + break; + case 1: + mode_list[list_pos] = 2; + for (i = 0; i < 3; i++) { + ccoef += 4; + coef_list[list_end] = ccoef; + mode_list[list_end++] = 2; + } + break; + case 3: + nz_coeff[nz_coeff_count++] = bink_scan[ccoef]; + sign = -(int)bits.GetBit(); + block[bink_scan[ccoef]] = (mask ^ sign) - sign; + coef_list[list_pos] = 0; + mode_list[list_pos++] = 0; + masks_count--; + if (masks_count < 0) + return 0; + break; + } + } + } + + return 0; +} + +/** + * Copy 8x8 block from source to destination, where src and dst may be overlapped + */ +void BinkDecoder::PutPixels8x8Overlapped(uint8_t *dst, uint8_t *src, int stride) +{ + uint8_t tmp[64]; + for (int i = 0; i < 8; i++) + memcpy(tmp + i*8, src + i*stride, 8); + for (int i = 0; i < 8; i++) + memcpy(dst + i*stride, tmp + i*8, 8); +} + +// copy size x size block from source to destination +void BinkDecoder::PutPixelsTab(uint8_t *dest, uint8_t *prev, uint32_t pitch, uint32_t size) +{ + for (uint32_t i = 0; i < size; i++) + { + memcpy(dest, prev, size); + + dest += pitch; + prev += pitch; + } +} + +// fill size x size block with value +void BinkDecoder::FillBlockTab(uint8_t *dest, uint32_t value, uint32_t pitch, uint32_t size) +{ + for (uint32_t i = 0; i < size; i++) + { + memset(dest, value, size); + dest += pitch; + } +} + +void BinkDecoder::AddPixels8(uint8_t *dest, DCTELEM *block, uint32_t stride) +{ + for (int i = 0; i < 8; i++) + { + for (int j = 0; j < 8; j++) + { + dest[j] += block[j]; + } + + dest += stride; + block += 8; + } +} + +void BinkDecoder::ClearBlock(DCTELEM *block) +{ + memset(block, 0, 64 * sizeof(DCTELEM)); +} + +int BinkDecoder::DecodePlane(BinkCommon::BitReader &bits, int plane_idx, int is_chroma) +{ + int blk; + int bx, by; + uint8_t *dst, *prev, *ref, *ref_start, *ref_end; + int v, col[2]; + const uint8_t *scan; + int xoff, yoff; + + DCTELEM block[64]; + uint8_t ublock[64]; + int32_t dctblock[64]; + int coordmap[64]; + + int bw = is_chroma ? (frameWidth + 15) >> 4 : (frameWidth + 7) >> 3; + int bh = is_chroma ? (frameHeight + 15) >> 4 : (frameHeight + 7) >> 3; + int width = planes[plane_idx].width; + int height = planes[plane_idx].height; + int stride = planes[plane_idx].pitch; + + InitLengths(std::max(width, (int)8), bw); + + for (int i = 0; i < BINK_NB_SRC; i++) + ReadBundle(bits, i); + + + ref_start = planes[plane_idx].last ? planes[plane_idx].last + : planes[plane_idx].current; + + ref_end = ref_start + (bw - 1 + planes[plane_idx].pitch * (bh - 1)) * 8; + + for (int i = 0; i < 64; i++) + coordmap[i] = (i & 7) + (i >> 3) * stride; + + for (by = 0; by < bh; by++) + { + if (ReadBlockTypes(bits, &bundle[BINK_SRC_BLOCK_TYPES]) < 0) + return -1; + if (ReadBlockTypes(bits, &bundle[BINK_SRC_SUB_BLOCK_TYPES]) < 0) + return -1; + if (ReadColors(bits, &bundle[BINK_SRC_COLORS]) < 0) + return -1; + if (ReadPatterns(bits, &bundle[BINK_SRC_PATTERN]) < 0) + return -1; + if (ReadMotionValues(bits, &bundle[BINK_SRC_X_OFF]) < 0) + return -1; + if (ReadMotionValues(bits, &bundle[BINK_SRC_Y_OFF]) < 0) + return -1; + if (ReadDCs(bits, &bundle[BINK_SRC_INTRA_DC], kDCstartBits, 0) < 0) + return -1; + if (ReadDCs(bits, &bundle[BINK_SRC_INTER_DC], kDCstartBits, 1) < 0) + return -1; + if (ReadRuns(bits, &bundle[BINK_SRC_RUN]) < 0) + return -1; + + if (by == bh) + break; + + dst = planes[plane_idx].current + 8 * by * planes[plane_idx].pitch; + prev = (planes[plane_idx].last ? planes[plane_idx].last + : planes[plane_idx].current) + 8*by*stride; + + for (bx = 0; bx < bw; bx++, dst += 8, prev += 8) + { + blk = GetValue(BINK_SRC_BLOCK_TYPES); + + // 16x16 block type on odd line means part of the already decoded block, so skip it + if ((by & 1) && blk == SCALED_BLOCK) { + bx++; + dst += 8; + prev += 8; + continue; + } + + switch (blk) + { + case SKIP_BLOCK: + { + PutPixelsTab(dst, prev, stride, 8); + break; + } + case SCALED_BLOCK: + { + // This is 16x16 block which has its own subtype, which corresponds to other block types (range 3-9). Blocks should be decoded in the + // same way and then scaled twice. + blk = GetValue(BINK_SRC_SUB_BLOCK_TYPES); + + switch (blk) + { + case RUN_BLOCK: + { + scan = bink_patterns[bits.GetBits(4)]; + int i = 0; + do { + int run = GetValue(BINK_SRC_RUN) + 1; + + i += run; + if (i > 64) { + BinkCommon::LogError("Run went out of bounds"); + return -1; + } + if (bits.GetBit()) { + v = GetValue(BINK_SRC_COLORS); + for (int j = 0; j < run; j++) + ublock[*scan++] = v; + } else { + for (int j = 0; j < run; j++) + ublock[*scan++] = GetValue(BINK_SRC_COLORS); + } + } while (i < 63); + if (i == 63) + ublock[*scan++] = GetValue(BINK_SRC_COLORS); + break; + } + case INTRA_BLOCK: + { + memset(dctblock, 0, sizeof(*dctblock) * 64); + dctblock[0] = GetValue(BINK_SRC_INTRA_DC); + ReadDCTcoeffs(bits, dctblock, bink_scan, bink_intra_quant, -1); + bink_idct_put_c(ublock, 8, dctblock); + break; + } + case FILL_BLOCK: + { + v = GetValue(BINK_SRC_COLORS); + + FillBlockTab(dst, v, stride, 16); + break; + } + case PATTERN_BLOCK: + { + for (int i = 0; i < 2; i++) + col[i] = GetValue(BINK_SRC_COLORS); + + for (int j = 0; j < 8; j++) { + v = GetValue(BINK_SRC_PATTERN); + for (int k = 0; k < 8; k++, v >>= 1) + ublock[k + j*8] = col[v & 1]; + } + break; + } + case RAW_BLOCK: + { + for (int j = 0; j < 8; j++) + for (int i = 0; i < 8; i++) + ublock[i + j*8] = GetValue(BINK_SRC_COLORS); + break; + } + default: + BinkCommon::LogError("Incorrect 16x16 block type"); + return -1; + } + + if (blk != FILL_BLOCK) + { + scale_block_c(ublock, dst, stride); + } + bx++; + dst += 8; + prev += 8; + break; + } + case MOTION_BLOCK: + { + // Copy 8x8 block from previous frame with some offset (x and y values decoded at the beginning of the block) + xoff = GetValue(BINK_SRC_X_OFF); + yoff = GetValue(BINK_SRC_Y_OFF); + + ref = prev + xoff + yoff * stride; + if (ref < ref_start || ref > ref_end) { + BinkCommon::LogError("MOTION_BLOCK - Copy out of bounds"); + return -1; + } + + PutPixelsTab(dst, ref, stride, 8); + break; + } + case RUN_BLOCK: + { + scan = bink_patterns[bits.GetBits(4)]; + int i = 0; + do { + int run = GetValue(BINK_SRC_RUN) + 1; + + i += run; + if (i > 64) { + BinkCommon::LogError("Run went out of bounds"); + return -1; + } + if (bits.GetBit()) { + v = GetValue(BINK_SRC_COLORS); + for (int j = 0; j < run; j++) + dst[coordmap[*scan++]] = v; + } else { + for (int j = 0; j < run; j++) + dst[coordmap[*scan++]] = GetValue(BINK_SRC_COLORS); + } + } while (i < 63); + if (i == 63) + dst[coordmap[*scan++]] = GetValue(BINK_SRC_COLORS); + break; + } + case RESIDUE_BLOCK: + { + // motion and residue + xoff = GetValue(BINK_SRC_X_OFF); + yoff = GetValue(BINK_SRC_Y_OFF); + + ref = prev + xoff + yoff * stride; + if (ref < ref_start || ref > ref_end) { + BinkCommon::LogError("Copy out of bounds"); + return -1; + } + + PutPixelsTab(dst, ref, stride, 8); + + ClearBlock(block); + + // number of masks to decode + v = bits.GetBits(7); + ReadResidue(bits, block, v); + + AddPixels8(dst, block, stride); + break; + } + case INTRA_BLOCK: + { + memset(dctblock, 0, sizeof(*dctblock) * 64); + dctblock[0] = GetValue(BINK_SRC_INTRA_DC); + ReadDCTcoeffs(bits, dctblock, bink_scan, bink_intra_quant, -1); + bink_idct_put_c(dst, stride, dctblock); + break; + } + case FILL_BLOCK: + { + // Fill 8x8 block with one value from Colors + v = GetValue(BINK_SRC_COLORS); + + FillBlockTab(dst, v, stride, 8); + break; + } + case INTER_BLOCK: + { + xoff = GetValue(BINK_SRC_X_OFF); + yoff = GetValue(BINK_SRC_Y_OFF); + + ref = prev + xoff + yoff * stride; + if (ref < ref_start || ref > ref_end) { + BinkCommon::LogError("Copy out of bounds"); + return -1; + } + + PutPixelsTab(dst, ref, stride, 8); + + memset(dctblock, 0, sizeof(*dctblock) * 64); + dctblock[0] = GetValue(BINK_SRC_INTER_DC); + + ReadDCTcoeffs(bits, dctblock, bink_scan, bink_inter_quant, -1); + + bink_idct_add_c(dst, stride, dctblock); + break; + } + case PATTERN_BLOCK: + { + // Fill block with two colours taken from Colors values using 8 values from Patterns + for (int i = 0; i < 2; i++) + col[i] = GetValue(BINK_SRC_COLORS); + + for (int i = 0; i < 8; i++) { + v = GetValue(BINK_SRC_PATTERN); + for (int j = 0; j < 8; j++, v >>= 1) + dst[i*stride + j] = col[v & 1]; + } + break; + } + case RAW_BLOCK: + { + for (int i = 0; i < 8; i++) + memcpy(dst + i*stride, bundle[BINK_SRC_COLORS].cur_ptr + i*8, 8); + bundle[BINK_SRC_COLORS].cur_ptr += 64; + break; + } + default: + { + BinkCommon::LogError("Unknown block type"); + return -1; + } + } + } + } + + if (bits.GetPosition() & 0x1F) //next plane data starts at 32-bit boundary + bits.SkipBits(32 - (bits.GetPosition() & 0x1F)); + + return 0; +} + +int BinkDecoder::DecodeFrame(BinkCommon::BitReader &bits) +{ + if (hasAlpha) { + if (signature >= kBIKiID) + bits.SkipBits(32); // skip alpha plane data size + + if (DecodePlane(bits, 3, 0) < 0) + return -1; + } + + if (signature >= kBIKiID) + bits.SkipBits(32); + + for (int plane = 0; plane < 3; plane++) + { + int plane_idx = (!plane || !swapPlanes) ? plane : (plane ^ 3); + + if (signature > kBIKbID) { + if (DecodePlane(bits, plane_idx, !!plane) < 0) + return -1; + } else { + if (DecodePlane(bits, plane_idx, !!plane) < 0) + return -1; + } + if (bits.GetPosition() >= bits.GetSize()) + break; + } + + if (signature > kBIKbID) + { + for (uint32_t i = 0; i < planes.size(); i++) + planes[i].Swap(); + } + + return 1; +} + +/* + * Bink DSP routines + */ + +#define A1 2896 /* (1/sqrt(2))<<12 */ +#define A2 2217 +#define A3 3784 +#define A4 -5352 + +#define IDCT_TRANSFORM(dest,s0,s1,s2,s3,s4,s5,s6,s7,d0,d1,d2,d3,d4,d5,d6,d7,munge,src) {\ + const int a0 = (src)[s0] + (src)[s4]; \ + const int a1 = (src)[s0] - (src)[s4]; \ + const int a2 = (src)[s2] + (src)[s6]; \ + const int a3 = (A1*((src)[s2] - (src)[s6])) >> 11; \ + const int a4 = (src)[s5] + (src)[s3]; \ + const int a5 = (src)[s5] - (src)[s3]; \ + const int a6 = (src)[s1] + (src)[s7]; \ + const int a7 = (src)[s1] - (src)[s7]; \ + const int b0 = a4 + a6; \ + const int b1 = (A3*(a5 + a7)) >> 11; \ + const int b2 = ((A4*a5) >> 11) - b0 + b1; \ + const int b3 = (A1*(a6 - a4) >> 11) - b2; \ + const int b4 = ((A2*a7) >> 11) + b3 - b1; \ + (dest)[d0] = munge(a0+a2 +b0); \ + (dest)[d1] = munge(a1+a3-a2+b2); \ + (dest)[d2] = munge(a1-a3+a2+b3); \ + (dest)[d3] = munge(a0-a2 -b4); \ + (dest)[d4] = munge(a0-a2 +b4); \ + (dest)[d5] = munge(a1-a3+a2-b3); \ + (dest)[d6] = munge(a1+a3-a2-b2); \ + (dest)[d7] = munge(a0+a2 -b0); \ +} +/* end IDCT_TRANSFORM macro */ + +#define MUNGE_NONE(x) (x) +#define IDCT_COL(dest,src) IDCT_TRANSFORM(dest,0,8,16,24,32,40,48,56,0,8,16,24,32,40,48,56,MUNGE_NONE,src) + +#define MUNGE_ROW(x) (((x) + 0x7F)>>8) +#define IDCT_ROW(dest,src) IDCT_TRANSFORM(dest,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,MUNGE_ROW,src) + +static inline void bink_idct_col(int *dest, const int32_t *src) +{ + if ((src[8]|src[16]|src[24]|src[32]|src[40]|src[48]|src[56])==0) { + dest[0] = + dest[8] = + dest[16] = + dest[24] = + dest[32] = + dest[40] = + dest[48] = + dest[56] = src[0]; + } else { + IDCT_COL(dest, src); + } +} + +static void bink_idct_c(int32_t *block) +{ + int temp[64]; + + for (int i = 0; i < 8; i++) + bink_idct_col(&temp[i], &block[i]); + for (int i = 0; i < 8; i++) { + IDCT_ROW( (&block[8*i]), (&temp[8*i]) ); + } +} + +static void bink_idct_add_c(uint8_t *dest, int linesize, int32_t *block) +{ + bink_idct_c(block); + for (int i = 0; i < 8; i++, dest += linesize, block += 8) + for (int j = 0; j < 8; j++) + dest[j] += block[j]; +} + +static void bink_idct_put_c(uint8_t *dest, int linesize, int32_t *block) +{ + int temp[64]; + for (int i = 0; i < 8; i++) + bink_idct_col(&temp[i], &block[i]); + for (int i = 0; i < 8; i++) { + IDCT_ROW( (&dest[i*linesize]), (&temp[8*i]) ); + } +} + +static void scale_block_c(const uint8_t src[64], uint8_t *dst, int linesize) +{ + int i, j; + uint16_t *dst1 = (uint16_t *) dst; + uint16_t *dst2 = (uint16_t *)(dst + linesize); + + for (j = 0; j < 8; j++) { + for (i = 0; i < 8; i++) { + dst1[i] = dst2[i] = src[i] * 0x0101; + } + src += 8; + dst1 += linesize; + dst2 += linesize; + } +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/BitReader.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/BitReader.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/BitReader.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/BitReader.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,110 @@ +/* + * libbinkdec - decode Bink video and audio + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "BitReader.h" + +namespace BinkCommon { + +BitReader::BitReader(BinkCommon::FileStream &file, uint32_t size) +{ + this->file = &file; + this->totalSize = size; + this->nCachedBits = 0; + this->currentOffset = 0; + this->bytesRead = 0; + + FillCache(); +} + +BitReader::~BitReader() +{ +// file->Skip(totalSize - (currentOffset/8)); +} + +void BitReader::FillCache() +{ + if (bytesRead < totalSize) + { + this->cache = this->file->ReadByte(); + nCachedBits = 8; + bytesRead++; + } + else + { + // TODO: handle this case? + assert(0); + } +} + +uint32_t BitReader::GetSize() +{ + return totalSize * 8; +} + +uint32_t BitReader::GetPosition() +{ + return currentOffset + (8 - nCachedBits); +} + +uint32_t BitReader::GetBit() +{ + if (nCachedBits == 0) + { + FillCache(); + currentOffset += 8; + } + + uint32_t ret = cache & 1; + + cache >>= 1; + nCachedBits--; + + return ret; +} + +uint32_t BitReader::GetBits(uint32_t n) +{ + uint32_t ret = 0; + + int bitsTodo = n; + + uint32_t theShift = 0; + + while (bitsTodo) + { + uint32_t bit = GetBit(); + bit <<= theShift; + + theShift++; + + ret |= bit; + + bitsTodo--; + } + + return ret; +} + +void BitReader::SkipBits(uint32_t n) +{ + GetBits(n); +} + +} // close namespace BinkCommon diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/dct32.c rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/dct32.c --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/dct32.c 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/dct32.c 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,284 @@ +/* + * This file has been modified by Barry Duncan to comment out a header include for 'mathops.h' which is part of FFmpeg + * and not available in this project. 'DCT32_FLOAT' has also been defined as 1. This file is otherwise identical to the + * FFmpeg original + */ + +/* + * Template for the Discrete Cosine Transform for 32 samples + * Copyright (c) 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "dct32.h" +//#include "mathops.h" + +#define DCT32_FLOAT 1 + +#if DCT32_FLOAT +# define dct32 ff_dct32_float +# define FIXHR(x) ((float)(x)) +# define MULH3(x, y, s) ((s)*(y)*(x)) +# define INTFLOAT float +#else +# define dct32 ff_dct32_fixed +# define FIXHR(a) ((int)((a) * (1LL<<32) + 0.5)) +# define MULH3(x, y, s) MULH((s)*(x), y) +# define INTFLOAT int +#endif + + +/* tab[i][j] = 1.0 / (2.0 * cos(pi*(2*k+1) / 2^(6 - j))) */ + +/* cos(i*pi/64) */ + +#define COS0_0 FIXHR(0.50060299823519630134/2) +#define COS0_1 FIXHR(0.50547095989754365998/2) +#define COS0_2 FIXHR(0.51544730992262454697/2) +#define COS0_3 FIXHR(0.53104259108978417447/2) +#define COS0_4 FIXHR(0.55310389603444452782/2) +#define COS0_5 FIXHR(0.58293496820613387367/2) +#define COS0_6 FIXHR(0.62250412303566481615/2) +#define COS0_7 FIXHR(0.67480834145500574602/2) +#define COS0_8 FIXHR(0.74453627100229844977/2) +#define COS0_9 FIXHR(0.83934964541552703873/2) +#define COS0_10 FIXHR(0.97256823786196069369/2) +#define COS0_11 FIXHR(1.16943993343288495515/4) +#define COS0_12 FIXHR(1.48416461631416627724/4) +#define COS0_13 FIXHR(2.05778100995341155085/8) +#define COS0_14 FIXHR(3.40760841846871878570/8) +#define COS0_15 FIXHR(10.19000812354805681150/32) + +#define COS1_0 FIXHR(0.50241928618815570551/2) +#define COS1_1 FIXHR(0.52249861493968888062/2) +#define COS1_2 FIXHR(0.56694403481635770368/2) +#define COS1_3 FIXHR(0.64682178335999012954/2) +#define COS1_4 FIXHR(0.78815462345125022473/2) +#define COS1_5 FIXHR(1.06067768599034747134/4) +#define COS1_6 FIXHR(1.72244709823833392782/4) +#define COS1_7 FIXHR(5.10114861868916385802/16) + +#define COS2_0 FIXHR(0.50979557910415916894/2) +#define COS2_1 FIXHR(0.60134488693504528054/2) +#define COS2_2 FIXHR(0.89997622313641570463/2) +#define COS2_3 FIXHR(2.56291544774150617881/8) + +#define COS3_0 FIXHR(0.54119610014619698439/2) +#define COS3_1 FIXHR(1.30656296487637652785/4) + +#define COS4_0 FIXHR(0.70710678118654752439/2) + +/* butterfly operator */ +#define BF(a, b, c, s)\ +{\ + tmp0 = val##a + val##b;\ + tmp1 = val##a - val##b;\ + val##a = tmp0;\ + val##b = MULH3(tmp1, c, 1<<(s));\ +} + +#define BF0(a, b, c, s)\ +{\ + tmp0 = tab[a] + tab[b];\ + tmp1 = tab[a] - tab[b];\ + val##a = tmp0;\ + val##b = MULH3(tmp1, c, 1<<(s));\ +} + +#define BF1(a, b, c, d)\ +{\ + BF(a, b, COS4_0, 1);\ + BF(c, d,-COS4_0, 1);\ + val##c += val##d;\ +} + +#define BF2(a, b, c, d)\ +{\ + BF(a, b, COS4_0, 1);\ + BF(c, d,-COS4_0, 1);\ + val##c += val##d;\ + val##a += val##c;\ + val##c += val##b;\ + val##b += val##d;\ +} + +#define ADD(a, b) val##a += val##b + +/* DCT32 without 1/sqrt(2) coef zero scaling. */ +void dct32(INTFLOAT *out, const INTFLOAT *tab) +{ + INTFLOAT tmp0, tmp1; + + INTFLOAT val0 , val1 , val2 , val3 , val4 , val5 , val6 , val7 , + val8 , val9 , val10, val11, val12, val13, val14, val15, + val16, val17, val18, val19, val20, val21, val22, val23, + val24, val25, val26, val27, val28, val29, val30, val31; + + /* pass 1 */ + BF0( 0, 31, COS0_0 , 1); + BF0(15, 16, COS0_15, 5); + /* pass 2 */ + BF( 0, 15, COS1_0 , 1); + BF(16, 31,-COS1_0 , 1); + /* pass 1 */ + BF0( 7, 24, COS0_7 , 1); + BF0( 8, 23, COS0_8 , 1); + /* pass 2 */ + BF( 7, 8, COS1_7 , 4); + BF(23, 24,-COS1_7 , 4); + /* pass 3 */ + BF( 0, 7, COS2_0 , 1); + BF( 8, 15,-COS2_0 , 1); + BF(16, 23, COS2_0 , 1); + BF(24, 31,-COS2_0 , 1); + /* pass 1 */ + BF0( 3, 28, COS0_3 , 1); + BF0(12, 19, COS0_12, 2); + /* pass 2 */ + BF( 3, 12, COS1_3 , 1); + BF(19, 28,-COS1_3 , 1); + /* pass 1 */ + BF0( 4, 27, COS0_4 , 1); + BF0(11, 20, COS0_11, 2); + /* pass 2 */ + BF( 4, 11, COS1_4 , 1); + BF(20, 27,-COS1_4 , 1); + /* pass 3 */ + BF( 3, 4, COS2_3 , 3); + BF(11, 12,-COS2_3 , 3); + BF(19, 20, COS2_3 , 3); + BF(27, 28,-COS2_3 , 3); + /* pass 4 */ + BF( 0, 3, COS3_0 , 1); + BF( 4, 7,-COS3_0 , 1); + BF( 8, 11, COS3_0 , 1); + BF(12, 15,-COS3_0 , 1); + BF(16, 19, COS3_0 , 1); + BF(20, 23,-COS3_0 , 1); + BF(24, 27, COS3_0 , 1); + BF(28, 31,-COS3_0 , 1); + + + + /* pass 1 */ + BF0( 1, 30, COS0_1 , 1); + BF0(14, 17, COS0_14, 3); + /* pass 2 */ + BF( 1, 14, COS1_1 , 1); + BF(17, 30,-COS1_1 , 1); + /* pass 1 */ + BF0( 6, 25, COS0_6 , 1); + BF0( 9, 22, COS0_9 , 1); + /* pass 2 */ + BF( 6, 9, COS1_6 , 2); + BF(22, 25,-COS1_6 , 2); + /* pass 3 */ + BF( 1, 6, COS2_1 , 1); + BF( 9, 14,-COS2_1 , 1); + BF(17, 22, COS2_1 , 1); + BF(25, 30,-COS2_1 , 1); + + /* pass 1 */ + BF0( 2, 29, COS0_2 , 1); + BF0(13, 18, COS0_13, 3); + /* pass 2 */ + BF( 2, 13, COS1_2 , 1); + BF(18, 29,-COS1_2 , 1); + /* pass 1 */ + BF0( 5, 26, COS0_5 , 1); + BF0(10, 21, COS0_10, 1); + /* pass 2 */ + BF( 5, 10, COS1_5 , 2); + BF(21, 26,-COS1_5 , 2); + /* pass 3 */ + BF( 2, 5, COS2_2 , 1); + BF(10, 13,-COS2_2 , 1); + BF(18, 21, COS2_2 , 1); + BF(26, 29,-COS2_2 , 1); + /* pass 4 */ + BF( 1, 2, COS3_1 , 2); + BF( 5, 6,-COS3_1 , 2); + BF( 9, 10, COS3_1 , 2); + BF(13, 14,-COS3_1 , 2); + BF(17, 18, COS3_1 , 2); + BF(21, 22,-COS3_1 , 2); + BF(25, 26, COS3_1 , 2); + BF(29, 30,-COS3_1 , 2); + + /* pass 5 */ + BF1( 0, 1, 2, 3); + BF2( 4, 5, 6, 7); + BF1( 8, 9, 10, 11); + BF2(12, 13, 14, 15); + BF1(16, 17, 18, 19); + BF2(20, 21, 22, 23); + BF1(24, 25, 26, 27); + BF2(28, 29, 30, 31); + + /* pass 6 */ + + ADD( 8, 12); + ADD(12, 10); + ADD(10, 14); + ADD(14, 9); + ADD( 9, 13); + ADD(13, 11); + ADD(11, 15); + + out[ 0] = val0; + out[16] = val1; + out[ 8] = val2; + out[24] = val3; + out[ 4] = val4; + out[20] = val5; + out[12] = val6; + out[28] = val7; + out[ 2] = val8; + out[18] = val9; + out[10] = val10; + out[26] = val11; + out[ 6] = val12; + out[22] = val13; + out[14] = val14; + out[30] = val15; + + ADD(24, 28); + ADD(28, 26); + ADD(26, 30); + ADD(30, 25); + ADD(25, 29); + ADD(29, 27); + ADD(27, 31); + + out[ 1] = val16 + val24; + out[17] = val17 + val25; + out[ 9] = val18 + val26; + out[25] = val19 + val27; + out[ 5] = val20 + val28; + out[21] = val21 + val29; + out[13] = val22 + val30; + out[29] = val23 + val31; + out[ 3] = val24 + val20; + out[19] = val25 + val21; + out[11] = val26 + val22; + out[27] = val27 + val23; + out[ 7] = val28 + val18; + out[23] = val29 + val19; + out[15] = val30 + val17; + out[31] = val31; +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/dct.c rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/dct.c --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/dct.c 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/dct.c 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,236 @@ +/* + * This file has been modified from its original release by Barry Duncan to comment out an include for header + * 'libavutil/mathematics.h' which is part of the FFmpeg project. This file is not available in this project + * and has therefore been unreferenced. Two includes for 'string.h' and 'stdlib.h' have been added to provide + * the functionality that was available from this FFmpeg header. All uses of the function 'av_malloc' from FFmpeg have been replaced + * with a standard 'malloc' function call. All uses of the function 'av_freep' from FFmpeg have been replaced with a standard 'free' + * function call. The line which checks 'HAVE_MMX' has been commented out. Fixed some warnings for conversion from double to float for + * some constant numbers by adding 'f' (eg 0.05 to 0.5f). + * This file is otherwise identical to the FFmpeg original. + */ + +/* + * (I)DCT Transforms + * Copyright (c) 2009 Peter Ross + * Copyright (c) 2010 Alex Converse + * Copyright (c) 2010 Vitor Sessak + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * (Inverse) Discrete Cosine Transforms. These are also known as the + * type II and type III DCTs respectively. + */ + +#include +#include +#include +//#include "libavutil/mathematics.h" +#include "dct.h" +#include "dct32.h" + +/* sin((M_PI * x / (2*n)) */ +#define SIN(s,n,x) (s->costab[(n) - (x)]) + +/* cos((M_PI * x / (2*n)) */ +#define COS(s,n,x) (s->costab[x]) + +static void ff_dst_calc_I_c(DCTContext *ctx, FFTSample *data) +{ + int n = 1 << ctx->nbits; + int i; + + data[0] = 0; + for(i = 1; i < n/2; i++) { + float tmp1 = data[i ]; + float tmp2 = data[n - i]; + float s = SIN(ctx, n, 2*i); + + s *= tmp1 + tmp2; + tmp1 = (tmp1 - tmp2) * 0.5f; + data[i ] = s + tmp1; + data[n - i] = s - tmp1; + } + + data[n/2] *= 2; + ctx->rdft.rdft_calc(&ctx->rdft, data); + + data[0] *= 0.5f; + + for(i = 1; i < n-2; i += 2) { + data[i + 1] += data[i - 1]; + data[i ] = -data[i + 2]; + } + + data[n-1] = 0; +} + +static void ff_dct_calc_I_c(DCTContext *ctx, FFTSample *data) +{ + int n = 1 << ctx->nbits; + int i; + float next = -0.5f * (data[0] - data[n]); + + for(i = 0; i < n/2; i++) { + float tmp1 = data[i ]; + float tmp2 = data[n - i]; + float s = SIN(ctx, n, 2*i); + float c = COS(ctx, n, 2*i); + + c *= tmp1 - tmp2; + s *= tmp1 - tmp2; + + next += c; + + tmp1 = (tmp1 + tmp2) * 0.5f; + data[i ] = tmp1 - s; + data[n - i] = tmp1 + s; + } + + ctx->rdft.rdft_calc(&ctx->rdft, data); + data[n] = data[1]; + data[1] = next; + + for(i = 3; i <= n; i += 2) + data[i] = data[i - 2] - data[i]; +} + +static void ff_dct_calc_III_c(DCTContext *ctx, FFTSample *data) +{ + int n = 1 << ctx->nbits; + int i; + + float next = data[n - 1]; + float inv_n = 1.0f / n; + + for (i = n - 2; i >= 2; i -= 2) { + float val1 = data[i ]; + float val2 = data[i - 1] - data[i + 1]; + float c = COS(ctx, n, i); + float s = SIN(ctx, n, i); + + data[i ] = c * val1 + s * val2; + data[i + 1] = s * val1 - c * val2; + } + + data[1] = 2 * next; + + ctx->rdft.rdft_calc(&ctx->rdft, data); + + for (i = 0; i < n / 2; i++) { + float tmp1 = data[i ] * inv_n; + float tmp2 = data[n - i - 1] * inv_n; + float csc = ctx->csc2[i] * (tmp1 - tmp2); + + tmp1 += tmp2; + data[i ] = tmp1 + csc; + data[n - i - 1] = tmp1 - csc; + } +} + +static void ff_dct_calc_II_c(DCTContext *ctx, FFTSample *data) +{ + int n = 1 << ctx->nbits; + int i; + float next; + + for (i=0; i < n/2; i++) { + float tmp1 = data[i ]; + float tmp2 = data[n - i - 1]; + float s = SIN(ctx, n, 2*i + 1); + + s *= tmp1 - tmp2; + tmp1 = (tmp1 + tmp2) * 0.5f; + + data[i ] = tmp1 + s; + data[n-i-1] = tmp1 - s; + } + + ctx->rdft.rdft_calc(&ctx->rdft, data); + + next = data[1] * 0.5f; + data[1] *= -1; + + for (i = n - 2; i >= 0; i -= 2) { + float inr = data[i ]; + float ini = data[i + 1]; + float c = COS(ctx, n, i); + float s = SIN(ctx, n, i); + + data[i ] = c * inr + s * ini; + + data[i+1] = next; + + next += s * inr - c * ini; + } +} + +static void dct32_func(DCTContext *ctx, FFTSample *data) +{ + ctx->dct32(data, data); +} + +av_cold int ff_dct_init(DCTContext *s, int nbits, enum DCTTransformType inverse) +{ + int n = 1 << nbits; + int i; + + memset(s, 0, sizeof(*s)); + + s->nbits = nbits; + s->inverse = inverse; + + if (inverse == DCT_II && nbits == 5) { + s->dct_calc = dct32_func; + } else { + ff_init_ff_cos_tabs(nbits+2); + + s->costab = ff_cos_tabs[nbits+2]; + + s->csc2 = (FFTSample*)malloc(n/2 * sizeof(FFTSample)); + + if (ff_rdft_init(&s->rdft, nbits, inverse == DCT_III) < 0) { + free(s->csc2); + s->csc2 = 0; + return -1; + } + + for (i = 0; i < n/2; i++) + s->csc2[i] = 0.5f / sin((M_PI / (2*n) * (2*i + 1))); + + switch(inverse) { + case DCT_I : s->dct_calc = ff_dct_calc_I_c; break; + case DCT_II : s->dct_calc = ff_dct_calc_II_c ; break; + case DCT_III: s->dct_calc = ff_dct_calc_III_c; break; + case DST_I : s->dct_calc = ff_dst_calc_I_c; break; + } + } + + s->dct32 = ff_dct32_float; +// if (HAVE_MMX) ff_dct_init_mmx(s); + + return 0; +} + +av_cold void ff_dct_end(DCTContext *s) +{ + ff_rdft_end(&s->rdft); + free(s->csc2); + s->csc2 = 0; +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/fft.c rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/fft.c --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/fft.c 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/fft.c 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,368 @@ +/* + * This file has been modified from its original release by Barry Duncan to comment out an include for header + * 'libavutil/mathematics.h' which is part of the FFmpeg project. This file is not available in this project + * and has therefore been unreferenced. All uses of the function 'av_malloc' from FFmpeg have been replaced + * with a standard 'malloc' function call. All uses of the function 'av_freep' from FFmpeg have been replaced + * with a standard 'free' function call. Three lines where 'ARCH_ARM', 'HAVE_ALTIVEC' and 'HAVE_MMX' have + * been commented out. A usage of 'av_cold' has also been commented out. This file is otherwise identical to the + * FFmpeg original. + */ + +/* + * FFT/IFFT transforms + * Copyright (c) 2008 Loren Merritt + * Copyright (c) 2002 Fabrice Bellard + * Partly based on libdjbfft by D. J. Bernstein + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * FFT/IFFT transforms. + */ + +#include +#include +//#include "libavutil/mathematics.h" +#include "fft.h" +#include "fft-internal.h" + +/* cos(2*pi*x/n) for 0<=x<=n/4, followed by its reverse */ +#if !CONFIG_HARDCODED_TABLES +COSTABLE(16); +COSTABLE(32); +COSTABLE(64); +COSTABLE(128); +COSTABLE(256); +COSTABLE(512); +COSTABLE(1024); +COSTABLE(2048); +COSTABLE(4096); +COSTABLE(8192); +COSTABLE(16384); +COSTABLE(32768); +COSTABLE(65536); +#endif +COSTABLE_CONST FFTSample * const FFT_NAME(ff_cos_tabs)[] = { + NULL, NULL, NULL, NULL, + FFT_NAME(ff_cos_16), + FFT_NAME(ff_cos_32), + FFT_NAME(ff_cos_64), + FFT_NAME(ff_cos_128), + FFT_NAME(ff_cos_256), + FFT_NAME(ff_cos_512), + FFT_NAME(ff_cos_1024), + FFT_NAME(ff_cos_2048), + FFT_NAME(ff_cos_4096), + FFT_NAME(ff_cos_8192), + FFT_NAME(ff_cos_16384), + FFT_NAME(ff_cos_32768), + FFT_NAME(ff_cos_65536), +}; + +static void ff_fft_permute_c(FFTContext *s, FFTComplex *z); +static void ff_fft_calc_c(FFTContext *s, FFTComplex *z); + +static int split_radix_permutation(int i, int n, int inverse) +{ + int m; + if(n <= 2) return i&1; + m = n >> 1; + if(!(i&m)) return split_radix_permutation(i, m, inverse)*2; + m >>= 1; + if(inverse == !(i&m)) return split_radix_permutation(i, m, inverse)*4 + 1; + else return split_radix_permutation(i, m, inverse)*4 - 1; +} + +av_cold void ff_init_ff_cos_tabs(int index) +{ +#if !CONFIG_HARDCODED_TABLES + int i; + int m = 1<= 16; + else if (i < n/2) + return is_second_half_of_fft32(i, n/2); + else if (i < 3*n/4) + return is_second_half_of_fft32(i - n/2, n/4); + else + return is_second_half_of_fft32(i - 3*n/4, n/4); +} + +static av_cold void fft_perm_avx(FFTContext *s) +{ + int i; + int n = 1 << s->nbits; + + for (i = 0; i < n; i += 16) { + int k; + if (is_second_half_of_fft32(i, n)) { + for (k = 0; k < 16; k++) + s->revtab[-split_radix_permutation(i + k, n, s->inverse) & (n - 1)] = + i + avx_tab[k]; + + } else { + for (k = 0; k < 16; k++) { + int j = i + k; + j = (j & ~7) | ((j >> 1) & 3) | ((j << 2) & 4); + s->revtab[-split_radix_permutation(i + k, n, s->inverse) & (n - 1)] = j; + } + } + } +} + +av_cold int ff_fft_init(FFTContext *s, int nbits, int inverse) +{ + int i, j, n; + + if (nbits < 2 || nbits > 16) + goto fail; + s->nbits = nbits; + n = 1 << nbits; + + s->revtab = (uint16_t*)malloc(n * sizeof(uint16_t)); + if (!s->revtab) + goto fail; + s->tmp_buf = (FFTComplex*)malloc(n * sizeof(FFTComplex)); + if (!s->tmp_buf) + goto fail; + s->inverse = inverse; + s->fft_permutation = FF_FFT_PERM_DEFAULT; + + s->fft_permute = ff_fft_permute_c; + s->fft_calc = ff_fft_calc_c; +#if CONFIG_MDCT + s->imdct_calc = ff_imdct_calc_c; + s->imdct_half = ff_imdct_half_c; + s->mdct_calc = ff_mdct_calc_c; +#endif + +#if CONFIG_FFT_FLOAT + +// if (ARCH_ARM) ff_fft_init_arm(s); +// if (HAVE_ALTIVEC) ff_fft_init_altivec(s); +// if (HAVE_MMX) ff_fft_init_mmx(s); + if (CONFIG_MDCT) s->mdct_calcw = s->mdct_calc; +#else + if (CONFIG_MDCT) s->mdct_calcw = ff_mdct_calcw_c; + if (ARCH_ARM) ff_fft_fixed_init_arm(s); +#endif + + for(j=4; j<=nbits; j++) { + ff_init_ff_cos_tabs(j); + } + + if (s->fft_permutation == FF_FFT_PERM_AVX) { + fft_perm_avx(s); + } else { + for(i=0; ifft_permutation == FF_FFT_PERM_SWAP_LSBS) + j = (j&~3) | ((j>>1)&1) | ((j<<1)&2); + s->revtab[-split_radix_permutation(i, n, s->inverse) & (n-1)] = j; + } + } + + return 0; + fail: + free(s->revtab); + s->revtab = 0; + free(s->tmp_buf); + s->tmp_buf = 0; + return -1; +} + +static void ff_fft_permute_c(FFTContext *s, FFTComplex *z) +{ + int j, np; + const uint16_t *revtab = s->revtab; + np = 1 << s->nbits; + /* TODO: handle split-radix permute in a more optimal way, probably in-place */ + for(j=0;jtmp_buf[revtab[j]] = z[j]; + memcpy(z, s->tmp_buf, np * sizeof(FFTComplex)); +} + +/*av_cold*/ void ff_fft_end(FFTContext *s) +{ + free(s->revtab); + s->revtab = 0; + free(s->tmp_buf); + s->tmp_buf = 0; +} + +#define BUTTERFLIES(a0,a1,a2,a3) {\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, a0.re, t5);\ + BF(a3.im, a1.im, a1.im, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, a1.re, t4);\ + BF(a2.im, a0.im, a0.im, t6);\ +} + +// force loading all the inputs before storing any. +// this is slightly slower for small data, but avoids store->load aliasing +// for addresses separated by large powers of 2. +#define BUTTERFLIES_BIG(a0,a1,a2,a3) {\ + FFTSample r0=a0.re, i0=a0.im, r1=a1.re, i1=a1.im;\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, r0, t5);\ + BF(a3.im, a1.im, i1, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, r1, t4);\ + BF(a2.im, a0.im, i0, t6);\ +} + +#define TRANSFORM(a0,a1,a2,a3,wre,wim) {\ + CMUL(t1, t2, a2.re, a2.im, wre, -wim);\ + CMUL(t5, t6, a3.re, a3.im, wre, wim);\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +#define TRANSFORM_ZERO(a0,a1,a2,a3) {\ + t1 = a2.re;\ + t2 = a2.im;\ + t5 = a3.re;\ + t6 = a3.im;\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +/* z[0...8n-1], w[1...2n-1] */ +#define PASS(name)\ +static void name(FFTComplex *z, const FFTSample *wre, unsigned int n)\ +{\ + FFTDouble t1, t2, t3, t4, t5, t6;\ + int o1 = 2*n;\ + int o2 = 4*n;\ + int o3 = 6*n;\ + const FFTSample *wim = wre+o1;\ + n--;\ +\ + TRANSFORM_ZERO(z[0],z[o1],z[o2],z[o3]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + do {\ + z += 2;\ + wre += 2;\ + wim -= 2;\ + TRANSFORM(z[0],z[o1],z[o2],z[o3],wre[0],wim[0]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + } while(--n);\ +} + +PASS(pass) +#undef BUTTERFLIES +#define BUTTERFLIES BUTTERFLIES_BIG +PASS(pass_big) + +#define DECL_FFT(n,n2,n4)\ +static void fft##n(FFTComplex *z)\ +{\ + fft##n2(z);\ + fft##n4(z+n4*2);\ + fft##n4(z+n4*3);\ + pass(z,FFT_NAME(ff_cos_##n),n4/2);\ +} + +static void fft4(FFTComplex *z) +{ + FFTDouble t1, t2, t3, t4, t5, t6, t7, t8; + + BF(t3, t1, z[0].re, z[1].re); + BF(t8, t6, z[3].re, z[2].re); + BF(z[2].re, z[0].re, t1, t6); + BF(t4, t2, z[0].im, z[1].im); + BF(t7, t5, z[2].im, z[3].im); + BF(z[3].im, z[1].im, t4, t8); + BF(z[3].re, z[1].re, t3, t7); + BF(z[2].im, z[0].im, t2, t5); +} + +static void fft8(FFTComplex *z) +{ + FFTDouble t1, t2, t3, t4, t5, t6; + + fft4(z); + + BF(t1, z[5].re, z[4].re, -z[5].re); + BF(t2, z[5].im, z[4].im, -z[5].im); + BF(t5, z[7].re, z[6].re, -z[7].re); + BF(t6, z[7].im, z[6].im, -z[7].im); + + BUTTERFLIES(z[0],z[2],z[4],z[6]); + TRANSFORM(z[1],z[3],z[5],z[7],sqrthalf,sqrthalf); +} + +#if !CONFIG_SMALL +static void fft16(FFTComplex *z) +{ + FFTDouble t1, t2, t3, t4, t5, t6; + FFTSample cos_16_1 = FFT_NAME(ff_cos_16)[1]; + FFTSample cos_16_3 = FFT_NAME(ff_cos_16)[3]; + + fft8(z); + fft4(z+8); + fft4(z+12); + + TRANSFORM_ZERO(z[0],z[4],z[8],z[12]); + TRANSFORM(z[2],z[6],z[10],z[14],sqrthalf,sqrthalf); + TRANSFORM(z[1],z[5],z[9],z[13],cos_16_1,cos_16_3); + TRANSFORM(z[3],z[7],z[11],z[15],cos_16_3,cos_16_1); +} +#else +DECL_FFT(16,8,4) +#endif +DECL_FFT(32,16,8) +DECL_FFT(64,32,16) +DECL_FFT(128,64,32) +DECL_FFT(256,128,64) +DECL_FFT(512,256,128) +#if !CONFIG_SMALL +#define pass pass_big +#endif +DECL_FFT(1024,512,256) +DECL_FFT(2048,1024,512) +DECL_FFT(4096,2048,1024) +DECL_FFT(8192,4096,2048) +DECL_FFT(16384,8192,4096) +DECL_FFT(32768,16384,8192) +DECL_FFT(65536,32768,16384) + +static void (* const fft_dispatch[])(FFTComplex*) = { + fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024, + fft2048, fft4096, fft8192, fft16384, fft32768, fft65536, +}; + +static void ff_fft_calc_c(FFTContext *s, FFTComplex *z) +{ + fft_dispatch[s->nbits-2](z); +} + diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/FileStream.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/FileStream.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/FileStream.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/FileStream.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,148 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "FileStream.h" +#include + +namespace BinkCommon { + +bool FileStream::Open(const std::string &fileName) +{ + file.open(fileName.c_str(), std::ifstream::in | std::ifstream::binary); + if (!file.is_open()) + { + // log error + return false; + } + + return true; +} + +bool FileStream::Is_Open() +{ + return file.is_open(); +} + +void FileStream::Close() +{ + file.close(); +} + +int32_t FileStream::ReadBytes(uint8_t *data, uint32_t nBytes) +{ + file.read(reinterpret_cast(data), nBytes); + + if (file.eof()) { + return 0; + } + else if (file.fail()) { + return 0; + } + else if (file.bad()) { + return 0; + } + + return static_cast(file.gcount()); +} + +uint32_t FileStream::ReadUint32LE() +{ + uint32_t value; + file.read(reinterpret_cast(&value), 4); + return value; +} + +uint32_t FileStream::ReadUint32BE() +{ + uint32_t value; + file.read(reinterpret_cast(&value), 4); +#ifdef _MSC_VER + return _byteswap_ulong(value); +#else // DG: provide alternative for GCC/clang + return __builtin_bswap32(value); +#endif +} + +uint16_t FileStream::ReadUint16LE() +{ + uint16_t value; + file.read(reinterpret_cast(&value), 2); + return value; +} + +uint16_t FileStream::ReadUint16BE() +{ + uint16_t value; + file.read(reinterpret_cast(&value), 2); +#ifdef _MSC_VER + return _byteswap_ushort(value); +#else // DG: provide alternative for GCC/clang + return __builtin_bswap16(value); +#endif +} + +uint8_t FileStream::ReadByte() +{ + uint8_t value; + file.read(reinterpret_cast(&value), 1); + return value; +} + +bool FileStream::Seek(int32_t offset, SeekDirection direction) +{ + if (kSeekStart == direction) { + file.seekg(offset, std::ios::beg); + } + else if (kSeekCurrent == direction) { + file.seekg(offset, std::ios::cur); + } + + // TODO - end seek + + if (file.bad()) + { + // todo + return false; + } + if (file.fail()) + { + // todo + return false; + } + + return true; +} + +bool FileStream::Skip(int32_t offset) +{ + return Seek(offset, kSeekCurrent); +} + +bool FileStream::Is_Eos() +{ + return file.eof(); +} + +int32_t FileStream::GetPosition() +{ + return static_cast(file.tellg()); +} + +} // close namespace BinkCommon + diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/HuffmanVLC.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/HuffmanVLC.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/HuffmanVLC.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/HuffmanVLC.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,71 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +namespace BinkCommon { + +uint8_t VLC_GetCodeBits(BitReader &bits, VLCtable &table) +{ + uint8_t codeBits = 0; + + // search each length array + for (uint32_t i = 0; i < table.size(); i++) + { + // get and add a new bit to codeBits + uint8_t theBit = bits.GetBit() << i; + codeBits |= theBit; + + // search for a code match + for (uint32_t j = 0; j < table[i].size(); j++) + { + if (codeBits == table[i][j].code) + { + return table[i][j].symbol; + } + } + } + + // shouldn't get here.. + return 0; +} + +void VLC_InitTable(VLCtable &table, uint32_t maxLength, uint32_t size, const uint8_t *lengths, const uint8_t *bits) +{ + table.resize(maxLength); + + for (uint32_t i = 0; i < size; i++) + { + VLC newCode; + newCode.symbol = i; + newCode.code = bits[i]; + + uint8_t codeLength = lengths[i]; + + // add the code to the array corresponding to the length + table[codeLength - 1].push_back(newCode); + } +} + +uint32_t VLC_GetSize(VLCtable &table) +{ + return table.size(); +} + +} // close namespace BinkCommon diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/LogError.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/LogError.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/LogError.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/LogError.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,31 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "LogError.h" + +namespace BinkCommon { + +static std::string LastError; + +void LogError(const std::string &error) +{ + LastError = error; +} + +} // close namespace BinkCommon diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/mdct.c rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/mdct.c --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/mdct.c 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/mdct.c 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,213 @@ +/* + * This file has been modified from its original release by Barry Duncan to comment out includes for headers + * 'libavutil/mathematics.h' and 'libavutil/common.h' which are part of the FFmpeg project. These files are + * not available in this project and have therefore been unreferenced. All uses of the function 'av_malloc' from FFmpeg have been replaced + * with a standard 'malloc' function call. All uses of the function 'av_freep' from FFmpeg have been replaced with a standard 'free' + * function call. This file is otherwise identical to the FFmpeg original. + */ + +/* + * MDCT/IMDCT transforms + * Copyright (c) 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +//#include "libavutil/common.h" +//#include "libavutil/mathematics.h" +#include "fft.h" +#include "fft-internal.h" + +/** + * @file + * MDCT/IMDCT transforms. + */ + +#if CONFIG_FFT_FLOAT +# define RSCALE(x) (x) +#else +# define RSCALE(x) ((x) >> 1) +#endif + +/** + * init MDCT or IMDCT computation. + */ +av_cold int ff_mdct_init(FFTContext *s, int nbits, int inverse, double scale) +{ + int n, n4, i; + double alpha, theta; + int tstep; + + memset(s, 0, sizeof(*s)); + n = 1 << nbits; + s->mdct_bits = nbits; + s->mdct_size = n; + n4 = n >> 2; + s->mdct_permutation = FF_MDCT_PERM_NONE; + + if (ff_fft_init(s, s->mdct_bits - 2, inverse) < 0) + goto fail; + + s->tcos = (FFTSample*)malloc(n/2 * sizeof(FFTSample)); + + if (!s->tcos) + goto fail; + + switch (s->mdct_permutation) { + case FF_MDCT_PERM_NONE: + s->tsin = s->tcos + n4; + tstep = 1; + break; + case FF_MDCT_PERM_INTERLEAVE: + s->tsin = s->tcos + 1; + tstep = 2; + break; + default: + goto fail; + } + + theta = 1.0 / 8.0 + (scale < 0 ? n4 : 0); + scale = sqrt(fabs(scale)); + for(i=0;itcos[i*tstep] = FIX15(-cos(alpha) * scale); + s->tsin[i*tstep] = FIX15(-sin(alpha) * scale); + } + return 0; + fail: + ff_mdct_end(s); + return -1; +} + +/** + * Compute the middle half of the inverse MDCT of size N = 2^nbits, + * thus excluding the parts that can be derived by symmetry + * @param output N/2 samples + * @param input N/2 samples + */ +void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + int k, n8, n4, n2, n, j; + const uint16_t *revtab = s->revtab; + const FFTSample *tcos = s->tcos; + const FFTSample *tsin = s->tsin; + const FFTSample *in1, *in2; + FFTComplex *z = (FFTComplex *)output; + + n = 1 << s->mdct_bits; + n2 = n >> 1; + n4 = n >> 2; + n8 = n >> 3; + + /* pre rotation */ + in1 = input; + in2 = input + n2 - 1; + for(k = 0; k < n4; k++) { + j=revtab[k]; + CMUL(z[j].re, z[j].im, *in2, *in1, tcos[k], tsin[k]); + in1 += 2; + in2 -= 2; + } + s->fft_calc(s, z); + + /* post rotation + reordering */ + for(k = 0; k < n8; k++) { + FFTSample r0, i0, r1, i1; + CMUL(r0, i1, z[n8-k-1].im, z[n8-k-1].re, tsin[n8-k-1], tcos[n8-k-1]); + CMUL(r1, i0, z[n8+k ].im, z[n8+k ].re, tsin[n8+k ], tcos[n8+k ]); + z[n8-k-1].re = r0; + z[n8-k-1].im = i0; + z[n8+k ].re = r1; + z[n8+k ].im = i1; + } +} + +/** + * Compute inverse MDCT of size N = 2^nbits + * @param output N samples + * @param input N/2 samples + */ +void ff_imdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + int k; + int n = 1 << s->mdct_bits; + int n2 = n >> 1; + int n4 = n >> 2; + + ff_imdct_half_c(s, output+n4, input); + + for(k = 0; k < n4; k++) { + output[k] = -output[n2-k-1]; + output[n-k-1] = output[n2+k]; + } +} + +/** + * Compute MDCT of size N = 2^nbits + * @param input N samples + * @param out N/2 samples + */ +void ff_mdct_calc_c(FFTContext *s, FFTSample *out, const FFTSample *input) +{ + int i, j, n, n8, n4, n2, n3; + FFTDouble re, im; + const uint16_t *revtab = s->revtab; + const FFTSample *tcos = s->tcos; + const FFTSample *tsin = s->tsin; + FFTComplex *x = (FFTComplex *)out; + + n = 1 << s->mdct_bits; + n2 = n >> 1; + n4 = n >> 2; + n8 = n >> 3; + n3 = 3 * n4; + + /* pre rotation */ + for(i=0;ifft_calc(s, x); + + /* post rotation */ + for(i=0;itcos); + s->tcos = 0; + ff_fft_end(s); +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/rdft.c rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/rdft.c --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/rdft.c 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/rdft.c 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * This file has been modified from its original release by Barry Duncan to comment out an include for header + * 'libavutil/mathematics.h' which is part of the FFmpeg project. This file is not available in this project + * and has therefore been unreferenced. The line which checks 'HAVE_MMX' has been commented out. + * This file is otherwise identical to the FFmpeg original. + */ + +/* + * (I)RDFT transforms + * Copyright (c) 2009 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +//#include "libavutil/mathematics.h" +#include "rdft.h" + +/** + * @file + * (Inverse) Real Discrete Fourier Transforms. + */ + +/* sin(2*pi*x/n) for 0<=xnbits; + const float k1 = 0.5f; + const float k2 = 0.5f - s->inverse; + const FFTSample *tcos = s->tcos; + const FFTSample *tsin = s->tsin; + + if (!s->inverse) { + s->fft.fft_permute(&s->fft, (FFTComplex*)data); + s->fft.fft_calc(&s->fft, (FFTComplex*)data); + } + /* i=0 is a special case because of packing, the DC term is real, so we + are going to throw the N/2 term (also real) in with it. */ + ev.re = data[0]; + data[0] = ev.re+data[1]; + data[1] = ev.re-data[1]; + for (i = 1; i < (n>>2); i++) { + i1 = 2*i; + i2 = n-i1; + /* Separate even and odd FFTs */ + ev.re = k1*(data[i1 ]+data[i2 ]); + od.im = -k2*(data[i1 ]-data[i2 ]); + ev.im = k1*(data[i1+1]-data[i2+1]); + od.re = k2*(data[i1+1]+data[i2+1]); + /* Apply twiddle factors to the odd FFT and add to the even FFT */ + data[i1 ] = ev.re + od.re*tcos[i] - od.im*tsin[i]; + data[i1+1] = ev.im + od.im*tcos[i] + od.re*tsin[i]; + data[i2 ] = ev.re - od.re*tcos[i] + od.im*tsin[i]; + data[i2+1] = -ev.im + od.im*tcos[i] + od.re*tsin[i]; + } + data[2*i+1]=s->sign_convention*data[2*i+1]; + if (s->inverse) { + data[0] *= k1; + data[1] *= k1; + s->fft.fft_permute(&s->fft, (FFTComplex*)data); + s->fft.fft_calc(&s->fft, (FFTComplex*)data); + } +} + +av_cold int ff_rdft_init(RDFTContext *s, int nbits, enum RDFTransformType trans) +{ + int n = 1 << nbits; + int i; + const double theta = (trans == DFT_R2C || trans == DFT_C2R ? -1 : 1)*2*M_PI/n; + + s->nbits = nbits; + s->inverse = trans == IDFT_C2R || trans == DFT_C2R; + s->sign_convention = trans == IDFT_R2C || trans == DFT_C2R ? 1 : -1; + + if (nbits < 4 || nbits > 16) + return -1; + + if (ff_fft_init(&s->fft, nbits-1, trans == IDFT_C2R || trans == IDFT_R2C) < 0) + return -1; + + ff_init_ff_cos_tabs(nbits); + s->tcos = ff_cos_tabs[nbits]; + s->tsin = ff_sin_tabs[nbits]+(trans == DFT_R2C || trans == DFT_C2R)*(n>>2); +#if !CONFIG_HARDCODED_TABLES + for (i = 0; i < (n>>2); i++) { + s->tsin[i] = sin(i*theta); + } +#endif + s->rdft_calc = ff_rdft_calc_c; + +// if (ARCH_ARM) ff_rdft_init_arm(s); + + return 0; +} + +av_cold void ff_rdft_end(RDFTContext *s) +{ + ff_fft_end(&s->fft); +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/Util.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/Util.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/src/Util.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/src/Util.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * libbinkdec - Bink video decoder + * Copyright (C) 2011 Barry Duncan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This code is based on the Bink decoder from the FFmpeg project which can be obtained from http://www.ffmpeg.org/ + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "Util.h" +#include + +// from FFmpeg - mathematics.c +const uint8_t ff_log2_tab[256]={ + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; + +// from FFmpeg - common.h +/*static av_always_inline av_const*/const int av_log2_c(unsigned int v) +{ + int n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/win32/binkdec.def rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/win32/binkdec.def --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/win32/binkdec.def 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/win32/binkdec.def 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,15 @@ +LIBRARY +EXPORTS + +; functions +Bink_Open +Bink_Close +Bink_GetNumAudioTracks +Bink_GetAudioTrackDetails +Bink_GetAudioData +Bink_GetNumFrames +Bink_GetCurrentFrameNum +Bink_GetNextFrame +Bink_GetFrameSize +Bink_GetFrameRate +Bink_GotoFrame \ No newline at end of file diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/win32/VS2010/binkdec_dynamic.sln rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/win32/VS2010/binkdec_dynamic.sln --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/win32/VS2010/binkdec_dynamic.sln 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/win32/VS2010/binkdec_dynamic.sln 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual C++ Express 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "binkdec_dynamic", "binkdec_dynamic.vcxproj", "{E92ED1F6-64A1-43CF-BD8A-4D6B68CB7EEC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E92ED1F6-64A1-43CF-BD8A-4D6B68CB7EEC}.Debug|Win32.ActiveCfg = Debug|Win32 + {E92ED1F6-64A1-43CF-BD8A-4D6B68CB7EEC}.Debug|Win32.Build.0 = Debug|Win32 + {E92ED1F6-64A1-43CF-BD8A-4D6B68CB7EEC}.Release|Win32.ActiveCfg = Release|Win32 + {E92ED1F6-64A1-43CF-BD8A-4D6B68CB7EEC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/win32/VS2010/binkdec_dynamic.vcxproj rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/win32/VS2010/binkdec_dynamic.vcxproj --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/libs/libbinkdec/win32/VS2010/binkdec_dynamic.vcxproj 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/libs/libbinkdec/win32/VS2010/binkdec_dynamic.vcxproj 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,120 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {E92ED1F6-64A1-43CF-BD8A-4D6B68CB7EEC} + binkdec_dynamic + + + + DynamicLibrary + true + MultiByte + + + DynamicLibrary + false + true + MultiByte + + + + + + + + + + + + + libbinkdec + C:\BinkW32;$(IncludePath) + C:\BinkW32;$(LibraryPath) + + + libbinkdec + + + + Level3 + Disabled + ../../include + false + true + + + true + ../binkdec.def + %(AdditionalDependencies) + + + + + Level3 + Full + true + true + ../../include + AnySuitable + true + StreamingSIMDExtensions + + + false + true + true + ../binkdec.def + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/BinaryImage.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/BinaryImage.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/BinaryImage.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/BinaryImage.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -39,7 +39,7 @@ ================================================================================================ */ -#include "tr_local.h" +#include "RenderCommon.h" #include "DXT/DXTCodec.h" #include "Color/ColorSpace.h" diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/BufferObject.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/BufferObject.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/BufferObject.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/BufferObject.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -28,7 +28,7 @@ */ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" idCVar r_showBuffers( "r_showBuffers", "0", CVAR_INTEGER, "" ); diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Cinematic.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Cinematic.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Cinematic.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Cinematic.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -39,7 +39,7 @@ #include //} -#include "tr_local.h" +#include "RenderCommon.h" #define CIN_system 1 #define CIN_loop 2 @@ -66,6 +66,17 @@ } #endif +#ifdef USE_BINKDEC +// DG: not sure how to use FFMPEG and BINKDEC at the same time.. it might be useful if someone wants to +// use binkdec for bink and FFMPEG for other formats in custom code so I didn't just rip FFMPEG out +// But right now it's unsupported, if you need this adjust the video loading code etc yourself +#ifdef USE_FFMPEG +#error "Currently, only one of FFMPEG and BINKDEC is supported at a time!" +#endif + +#include +#endif // USE_BINKDEC + class idCinematicLocal : public idCinematic { public: @@ -98,6 +109,19 @@ bool InitFromFFMPEGFile( const char* qpath, bool looping ); void FFMPEGReset(); #endif +#ifdef USE_BINKDEC + BinkHandle binkHandle; + cinData_t ImageForTimeBinkDec( int milliseconds ); + bool InitFromBinkDecFile( const char* qpath, bool looping ); + void BinkDecReset(); + + YUVbuffer yuvBuffer; + int framePos; + int numFrames; + idImage* imgY; + idImage* imgCr; + idImage* imgCb; +#endif idImage* img; bool isRoQ; @@ -400,6 +424,38 @@ hasFrame = false; #endif +#ifdef USE_BINKDEC + binkHandle.isValid = false; + binkHandle.instanceIndex = -1; // whatever this is, it now has a deterministic value + framePos = -1; + numFrames = 0; + + imgY = globalImages->AllocStandaloneImage( "_cinematicY" ); + imgCr = globalImages->AllocStandaloneImage( "_cinematicCr" ); + imgCb = globalImages->AllocStandaloneImage( "_cinematicCb" ); + { + idImageOpts opts; + opts.format = FMT_LUM8; + opts.colorFormat = CFM_DEFAULT; + opts.width = 32; + opts.height = 32; + opts.numLevels = 1; + if( imgY != NULL ) + { + imgY->AllocImage( opts, TF_LINEAR, TR_REPEAT ); + } + if( imgCr != NULL ) + { + imgCr->AllocImage( opts, TF_LINEAR, TR_REPEAT ); + } + if( imgCb != NULL ) + { + imgCb->AllocImage( opts, TF_LINEAR, TR_REPEAT ); + } + } + +#endif + // Carl: Original Doom 3 RoQ files: image = NULL; status = FMV_EOF; @@ -457,6 +513,20 @@ } #endif +#ifdef USE_BINKDEC + if( binkHandle.isValid ) + { + Bink_Close( binkHandle ); + } + + delete imgY; + imgY = NULL; + delete imgCr; + imgCr = NULL; + delete imgCb; + imgCb = NULL; +#endif + delete img; img = NULL; } @@ -599,6 +669,80 @@ } #endif +#ifdef USE_BINKDEC +bool idCinematicLocal::InitFromBinkDecFile( const char* qpath, bool amilooping ) +{ + int ret; + looping = amilooping; + startTime = 0; + isRoQ = false; + CIN_HEIGHT = DEFAULT_CIN_HEIGHT; + CIN_WIDTH = DEFAULT_CIN_WIDTH; + + idStr fullpath; + idFile* testFile = fileSystem->OpenFileRead( qpath ); + if( testFile ) + { + fullpath = testFile->GetFullPath(); + fileSystem->CloseFile( testFile ); + } + // RB: case sensitivity HACK for Linux + else if( idStr::Cmpn( qpath, "sound/vo", 8 ) == 0 ) + { + idStr newPath( qpath ); + newPath.Replace( "sound/vo", "sound/VO" ); + + testFile = fileSystem->OpenFileRead( newPath ); + if( testFile ) + { + fullpath = testFile->GetFullPath(); + fileSystem->CloseFile( testFile ); + } + else + { + common->Warning( "idCinematic: Cannot open BinkDec video file: '%s', %d\n", qpath, looping ); + return false; + } + } + + binkHandle = Bink_Open( fullpath ); + if( !binkHandle.isValid ) + { + common->Warning( "idCinematic: Cannot open BinkDec video file: '%s', %d\n", qpath, looping ); + return false; + } + + { + uint32_t w = 0, h = 0; + Bink_GetFrameSize( binkHandle, w, h ); + CIN_WIDTH = w; + CIN_HEIGHT = h; + } + + frameRate = Bink_GetFrameRate( binkHandle ); + numFrames = Bink_GetNumFrames( binkHandle ); + float durationSec = frameRate * numFrames; + animationLength = durationSec; + buf = NULL; + + common->Printf( "Loaded BinkDec file: '%s', looping=%d%dx%d, %f FPS, %f sec\n", qpath, looping, CIN_WIDTH, CIN_HEIGHT, frameRate, durationSec ); + + status = FMV_PLAY; + + startTime = Sys_Milliseconds(); + memset( yuvBuffer, 0, sizeof( yuvBuffer ) ); + framePos = -1; + + return true; +} + +void idCinematicLocal::BinkDecReset() +{ + framePos = -1; + Bink_GotoFrame( binkHandle, 0 ); + status = FMV_LOOPED; +} +#endif // USE_BINKDEC /* ============== @@ -646,6 +790,13 @@ fileName = temp; //idLib::Warning( "New filename: '%s'\n", fileName.c_str() ); return InitFromFFMPEGFile( fileName.c_str(), amilooping ); +#elif defined(USE_BINKDEC) + idStr temp = fileName.StripFileExtension() + ".bik"; + animationLength = 0; + RoQShutdown(); + fileName = temp; + //idLib::Warning( "New filename: '%s'\n", fileName.c_str() ); + return InitFromBinkDecFile( fileName.c_str(), amilooping ); #else animationLength = 0; return false; @@ -727,6 +878,14 @@ status = FMV_EOF; } #endif +#ifdef USE_BINKDEC + if( !isRoQ && binkHandle.isValid ) + { + memset( yuvBuffer, 0 , sizeof( yuvBuffer ) ); + Bink_Close( binkHandle ); + status = FMV_EOF; + } +#endif } /* @@ -769,6 +928,10 @@ if( !isRoQ ) return ImageForTimeFFMPEG( thisTime ); #endif +#ifdef USE_BINKDEC // DG: libbinkdec support + if( !isRoQ ) + return ImageForTimeBinkDec( thisTime ); +#endif // Carl: Handle original Doom 3 RoQ video files cinData_t cinData; @@ -995,6 +1158,128 @@ return cinData; } +#endif + + +#ifdef USE_BINKDEC +cinData_t idCinematicLocal::ImageForTimeBinkDec( int thisTime ) +{ + cinData_t cinData = {0}; + + if( thisTime <= 0 ) + { + thisTime = Sys_Milliseconds(); + } + + if( r_skipDynamicTextures.GetBool() || status == FMV_EOF || status == FMV_IDLE ) + { + return cinData; + } + + if( !binkHandle.isValid ) + { + // RB: .bik requested but not found + return cinData; + } + + if( startTime == -1 ) + { + BinkDecReset(); + startTime = thisTime; + } + + int desiredFrame = ( ( thisTime - startTime ) * frameRate ) / 1000.0f; + if( desiredFrame < 0 ) + { + desiredFrame = 0; + } + + if( desiredFrame >= numFrames ) + { + status = FMV_EOF; + if( looping ) + { + desiredFrame = 0; + BinkDecReset(); + framePos = -1; + startTime = thisTime; + status = FMV_PLAY; + } + else + { + status = FMV_IDLE; + return cinData; + } + } + + if( desiredFrame == framePos ) + { + cinData.imageWidth = CIN_WIDTH; + cinData.imageHeight = CIN_HEIGHT; + cinData.status = status; + + cinData.imageY = imgY; + cinData.imageCr = imgCr; + cinData.imageCb = imgCb; + return cinData; + } + + // Bink_GotoFrame(binkHandle, desiredFrame); + // apparently Bink_GotoFrame() doesn't work super well, so skip frames + // (if necessary) by calling Bink_GetNextFrame() + while( framePos < desiredFrame ) + { + framePos = Bink_GetNextFrame( binkHandle, yuvBuffer ); + } + + cinData.imageWidth = CIN_WIDTH; + cinData.imageHeight = CIN_HEIGHT; + cinData.status = status; + + double invAspRat = double( CIN_HEIGHT ) / double( CIN_WIDTH ); + + idImage* imgs[3] = {imgY, imgCb, imgCr}; // that's the order of the channels in yuvBuffer[] + for( int i = 0; i < 3; ++i ) + { + // Note: img->UploadScratch() seems to assume 32bit per pixel data, but this is 8bit/pixel + // so uploading is a bit more manual here (compared to ffmpeg or RoQ) + idImage* img = imgs[i]; + int w = yuvBuffer[i].width; + int h = yuvBuffer[i].height; + // some videos, including the logo video and the main menu background, + // seem to have superfluous rows in at least some of the channels, + // leading to a black or glitchy bar at the bottom of the video. + // cut that off by reducing the height to the expected height + if( h > CIN_HEIGHT ) + { + h = CIN_HEIGHT; + } + else if( h < CIN_HEIGHT ) + { + // the U and V channels have a lower resolution than the Y channel + // (or the logical video resolution), so use the aspect ratio to + // calculate the real height + int hExp = invAspRat * w + 0.5; + if( h > hExp ) + h = hExp; + } + + if( img->GetUploadWidth() != w || img->GetUploadHeight() != h ) + { + idImageOpts opts = img->GetOpts(); + opts.width = w; + opts.height = h; + img->AllocImage( opts, TF_LINEAR, TR_REPEAT ); + } + img->SubImageUpload( 0, 0, 0, 0, w, h, yuvBuffer[i].data ); + } + + cinData.imageY = imgY; + cinData.imageCr = imgCr; + cinData.imageCb = imgCb; + + return cinData; +} #endif /* diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Framebuffer.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Framebuffer.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Framebuffer.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Framebuffer.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #include "precompiled.h" #pragma hdrstop -#include "tr_local.h" +#include "RenderCommon.h" #include "Framebuffer.h" idList Framebuffer::framebuffers; @@ -79,7 +79,7 @@ { cmdSystem->AddCommand( "listFramebuffers", R_ListFramebuffers_f, CMD_FL_RENDERER, "lists framebuffers" ); - backEnd.glState.currentFramebuffer = NULL; + tr.backend.currentFramebuffer = NULL; // SHADOWMAPS @@ -96,7 +96,7 @@ } // HDR - + int screenWidth = renderSystem->GetWidth(); int screenHeight = renderSystem->GetHeight(); @@ -207,7 +207,7 @@ { int screenWidth = renderSystem->GetWidth(); int screenHeight = renderSystem->GetHeight(); - + if( globalFramebuffers.hdrFBO->GetWidth() != screenWidth || globalFramebuffers.hdrFBO->GetHeight() != screenHeight ) { Unbind(); @@ -224,7 +224,7 @@ globalFramebuffers.hdrNonMSAAFBO->Bind(); globalFramebuffers.hdrNonMSAAFBO->AttachImage2D( GL_TEXTURE_2D, globalImages->currentRenderHDRImageNoMSAA, 0 ); globalFramebuffers.hdrNonMSAAFBO->Check(); - + globalFramebuffers.hdrNonMSAAFBO->width = screenWidth; globalFramebuffers.hdrNonMSAAFBO->height = screenHeight; @@ -340,33 +340,33 @@ { RENDERLOG_PRINTF( "Framebuffer::Bind( %s )\n", fboName.c_str() ); - if( backEnd.glState.currentFramebuffer != this ) + if( tr.backend.currentFramebuffer != this ) { glBindFramebuffer( GL_FRAMEBUFFER, frameBuffer ); - backEnd.glState.currentFramebuffer = this; + tr.backend.currentFramebuffer = this; } } bool Framebuffer::IsBound() { - return ( backEnd.glState.currentFramebuffer == this ); + return ( tr.backend.currentFramebuffer == this ); } void Framebuffer::Unbind() { RENDERLOG_PRINTF( "Framebuffer::Unbind()\n" ); - //if(backEnd.glState.framebuffer != NULL) + //if(tr.backend.framebuffer != NULL) { glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glBindRenderbuffer( GL_RENDERBUFFER, 0 ); - backEnd.glState.currentFramebuffer = NULL; + tr.backend.currentFramebuffer = NULL; } } bool Framebuffer::IsDefaultFramebufferActive() { - return ( backEnd.glState.currentFramebuffer == NULL ); + return ( tr.backend.currentFramebuffer == NULL ); } void Framebuffer::AddColorBuffer( int format, int index, int multiSamples ) diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/GLMatrix.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/GLMatrix.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/GLMatrix.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/GLMatrix.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" /* ========================================================================================== diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/GLState.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/GLState.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/GLState.h 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/GLState.h 2018-10-13 10:08:18.000000000 +0000 @@ -3,6 +3,7 @@ Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2016-2017 Dustin Land This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). @@ -70,6 +71,12 @@ static const uint64 GLS_DEPTHFUNC_EQUAL = 3 << 13; static const uint64 GLS_DEPTHFUNC_BITS = 3 << 13; +static const uint64 GLS_CULL_FRONTSIDED = 0 << 15; +static const uint64 GLS_CULL_BACKSIDED = 1 << 15; +static const uint64 GLS_CULL_TWOSIDED = 2 << 15; +static const uint64 GLS_CULL_BITS = 2 << 15; +static const uint64 GLS_CULL_MASK = GLS_CULL_FRONTSIDED | GLS_CULL_BACKSIDED | GLS_CULL_TWOSIDED; + static const uint64 GLS_BLENDOP_ADD = 0 << 18; static const uint64 GLS_BLENDOP_SUB = 1 << 18; static const uint64 GLS_BLENDOP_MIN = 2 << 18; @@ -138,9 +145,15 @@ static const uint64 GLS_STENCIL_OP_BITS = GLS_STENCIL_OP_FAIL_BITS | GLS_STENCIL_OP_ZFAIL_BITS | GLS_STENCIL_OP_PASS_BITS; +static const uint64 GLS_DEPTH_TEST_MASK = 1ull << 58; +static const uint64 GLS_CLOCKWISE = 1ull << 59; +static const uint64 GLS_SEPARATE_STENCIL = 1ull << 60; +static const uint64 GLS_MIRROR_VIEW = 1ull << 61; + static const uint64 GLS_OVERRIDE = 1ull << 63; // override the render prog state -static const uint64 GLS_DEFAULT = 0; +static const uint64 GLS_KEEP = GLS_DEPTH_TEST_MASK; +static const uint64 GLS_DEFAULT = 0; #define STENCIL_SHADOW_TEST_VALUE 128 #define STENCIL_SHADOW_MASK_VALUE 255 diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/GraphicsAPIWrapper.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/GraphicsAPIWrapper.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/GraphicsAPIWrapper.h 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/GraphicsAPIWrapper.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,199 +0,0 @@ -/* -=========================================================================== - -Doom 3 BFG Edition GPL Source Code -Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. -Copyright (C) 2013 Robert Beckebans - -This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). - -Doom 3 BFG Edition Source Code 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. - -Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . - -In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ -#ifndef __GRAPHICSAPIWRAPPER_H__ -#define __GRAPHICSAPIWRAPPER_H__ - -/* -================================================================================================ - - Graphics API wrapper/helper functions - - This wraps platform specific graphics API functionality that is used at run-time. This - functionality is wrapped to avoid excessive conditional compilation and/or code duplication - throughout the run-time rendering code that is shared on all platforms. - - Most other graphics API functions are called for initialization purposes and are called - directly from platform specific code implemented in files in the platform specific folders: - - renderer/OpenGL/ - renderer/DirectX/ - renderer/GCM/ - -================================================================================================ -*/ - -class idImage; -//class idTriangles; -class idRenderModelSurface; -class idDeclRenderProg; -class idRenderTexture; - -static const int MAX_OCCLUSION_QUERIES = 4096; -// returned by GL_GetDeferredQueryResult() when the query is from too long ago and the result is no longer available -static const int OCCLUSION_QUERY_TOO_OLD = -1; - -/* -================================================================================================ - - Platform Specific Context - -================================================================================================ -*/ - - - - -#define USE_CORE_PROFILE - -struct wrapperContext_t -{ -}; - - -/* -================================================ -wrapperConfig_t -================================================ -*/ -struct wrapperConfig_t -{ - // rendering options and settings - bool disableStateCaching; - bool lazyBindPrograms; - bool lazyBindParms; - bool lazyBindTextures; - bool stripFragmentBranches; - bool skipDetailTris; - bool singleTriangle; - // values for polygon offset - float polyOfsFactor; - float polyOfsUnits; - // global texture filter settings - int textureMinFilter; - int textureMaxFilter; - int textureMipFilter; - float textureAnisotropy; - float textureLODBias; -}; - -/* -================================================ -wrapperStats_t -================================================ -*/ -struct wrapperStats_t -{ - int c_queriesIssued; - int c_queriesPassed; - int c_queriesWaitTime; - int c_queriesTooOld; - int c_programsBound; - int c_drawElements; - int c_drawIndices; - int c_drawVertices; -}; - -/* -================================================================================================ - - API - -================================================================================================ -*/ - -void GL_SetWrapperContext( const wrapperContext_t& context ); -void GL_SetWrapperConfig( const wrapperConfig_t& config ); - -void GL_SetTimeDelta( uint64 delta ); // delta from GPU to CPU microseconds -void GL_StartFrame( int frame ); // inserts a timing mark for the start of the GPU frame -void GL_EndFrame(); // inserts a timing mark for the end of the GPU frame -void GL_WaitForEndFrame(); // wait for the GPU to reach the last end frame marker -void GL_GetLastFrameTime( uint64& startGPUTimeMicroSec, uint64& endGPUTimeMicroSec ); // GPU time between GL_StartFrame() and GL_EndFrame() -void GL_StartDepthPass( const idScreenRect& rect ); -void GL_FinishDepthPass(); -void GL_GetDepthPassRect( idScreenRect& rect ); - -void GL_SetDefaultState(); -void GL_State( uint64 stateVector, bool forceGlState = false ); -uint64 GL_GetCurrentState(); -uint64 GL_GetCurrentStateMinusStencil(); -void GL_Cull( int cullType ); -void GL_Scissor( int x /* left*/, int y /* bottom */, int w, int h ); -void GL_Viewport( int x /* left */, int y /* bottom */, int w, int h ); -ID_INLINE void GL_Scissor( const idScreenRect& rect ) -{ - GL_Scissor( rect.x1, rect.y1, rect.x2 - rect.x1 + 1, rect.y2 - rect.y1 + 1 ); -} -ID_INLINE void GL_Viewport( const idScreenRect& rect ) -{ - GL_Viewport( rect.x1, rect.y1, rect.x2 - rect.x1 + 1, rect.y2 - rect.y1 + 1 ); -} -ID_INLINE void GL_ViewportAndScissor( int x, int y, int w, int h ) -{ - GL_Viewport( x, y, w, h ); - GL_Scissor( x, y, w, h ); -} -ID_INLINE void GL_ViewportAndScissor( const idScreenRect& rect ) -{ - GL_Viewport( rect ); - GL_Scissor( rect ); -} - -// RB: HDR parm -void GL_Clear( bool color, bool depth, bool stencil, byte stencilValue, float r, float g, float b, float a, bool clearHDR = true ); -// RB end -void GL_PolygonOffset( float scale, float bias ); -void GL_DepthBoundsTest( const float zmin, const float zmax ); -//void GL_Color( float* color ); -// RB begin -void GL_Color( const idVec3& color ); -void GL_Color( const idVec4& color ); -// RB end -void GL_Color( float r, float g, float b ); -void GL_Color( float r, float g, float b, float a ); -void GL_SelectTexture( int unit ); - -void GL_Flush(); // flush the GPU command buffer -void GL_Finish(); // wait for the GPU to have executed all commands - - -// RB begin -bool GL_CheckErrors_( const char* filename, int line ); -#if 1 // !defined(RETAIL) -#define GL_CheckErrors() GL_CheckErrors_(__FILE__, __LINE__) -#else -#define GL_CheckErrors() false -#endif -// RB end - -wrapperStats_t GL_GetCurrentStats(); -void GL_ClearStats(); - - -#endif // !__GRAPHICSAPIWRAPPER_H__ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/GuiModel.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/GuiModel.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/GuiModel.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/GuiModel.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" const float idGuiModel::STEREO_DEPTH_NEAR = 0.0f; const float idGuiModel::STEREO_DEPTH_MID = 0.5f; diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/GuiModel.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/GuiModel.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/GuiModel.h 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/GuiModel.h 2018-10-13 10:08:18.000000000 +0000 @@ -42,16 +42,16 @@ public: idGuiModel(); - void Clear(); + void Clear(); - void WriteToDemo( idDemoFile* demo ); - void ReadFromDemo( idDemoFile* demo ); + void WriteToDemo( idDemoFile* demo ); + void ReadFromDemo( idDemoFile* demo ); // allocates memory for verts and indexes in frame-temporary buffer memory - void BeginFrame(); + void BeginFrame(); - void EmitToCurrentView( float modelMatrix[16], bool depthHack ); - void EmitFullScreen(); + void EmitToCurrentView( float modelMatrix[16], bool depthHack ); + void EmitFullScreen(); // the returned pointer will be in write-combined memory, so only make contiguous // 32 bit writes and never read from it. @@ -60,10 +60,9 @@ //--------------------------- private: - void AdvanceSurf(); - void EmitSurfaces( float modelMatrix[16], float modelViewMatrix[16], - bool depthHack, bool allowFullScreenStereoDepth, bool linkAsEntity ); - + void AdvanceSurf(); + void EmitSurfaces( float modelMatrix[16], float modelViewMatrix[16], bool depthHack, bool allowFullScreenStereoDepth, bool linkAsEntity ); + guiModelSurface_t* surf; float shaderParms[ MAX_ENTITY_SHADER_PARMS ]; @@ -81,8 +80,8 @@ idDrawVert* vertexPointer; triIndex_t* indexPointer; - int numVerts; - int numIndexes; + int numVerts; + int numIndexes; idList surfaces; }; diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image_files.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image_files.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image_files.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image_files.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -31,7 +31,7 @@ #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" /* diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image.h 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image.h 2018-10-13 10:08:18.000000000 +0000 @@ -3,7 +3,8 @@ Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. -Copyright (C) 2013-2014 Robert Beckebans +Copyright (C) 2013-2017 Robert Beckebans +Copyright (C) 2016-2017 Dustin Land This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). @@ -27,6 +28,164 @@ =========================================================================== */ +enum textureType_t +{ + TT_DISABLED, + TT_2D, + TT_CUBIC, + // RB begin + TT_2D_ARRAY, + TT_2D_MULTISAMPLE + // RB end +}; + +/* +================================================ +The internal *Texture Format Types*, ::textureFormat_t, are: +================================================ +*/ +enum textureFormat_t +{ + FMT_NONE, + + //------------------------ + // Standard color image formats + //------------------------ + + FMT_RGBA8, // 32 bpp + FMT_XRGB8, // 32 bpp + + //------------------------ + // Alpha channel only + //------------------------ + + // Alpha ends up being the same as L8A8 in our current implementation, because straight + // alpha gives 0 for color, but we want 1. + FMT_ALPHA, + + //------------------------ + // Luminance replicates the value across RGB with a constant A of 255 + // Intensity replicates the value across RGBA + //------------------------ + + FMT_L8A8, // 16 bpp + FMT_LUM8, // 8 bpp + FMT_INT8, // 8 bpp + + //------------------------ + // Compressed texture formats + //------------------------ + + FMT_DXT1, // 4 bpp + FMT_DXT5, // 8 bpp + + //------------------------ + // Depth buffer formats + //------------------------ + + FMT_DEPTH, // 24 bpp + + //------------------------ + // + //------------------------ + + FMT_X16, // 16 bpp + FMT_Y16_X16, // 32 bpp + FMT_RGB565, // 16 bpp + + // RB: don't change above for legacy .bimage compatibility + FMT_ETC1_RGB8_OES, // 4 bpp + FMT_SHADOW_ARRAY, // 32 bpp * 6 + FMT_RGBA16F, // 64 bpp + FMT_RGBA32F, // 128 bpp + FMT_R32F, // 32 bpp + // RB end +}; + +int BitsForFormat( textureFormat_t format ); + +enum textureSamples_t +{ + SAMPLE_1 = BIT( 0 ), + SAMPLE_2 = BIT( 1 ), + SAMPLE_4 = BIT( 2 ), + SAMPLE_8 = BIT( 3 ), + SAMPLE_16 = BIT( 4 ) +}; + +/* +================================================ +DXT5 color formats +================================================ +*/ +enum textureColor_t +{ + CFM_DEFAULT, // RGBA + CFM_NORMAL_DXT5, // XY format and use the fast DXT5 compressor + CFM_YCOCG_DXT5, // convert RGBA to CoCg_Y format + CFM_GREEN_ALPHA, // Copy the alpha channel to green + + // RB: don't change above for legacy .bimage compatibility + CFM_YCOCG_RGBA8, + // RB end +}; + +/* +================================================ +idImageOpts hold parameters for texture operations. +================================================ +*/ +class idImageOpts +{ +public: + idImageOpts(); + + bool operator==( const idImageOpts& opts ); + + //--------------------------------------------------- + // these determine the physical memory size and layout + //--------------------------------------------------- + + textureType_t textureType; + textureFormat_t format; + textureColor_t colorFormat; + textureSamples_t samples; + int width; + int height; // not needed for cube maps + int numLevels; // if 0, will be 1 for NEAREST / LINEAR filters, otherwise based on size + bool gammaMips; // if true, mips will be generated with gamma correction + bool readback; // 360 specific - cpu reads back from this texture, so allocate with cached memory +}; + +/* +======================== +idImageOpts::idImageOpts +======================== +*/ +ID_INLINE idImageOpts::idImageOpts() +{ + format = FMT_NONE; + colorFormat = CFM_DEFAULT; + samples = SAMPLE_1; + width = 0; + height = 0; + numLevels = 0; + textureType = TT_2D; + gammaMips = false; + readback = false; + +}; + +/* +======================== +idImageOpts::operator== +======================== +*/ +ID_INLINE bool idImageOpts::operator==( const idImageOpts& opts ) +{ + return ( memcmp( this, &opts, sizeof( *this ) ) == 0 ); +} + /* ==================================================================== @@ -79,7 +238,6 @@ JPG }; -#include "ImageOpts.h" #include "BinaryImage.h" #define MAX_IMAGE_NAME 256 @@ -90,6 +248,7 @@ public: idImage( const char* name ); + ~idImage(); const char* GetName() const { @@ -101,18 +260,6 @@ // May perform file loading if the image was not preloaded. void Bind(); - // Should be called at least once - void SetSamplerState( textureFilter_t tf, textureRepeat_t tr ); - - // used by callback functions to specify the actual data - // data goes from the bottom to the top line of the image, as OpenGL expects it - // These perform an implicit Bind() on the current texture unit - // FIXME: should we implement cinematics this way, instead of with explicit calls? - void GenerateImage( const byte* pic, int width, int height, - textureFilter_t filter, textureRepeat_t repeat, textureUsage_t usage, int msaaSamples = 0 ); - void GenerateCubeImage( const byte* pic[6], int size, - textureFilter_t filter, textureUsage_t usage ); - // RB begin void GenerateShadowArray( int width, int height, textureFilter_t filter, textureRepeat_t repeat, textureUsage_t usage ); // RB end @@ -164,6 +311,26 @@ // Platform specific implementations //--------------------------------------------- +#if defined( ID_VULKAN ) + void CreateFromSwapImage( VkImage image, VkImageView imageView, VkFormat format, const VkExtent2D& extent ); + VkImage GetImage() const + { + return image; + } + VkImageView GetView() const + { + return view; + } + VkImageLayout GetLayout() const + { + return layout; + } + VkSampler GetSampler() const + { + return sampler; + } +#endif + void AllocImage( const idImageOpts& imgOpts, textureFilter_t filter, textureRepeat_t repeat ); // Deletes the texture object, but leaves the structure so it can be reloaded @@ -196,20 +363,37 @@ return ( opts.format == FMT_DXT1 || opts.format == FMT_DXT5 ); } - void SetTexParameters(); // update aniso and trilinear + bool IsLoaded() const { return texnum != TEXTURE_NOT_LOADED; } - static void GetGeneratedName( idStr& _name, const textureUsage_t& _usage, const cubeFiles_t& _cube ); + static void GetGeneratedName( idStr& _name, const textureUsage_t& _usage, const cubeFiles_t& _cube ); + + // used by callback functions to specify the actual data + // data goes from the bottom to the top line of the image, as OpenGL expects it + // These perform an implicit Bind() on the current texture unit + // FIXME: should we implement cinematics this way, instead of with explicit calls? + void GenerateImage( const byte* pic, + int width, int height, + textureFilter_t filter, + textureRepeat_t repeat, + textureUsage_t usage, + int msaaSamples = 0 ); + + void GenerateCubeImage( const byte* pic[6], int size, + textureFilter_t filter, textureUsage_t usage ); + + void SetTexParameters(); // update aniso and trilinear private: friend class idImageManager; - void AllocImage(); - void DeriveOpts(); + void DeriveOpts(); + void AllocImage(); + void SetSamplerState( textureFilter_t tf, textureRepeat_t tr ); // parameters that define this image idStr imgName; // game path, including extension (except for cube maps), may be an image program @@ -232,37 +416,36 @@ static const GLuint TEXTURE_NOT_LOADED = 0xFFFFFFFF; +#if defined( ID_VULKAN ) + bool bIsSwapChainImage; + VkFormat internalFormat; + VkImage image; + VkImageView view; + VkImageLayout layout; + VkSampler sampler; + +#if defined( ID_USE_AMD_ALLOCATOR ) + VmaAllocation allocation; + static idList< VmaAllocation > allocationGarbage[ NUM_FRAME_DATA ]; +#else + vulkanAllocation_t allocation; + static idList< vulkanAllocation_t > allocationGarbage[ NUM_FRAME_DATA ]; +#endif + + static int garbageIndex; + static idList< VkImage > imageGarbage[ NUM_FRAME_DATA ]; + static idList< VkImageView > viewGarbage[ NUM_FRAME_DATA ]; + static idList< VkSampler > samplerGarbage[ NUM_FRAME_DATA ]; +#else GLuint texnum; // gl texture binding // we could derive these in subImageUpload each time if necessary GLuint internalFormat; GLuint dataFormat; GLuint dataType; - - +#endif }; -ID_INLINE idImage::idImage( const char* name ) : imgName( name ) -{ - texnum = TEXTURE_NOT_LOADED; - internalFormat = 0; - dataFormat = 0; - dataType = 0; - generatorFunction = NULL; - filter = TF_DEFAULT; - repeat = TR_REPEAT; - usage = TD_DEFAULT; - cubeFiles = CF_2D; - - referencedOutsideLevelLoad = false; - levelLoadReferenced = false; - defaulted = false; - sourceFileTime = FILE_NOT_FOUND_TIMESTAMP; - binaryFileTime = FILE_NOT_FOUND_TIMESTAMP; - refCount = 0; -} - - // data is RGBA void R_WriteTGA( const char* filename, const byte* data, int width, int height, bool flipVertical = false, const char* basePath = "fs_savepath" ); // data is in top-to-bottom raster order unless flipVertical is set @@ -313,12 +496,6 @@ // reloads all apropriate images after a vid_restart void ReloadImages( bool all ); - // unbind all textures from all texture units - void UnbindAll(); - - // disable the active texture unit - void BindNull(); - // Called only by renderSystem::BeginLevelLoad void BeginLevelLoad(); @@ -330,14 +507,10 @@ // Loads unloaded level images int LoadLevelImages( bool pacifier ); - // used to clear and then write the dds conversion batch file - void StartBuild(); - void FinishBuild( bool removeDups = false ); - void PrintMemInfo( MemInfo_t* mi ); // built-in images - void CreateIntrinsicImages(); + void CreateIntrinsicImages(); idImage* defaultImage; idImage* flatNormalMap; // 128 128 255 in all pixels idImage* alphaNotchImage; // 2x1 texture with just 1110 and 1111 with point sampling @@ -396,8 +569,6 @@ extern idImageManager* globalImages; // pointer to global list for the rest of the system -int MakePowerOfTwo( int num ); - /* ==================================================================== diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image_intrinsic.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image_intrinsic.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image_intrinsic.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image_intrinsic.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -31,7 +31,7 @@ #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "SMAA/AreaTex.h" #include "SMAA/SearchTex.h" diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image_load.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image_load.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image_load.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image_load.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -3,8 +3,9 @@ Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. -Copyright (C) 2013-2016 Robert Beckebans +Copyright (C) 2013-2017 Robert Beckebans Copyright (C) 2014-2016 Kot in Action Creative Artel +Copyright (C) 2016-2017 Dustin Land This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). @@ -32,7 +33,7 @@ #include "precompiled.h" #include "framework/Common_local.h" -#include "tr_local.h" +#include "RenderCommon.h" /* ================ @@ -94,7 +95,6 @@ */ ID_INLINE void idImage::DeriveOpts() { - if( opts.format == FMT_NONE ) { opts.colorFormat = CFM_DEFAULT; @@ -152,7 +152,9 @@ opts.gammaMips = true; break; case TD_LIGHT: - // RB: don't destroy lighting + // RB: TODO check binary format version + // D3 BFG assets require RGB565 but it introduces color banding + // mods would prefer FMT_RGBA8 opts.format = FMT_RGB565; //FMT_RGBA8; opts.gammaMips = true; break; @@ -214,172 +216,6 @@ } /* -================ -GenerateImage -================ -*/ -void idImage::GenerateImage( const byte* pic, int width, int height, textureFilter_t filterParm, textureRepeat_t repeatParm, textureUsage_t usageParm, int msaaSamples ) -{ - PurgeImage(); - - filter = filterParm; - repeat = repeatParm; - usage = usageParm; - cubeFiles = CF_2D; - - opts.textureType = ( msaaSamples > 0 ) ? TT_2D_MULTISAMPLE : TT_2D; - opts.width = width; - opts.height = height; - opts.numLevels = 0; - opts.msaaSamples = msaaSamples; - DeriveOpts(); - - // if we don't have a rendering context, just return after we - // have filled in the parms. We must have the values set, or - // an image match from a shader before the render starts would miss - // the generated texture - if( !R_IsInitialized() ) - { - return; - } - - // RB: allow pic == NULL for internal framebuffer images - if( pic == NULL || opts.textureType == TT_2D_MULTISAMPLE ) - { - AllocImage(); - } - else - { - idBinaryImage im( GetName() ); - - - // foresthale 2014-05-30: give a nice progress display when binarizing - commonLocal.LoadPacifierBinarizeFilename( GetName() , "generated image" ); - if( opts.numLevels > 1 ) - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.height * 4 / 3 ); - } - else - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.height ); - } - - im.Load2DFromMemory( width, height, pic, opts.numLevels, opts.format, opts.colorFormat, opts.gammaMips ); - - commonLocal.LoadPacifierBinarizeEnd(); - - AllocImage(); - - for( int i = 0; i < im.NumImages(); i++ ) - { - const bimageImage_t& img = im.GetImageHeader( i ); - const byte* data = im.GetImageData( i ); - SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data ); - } - } - // RB end -} - -/* -==================== -GenerateCubeImage - -Non-square cube sides are not allowed -==================== -*/ -void idImage::GenerateCubeImage( const byte* pic[6], int size, textureFilter_t filterParm, textureUsage_t usageParm ) -{ - PurgeImage(); - - filter = filterParm; - repeat = TR_CLAMP; - usage = usageParm; - cubeFiles = CF_NATIVE; - - opts.textureType = TT_CUBIC; - opts.width = size; - opts.height = size; - opts.numLevels = 0; - DeriveOpts(); - - // if we don't have a rendering context, just return after we - // have filled in the parms. We must have the values set, or - // an image match from a shader before the render starts would miss - // the generated texture - if( !R_IsInitialized() ) - { - return; - } - - idBinaryImage im( GetName() ); - - // foresthale 2014-05-30: give a nice progress display when binarizing - commonLocal.LoadPacifierBinarizeFilename( GetName(), "generated cube image" ); - if( opts.numLevels > 1 ) - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.width * 6 * 4 / 3 ); - } - else - { - commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.width * 6 ); - } - - im.LoadCubeFromMemory( size, pic, opts.numLevels, opts.format, opts.gammaMips ); - - commonLocal.LoadPacifierBinarizeEnd(); - - AllocImage(); - - for( int i = 0; i < im.NumImages(); i++ ) - { - const bimageImage_t& img = im.GetImageHeader( i ); - const byte* data = im.GetImageData( i ); - SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data ); - } -} - -// RB begin -void idImage::GenerateShadowArray( int width, int height, textureFilter_t filterParm, textureRepeat_t repeatParm, textureUsage_t usageParm ) -{ - PurgeImage(); - - filter = filterParm; - repeat = repeatParm; - usage = usageParm; - cubeFiles = CF_2D_ARRAY; - - opts.textureType = TT_2D_ARRAY; - opts.width = width; - opts.height = height; - opts.numLevels = 0; - DeriveOpts(); - - // if we don't have a rendering context, just return after we - // have filled in the parms. We must have the values set, or - // an image match from a shader before the render starts would miss - // the generated texture - if( !R_IsInitialized() ) - { - return; - } - - //idBinaryImage im( GetName() ); - //im.Load2DFromMemory( width, height, pic, opts.numLevels, opts.format, opts.colorFormat, opts.gammaMips ); - - AllocImage(); - - /* - for( int i = 0; i < im.NumImages(); i++ ) - { - const bimageImage_t& img = im.GetImageHeader( i ); - const byte* data = im.GetImageData( i ); - SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data ); - } - */ -} -// RB end - -/* =============== GetGeneratedName @@ -436,12 +272,11 @@ } else { - // RB begin + // RB: added CF_2D_ARRAY if( cubeFiles == CF_2D_ARRAY ) { opts.textureType = TT_2D_ARRAY; } - // RB end else if( cubeFiles != CF_2D ) { opts.textureType = TT_CUBIC; @@ -649,7 +484,6 @@ AllocImage(); - for( int i = 0; i < im.NumImages(); i++ ) { const bimageImage_t& img = im.GetImageHeader( i ); @@ -659,343 +493,69 @@ } /* -============== -Bind - -Automatically enables 2D mapping or cube mapping if needed -============== +================== +StorageSize +================== */ -void idImage::Bind() +int idImage::StorageSize() const { - RENDERLOG_PRINTF( "idImage::Bind( %s )\n", GetName() ); - - // load the image if necessary (FIXME: not SMP safe!) if( !IsLoaded() ) { - // load the image on demand here, which isn't our normal game operating mode - ActuallyLoadImage( true ); - } - - const int texUnit = backEnd.glState.currenttmu; - - // RB: added support for more types - tmu_t* tmu = &backEnd.glState.tmu[texUnit]; - // bind the texture - if( opts.textureType == TT_2D ) - { - if( tmu->current2DMap != texnum ) - { - tmu->current2DMap = texnum; - -#if !defined(USE_GLES2) && !defined(USE_GLES3) - if( glConfig.directStateAccess ) - { - glBindMultiTextureEXT( GL_TEXTURE0 + texUnit, GL_TEXTURE_2D, texnum ); - } - else -#endif - { - glActiveTexture( GL_TEXTURE0 + texUnit ); - glBindTexture( GL_TEXTURE_2D, texnum ); - } - } - } - else if( opts.textureType == TT_CUBIC ) - { - if( tmu->currentCubeMap != texnum ) - { - tmu->currentCubeMap = texnum; - -#if !defined(USE_GLES2) && !defined(USE_GLES3) - if( glConfig.directStateAccess ) - { - glBindMultiTextureEXT( GL_TEXTURE0 + texUnit, GL_TEXTURE_CUBE_MAP, texnum ); - } - else -#endif - { - glActiveTexture( GL_TEXTURE0 + texUnit ); - glBindTexture( GL_TEXTURE_CUBE_MAP, texnum ); - } - } - } - else if( opts.textureType == TT_2D_ARRAY ) - { - if( tmu->current2DArray != texnum ) - { - tmu->current2DArray = texnum; - -#if !defined(USE_GLES2) && !defined(USE_GLES3) - if( glConfig.directStateAccess ) - { - glBindMultiTextureEXT( GL_TEXTURE0 + texUnit, GL_TEXTURE_2D_ARRAY, texnum ); - } - else -#endif - { - glActiveTexture( GL_TEXTURE0 + texUnit ); - glBindTexture( GL_TEXTURE_2D_ARRAY, texnum ); - } - } + return 0; } - else if( opts.textureType == TT_2D_MULTISAMPLE ) + int baseSize = opts.width * opts.height; + if( opts.numLevels > 1 ) { - if( tmu->current2DMap != texnum ) - { - tmu->current2DMap = texnum; - -#if !defined(USE_GLES2) && !defined(USE_GLES3) - if( glConfig.directStateAccess ) - { - glBindMultiTextureEXT( GL_TEXTURE0 + texUnit, GL_TEXTURE_2D_MULTISAMPLE, texnum ); - } - else -#endif - { - glActiveTexture( GL_TEXTURE0 + texUnit ); - glBindTexture( GL_TEXTURE_2D_MULTISAMPLE, texnum ); - } - } + baseSize *= 4; + baseSize /= 3; } - // RB end + baseSize *= BitsForFormat( opts.format ); + baseSize /= 8; + return baseSize; } /* -================ -MakePowerOfTwo -================ +================== +Print +================== */ -int MakePowerOfTwo( int num ) +void idImage::Print() const { - int pot; - for( pot = 1; pot < num; pot <<= 1 ) + if( generatorFunction ) { + common->Printf( "F" ); } - return pot; -} - -/* -==================== -CopyFramebuffer -==================== -*/ -void idImage::CopyFramebuffer( int x, int y, int imageWidth, int imageHeight ) -{ - int target = GL_TEXTURE_2D; + else + { + common->Printf( " " ); + } + switch( opts.textureType ) { case TT_2D: - target = GL_TEXTURE_2D; + common->Printf( " " ); break; case TT_CUBIC: - target = GL_TEXTURE_CUBE_MAP; + common->Printf( "C " ); break; + case TT_2D_ARRAY: - target = GL_TEXTURE_2D_ARRAY; + common->Printf( "2D-A " ); break; + case TT_2D_MULTISAMPLE: - target = GL_TEXTURE_2D_MULTISAMPLE; + common->Printf( "2D-MS " ); break; + default: - //idLib::FatalError( "%s: bad texture type %d", GetName(), opts.textureType ); - return; + common->Printf( "", opts.textureType ); + break; } - glBindTexture( target, texnum ); + common->Printf( "%4i %4i ", opts.width, opts.height ); -#if !defined(USE_GLES2) - if( Framebuffer::IsDefaultFramebufferActive() ) - { - glReadBuffer( GL_BACK ); - } -#endif - - opts.width = imageWidth; - opts.height = imageHeight; - -#if defined(USE_GLES2) - glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, x, y, imageWidth, imageHeight, 0 ); -#else - if( r_useHDR.GetBool() && globalFramebuffers.hdrFBO->IsBound() ) - { - - //if( backEnd.glState.currentFramebuffer != NULL && backEnd.glState.currentFramebuffer->IsMultiSampled() ) - -#if defined(USE_HDR_MSAA) - if( globalFramebuffers.hdrFBO->IsMultiSampled() ) - { - glBindFramebuffer( GL_READ_FRAMEBUFFER, globalFramebuffers.hdrFBO->GetFramebuffer() ); - glBindFramebuffer( GL_DRAW_FRAMEBUFFER, globalFramebuffers.hdrNonMSAAFBO->GetFramebuffer() ); - glBlitFramebuffer( 0, 0, glConfig.nativeScreenWidth, glConfig.nativeScreenHeight, - 0, 0, glConfig.nativeScreenWidth, glConfig.nativeScreenHeight, - GL_COLOR_BUFFER_BIT, - GL_LINEAR ); - - globalFramebuffers.hdrNonMSAAFBO->Bind(); - - glCopyTexImage2D( target, 0, GL_RGBA16F, x, y, imageWidth, imageHeight, 0 ); - - globalFramebuffers.hdrFBO->Bind(); - } - else -#endif - { - glCopyTexImage2D( target, 0, GL_RGBA16F, x, y, imageWidth, imageHeight, 0 ); - } - } - else - { - glCopyTexImage2D( target, 0, GL_RGBA8, x, y, imageWidth, imageHeight, 0 ); - } -#endif - - // these shouldn't be necessary if the image was initialized properly - glTexParameterf( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameterf( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - - glTexParameterf( target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameterf( target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - - backEnd.pc.c_copyFrameBuffer++; -} - -/* -==================== -CopyDepthbuffer -==================== -*/ -void idImage::CopyDepthbuffer( int x, int y, int imageWidth, int imageHeight ) -{ - glBindTexture( ( opts.textureType == TT_CUBIC ) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, texnum ); - - opts.width = imageWidth; - opts.height = imageHeight; - glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, x, y, imageWidth, imageHeight, 0 ); - - backEnd.pc.c_copyFrameBuffer++; -} - -/* -============= -RB_UploadScratchImage - -if rows = cols * 6, assume it is a cube map animation -============= -*/ -void idImage::UploadScratch( const byte* data, int cols, int rows ) -{ - - // if rows = cols * 6, assume it is a cube map animation - if( rows == cols * 6 ) - { - rows /= 6; - const byte* pic[6]; - for( int i = 0; i < 6; i++ ) - { - pic[i] = data + cols * rows * 4 * i; - } - - if( opts.textureType != TT_CUBIC || usage != TD_LOOKUP_TABLE_RGBA ) - { - GenerateCubeImage( pic, cols, TF_LINEAR, TD_LOOKUP_TABLE_RGBA ); - return; - } - if( opts.width != cols || opts.height != rows ) - { - opts.width = cols; - opts.height = rows; - AllocImage(); - } - SetSamplerState( TF_LINEAR, TR_CLAMP ); - for( int i = 0; i < 6; i++ ) - { - SubImageUpload( 0, 0, 0, i, opts.width, opts.height, pic[i] ); - } - - } - else - { - if( opts.textureType != TT_2D || usage != TD_LOOKUP_TABLE_RGBA ) - { - GenerateImage( data, cols, rows, TF_LINEAR, TR_REPEAT, TD_LOOKUP_TABLE_RGBA ); - return; - } - if( opts.width != cols || opts.height != rows ) - { - opts.width = cols; - opts.height = rows; - AllocImage(); - } - SetSamplerState( TF_LINEAR, TR_REPEAT ); - SubImageUpload( 0, 0, 0, 0, opts.width, opts.height, data ); - } -} - -/* -================== -StorageSize -================== -*/ -int idImage::StorageSize() const -{ - - if( !IsLoaded() ) - { - return 0; - } - int baseSize = opts.width * opts.height; - if( opts.numLevels > 1 ) - { - baseSize *= 4; - baseSize /= 3; - } - baseSize *= BitsForFormat( opts.format ); - baseSize /= 8; - return baseSize; -} - -/* -================== -Print -================== -*/ -void idImage::Print() const -{ - if( generatorFunction ) - { - common->Printf( "F" ); - } - else - { - common->Printf( " " ); - } - - switch( opts.textureType ) - { - case TT_2D: - common->Printf( " " ); - break; - case TT_CUBIC: - common->Printf( "C " ); - break; - - case TT_2D_ARRAY: - common->Printf( "2D-A " ); - break; - - case TT_2D_MULTISAMPLE: - common->Printf( "2D-MS " ); - break; - - default: - common->Printf( "", opts.textureType ); - break; - } - - common->Printf( "%4i %4i ", opts.width, opts.height ); - - switch( opts.format ) + switch( opts.format ) { #define NAME_FORMAT( x ) case FMT_##x: common->Printf( "%-16s ", #x ); break; NAME_FORMAT( NONE ); @@ -1124,3 +684,224 @@ glBindTexture( ( opts.textureType == TT_CUBIC ) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, texnum ); SetTexParameters(); } + +/* +================ +GenerateImage +================ +*/ +void idImage::GenerateImage( const byte* pic, int width, int height, textureFilter_t filterParm, textureRepeat_t repeatParm, textureUsage_t usageParm, int msaaSamples ) +{ + PurgeImage(); + + filter = filterParm; + repeat = repeatParm; + usage = usageParm; + cubeFiles = CF_2D; + + opts.textureType = ( msaaSamples > 0 ) ? TT_2D_MULTISAMPLE : TT_2D; + opts.width = width; + opts.height = height; + opts.numLevels = 0; + opts.samples = textureSamples_t( msaaSamples ); + DeriveOpts(); + + // if we don't have a rendering context, just return after we + // have filled in the parms. We must have the values set, or + // an image match from a shader before the render starts would miss + // the generated texture + if( !R_IsInitialized() ) + { + return; + } + + // RB: allow pic == NULL for internal framebuffer images + if( pic == NULL || opts.textureType == TT_2D_MULTISAMPLE ) + { + AllocImage(); + } + else + { + idBinaryImage im( GetName() ); + + + // foresthale 2014-05-30: give a nice progress display when binarizing + commonLocal.LoadPacifierBinarizeFilename( GetName() , "generated image" ); + if( opts.numLevels > 1 ) + { + commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.height * 4 / 3 ); + } + else + { + commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.height ); + } + + im.Load2DFromMemory( width, height, pic, opts.numLevels, opts.format, opts.colorFormat, opts.gammaMips ); + + commonLocal.LoadPacifierBinarizeEnd(); + + AllocImage(); + + for( int i = 0; i < im.NumImages(); i++ ) + { + const bimageImage_t& img = im.GetImageHeader( i ); + const byte* data = im.GetImageData( i ); + SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data ); + } + } + // RB end +} + +/* +==================== +GenerateCubeImage + +Non-square cube sides are not allowed +==================== +*/ +void idImage::GenerateCubeImage( const byte* pic[6], int size, textureFilter_t filterParm, textureUsage_t usageParm ) +{ + PurgeImage(); + + filter = filterParm; + repeat = TR_CLAMP; + usage = usageParm; + cubeFiles = CF_NATIVE; + + opts.textureType = TT_CUBIC; + opts.width = size; + opts.height = size; + opts.numLevels = 0; + DeriveOpts(); + + // if we don't have a rendering context, just return after we + // have filled in the parms. We must have the values set, or + // an image match from a shader before the render starts would miss + // the generated texture + if( !R_IsInitialized() ) + { + return; + } + + idBinaryImage im( GetName() ); + + // foresthale 2014-05-30: give a nice progress display when binarizing + commonLocal.LoadPacifierBinarizeFilename( GetName(), "generated cube image" ); + if( opts.numLevels > 1 ) + { + commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.width * 6 * 4 / 3 ); + } + else + { + commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.width * 6 ); + } + + im.LoadCubeFromMemory( size, pic, opts.numLevels, opts.format, opts.gammaMips ); + + commonLocal.LoadPacifierBinarizeEnd(); + + AllocImage(); + + for( int i = 0; i < im.NumImages(); i++ ) + { + const bimageImage_t& img = im.GetImageHeader( i ); + const byte* data = im.GetImageData( i ); + SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data ); + } +} + +// RB begin +void idImage::GenerateShadowArray( int width, int height, textureFilter_t filterParm, textureRepeat_t repeatParm, textureUsage_t usageParm ) +{ + PurgeImage(); + + filter = filterParm; + repeat = repeatParm; + usage = usageParm; + cubeFiles = CF_2D_ARRAY; + + opts.textureType = TT_2D_ARRAY; + opts.width = width; + opts.height = height; + opts.numLevels = 0; + DeriveOpts(); + + // if we don't have a rendering context, just return after we + // have filled in the parms. We must have the values set, or + // an image match from a shader before the render starts would miss + // the generated texture + if( !R_IsInitialized() ) + { + return; + } + + //idBinaryImage im( GetName() ); + //im.Load2DFromMemory( width, height, pic, opts.numLevels, opts.format, opts.colorFormat, opts.gammaMips ); + + AllocImage(); + + /* + for( int i = 0; i < im.NumImages(); i++ ) + { + const bimageImage_t& img = im.GetImageHeader( i ); + const byte* data = im.GetImageData( i ); + SubImageUpload( img.level, 0, 0, img.destZ, img.width, img.height, data ); + } + */ +} +// RB end +/* +============= +RB_UploadScratchImage + +if rows = cols * 6, assume it is a cube map animation +============= +*/ +void idImage::UploadScratch( const byte* data, int cols, int rows ) +{ + // if rows = cols * 6, assume it is a cube map animation + if( rows == cols * 6 ) + { + rows /= 6; + const byte* pic[6]; + for( int i = 0; i < 6; i++ ) + { + pic[i] = data + cols * rows * 4 * i; + } + + if( opts.textureType != TT_CUBIC || usage != TD_LOOKUP_TABLE_RGBA ) + { + GenerateCubeImage( pic, cols, TF_LINEAR, TD_LOOKUP_TABLE_RGBA ); + return; + } + if( opts.width != cols || opts.height != rows ) + { + opts.width = cols; + opts.height = rows; + + AllocImage(); + } + SetSamplerState( TF_LINEAR, TR_CLAMP ); + for( int i = 0; i < 6; i++ ) + { + SubImageUpload( 0, 0, 0, i, opts.width, opts.height, pic[i] ); + } + } + else + { + if( opts.textureType != TT_2D || usage != TD_LOOKUP_TABLE_RGBA ) + { + GenerateImage( data, cols, rows, TF_LINEAR, TR_REPEAT, TD_LOOKUP_TABLE_RGBA ); + return; + } + if( opts.width != cols || opts.height != rows ) + { + opts.width = cols; + opts.height = rows; + + AllocImage(); + } + SetSamplerState( TF_LINEAR, TR_REPEAT ); + SubImageUpload( 0, 0, 0, 0, opts.width, opts.height, data ); + } +} \ No newline at end of file diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ImageManager.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ImageManager.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ImageManager.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ImageManager.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" // do this with a pointer, in case we want to make the actual manager // a private virtual subclass @@ -63,7 +63,7 @@ } else { - common->Printf( "USAGE: reloadImages \n" ); + idLib::Printf( "USAGE: reloadImages \n" ); return; } } @@ -81,7 +81,6 @@ /* ======================= R_QsortImageSizes - ======================= */ static int R_QsortImageSizes( const void* a, const void* b ) @@ -105,7 +104,6 @@ /* ======================= R_QsortImageName - ======================= */ static int R_QsortImageName( const void* a, const void* b ) @@ -180,20 +178,23 @@ if( failed ) { - common->Printf( "usage: listImages [ sorted | namesort | unloaded | duplicated | showOverSized ]\n" ); + idLib::Printf( "usage: listImages [ sorted | namesort | unloaded | duplicated | showOverSized ]\n" ); return; } const char* header = " -w-- -h-- filt -fmt-- wrap size --name-------\n"; - common->Printf( "\n%s", header ); + idLib::Printf( "\n%s", header ); totalSize = 0; - sortedImage_t* sortedArray = ( sortedImage_t* )alloca( sizeof( sortedImage_t ) * globalImages->images.Num() ); + idList< idImage* >& images = globalImages->images; + const int numImages = images.Num(); + + sortedImage_t* sortedArray = ( sortedImage_t* )alloca( sizeof( sortedImage_t ) * numImages ); - for( i = 0 ; i < globalImages->images.Num() ; i++ ) + for( i = 0 ; i < numImages; i++ ) { - image = globalImages->images[ i ]; + image = images[ i ]; if( uncompressedOnly ) { @@ -211,14 +212,14 @@ if( duplicated ) { int j; - for( j = i + 1 ; j < globalImages->images.Num() ; j++ ) + for( j = i + 1 ; j < numImages ; j++ ) { - if( idStr::Icmp( image->GetName(), globalImages->images[ j ]->GetName() ) == 0 ) + if( idStr::Icmp( image->GetName(), images[ j ]->GetName() ) == 0 ) { break; } } - if( j == globalImages->images.Num() ) + if( j == numImages ) { continue; } @@ -232,7 +233,7 @@ } else { - common->Printf( "%4i:", i ); + idLib::Printf( "%4i:", i ); image->Print(); } totalSize += image->StorageSize(); @@ -252,20 +253,20 @@ partialSize = 0; for( i = 0 ; i < count ; i++ ) { - common->Printf( "%4i:", sortedArray[i].index ); + idLib::Printf( "%4i:", sortedArray[i].index ); sortedArray[i].image->Print(); partialSize += sortedArray[i].image->StorageSize(); if( ( ( i + 1 ) % 10 ) == 0 ) { - common->Printf( "-------- %5.1f of %5.1f megs --------\n", - partialSize / ( 1024 * 1024.0 ), totalSize / ( 1024 * 1024.0 ) ); + idLib::Printf( "-------- %5.1f of %5.1f megs --------\n", + partialSize / ( 1024 * 1024.0 ), totalSize / ( 1024 * 1024.0 ) ); } } } - common->Printf( "%s", header ); - common->Printf( " %i images (%i total)\n", count, globalImages->images.Num() ); - common->Printf( " %5.1f total megabytes of images\n\n\n", totalSize / ( 1024 * 1024.0 ) ); + idLib::Printf( "%s", header ); + idLib::Printf( " %i images (%i total)\n", count, numImages ); + idLib::Printf( " %5.1f total megabytes of images\n\n\n", totalSize / ( 1024 * 1024.0 ) ); } /* @@ -280,7 +281,7 @@ { if( strlen( name ) >= MAX_IMAGE_NAME ) { - common->Error( "idImageManager::AllocImage: \"%s\" is too long\n", name ); + idLib::Error( "idImageManager::AllocImage: \"%s\" is too long\n", name ); } int hash = idStr( name ).FileNameHash(); @@ -356,62 +357,6 @@ return image; } - -/* -=============== -GetImageWithParameters -============== -*/ -idImage* idImageManager::GetImageWithParameters( const char* _name, textureFilter_t filter, textureRepeat_t repeat, textureUsage_t usage, cubeFiles_t cubeMap ) const -{ - if( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 ) - { - declManager->MediaPrint( "DEFAULTED\n" ); - return globalImages->defaultImage; - } - if( idStr::Icmpn( _name, "fonts", 5 ) == 0 || idStr::Icmpn( _name, "newfonts", 8 ) == 0 ) - { - usage = TD_FONT; - } - if( idStr::Icmpn( _name, "lights", 6 ) == 0 ) - { - usage = TD_LIGHT; - } - // strip any .tga file extensions from anywhere in the _name, including image program parameters - idStrStatic< MAX_OSPATH > name = _name; - name.Replace( ".tga", "" ); - name.BackSlashesToSlashes(); - int hash = name.FileNameHash(); - for( int i = imageHash.First( hash ); i != -1; i = imageHash.Next( i ) ) - { - idImage* image = images[i]; - if( name.Icmp( image->GetName() ) == 0 ) - { - // the built in's, like _white and _flat always match the other options - if( name[0] == '_' ) - { - return image; - } - if( image->cubeFiles != cubeMap ) - { - common->Error( "Image '%s' has been referenced with conflicting cube map states", _name ); - } - if( image->filter != filter || image->repeat != repeat ) - { - // we might want to have the system reset these parameters on every bind and - // share the image data - continue; - } - if( image->usage != usage ) - { - // If an image is used differently then we need 2 copies of it because usage affects the way it's compressed and swizzled - continue; - } - return image; - } - } - return NULL; -} /* =============== ImageFromFile @@ -460,7 +405,7 @@ } if( image->cubeFiles != cubeMap ) { - common->Error( "Image '%s' has been referenced with conflicting cube map states", _name ); + idLib::Error( "Image '%s' has been referenced with conflicting cube map states", _name ); } if( image->filter != filter || image->repeat != repeat ) @@ -628,13 +573,9 @@ */ void idImageManager::PurgeAllImages() { - int i; - idImage* image; - - for( i = 0; i < images.Num() ; i++ ) + for( int i = 0; i < images.Num() ; i++ ) { - image = images[i]; - image->PurgeImage(); + images[ i ]->PurgeImage(); } } @@ -645,9 +586,9 @@ */ void idImageManager::ReloadImages( bool all ) { - for( int i = 0 ; i < globalImages->images.Num() ; i++ ) + for( int i = 0 ; i < images.Num() ; i++ ) { - globalImages->images[ i ]->Reload( all ); + images[ i ]->Reload( all ); } } @@ -663,9 +604,9 @@ { if( args.Argc() != 2 ) { - common->Printf( "usage: combineCubeImages \n" ); - common->Printf( " combines basename[1-6][0001-9999].tga to basenameCM[0001-9999].tga\n" ); - common->Printf( " 1: forward 2:right 3:back 4:left 5:up 6:down\n" ); + idLib::Printf( "usage: combineCubeImages \n" ); + idLib::Printf( " combines basename[1-6][0001-9999].tga to basenameCM[0001-9999].tga\n" ); + idLib::Printf( " 1: forward 2:right 3:back 4:left 5:up 6:down\n" ); return; } @@ -683,12 +624,12 @@ { sprintf( filename, "%s%i%04i.tga", baseName.c_str(), orderRemap[side], frameNum ); - common->Printf( "reading %s\n", filename ); + idLib::Printf( "reading %s\n", filename ); R_LoadImage( filename, &pics[side], &width, &height, NULL, true ); if( !pics[side] ) { - common->Printf( "not found.\n" ); + idLib::Printf( "not found.\n" ); break; } @@ -736,7 +677,7 @@ } sprintf( filename, "%sCM%04i.tga", baseName.c_str(), frameNum ); - common->Printf( "writing %s\n", filename ); + idLib::Printf( "writing %s\n", filename ); R_WriteTGA( filename, combined, width, height * 6 ); } common->SetRefreshOnPrint( false ); @@ -744,33 +685,6 @@ /* =============== -UnbindAll -=============== -*/ -void idImageManager::UnbindAll() -{ - int oldTMU = backEnd.glState.currenttmu; - for( int i = 0; i < MAX_PROG_TEXTURE_PARMS; ++i ) - { - backEnd.glState.currenttmu = i; - BindNull(); - } - backEnd.glState.currenttmu = oldTMU; -} - -/* -=============== -BindNull -=============== -*/ -void idImageManager::BindNull() -{ - RENDERLOG_PRINTF( "BindNull()\n" ); - -} - -/* -=============== Init =============== */ @@ -870,7 +784,7 @@ if( preLoad_Images.GetBool() && manifest.NumResources() > 0 ) { // preload this levels images - common->Printf( "Preloading images...\n" ); + idLib::Printf( "Preloading images...\n" ); preloadingMapImages = mapPreload; int start = Sys_Milliseconds(); int numLoaded = 0; @@ -887,8 +801,8 @@ } //fileSystem->StopPreload(); int end = Sys_Milliseconds(); - common->Printf( "%05d images preloaded ( or were already loaded ) in %5.1f seconds\n", numLoaded, ( end - start ) * 0.001 ); - common->Printf( "----------------------------------------\n" ); + idLib::Printf( "%05d images preloaded ( or were already loaded ) in %5.1f seconds\n", numLoaded, ( end - start ) * 0.001 ); + idLib::Printf( "----------------------------------------\n" ); preloadingMapImages = false; } } @@ -932,35 +846,17 @@ { insideLevelLoad = false; - common->Printf( "----- idImageManager::EndLevelLoad -----\n" ); + idLib::Printf( "----- idImageManager::EndLevelLoad -----\n" ); int start = Sys_Milliseconds(); int loadCount = LoadLevelImages( true ); int end = Sys_Milliseconds(); - common->Printf( "%5i images loaded in %5.1f seconds\n", loadCount, ( end - start ) * 0.001 ); - common->Printf( "----------------------------------------\n" ); + idLib::Printf( "%5i images loaded in %5.1f seconds\n", loadCount, ( end - start ) * 0.001 ); + idLib::Printf( "----------------------------------------\n" ); //R_ListImages_f( idCmdArgs( "sorted sorted", false ) ); } /* -=============== -idImageManager::StartBuild -=============== -*/ -void idImageManager::StartBuild() -{ -} - -/* -=============== -idImageManager::FinishBuild -=============== -*/ -void idImageManager::FinishBuild( bool removeDups ) -{ -} - -/* =============== idImageManager::PrintMemInfo =============== diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ImageOpts.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ImageOpts.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ImageOpts.h 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ImageOpts.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,185 +0,0 @@ -/* -=========================================================================== - -Doom 3 BFG Edition GPL Source Code -Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. -Copyright (C) 2013-2014 Robert Beckebans - -This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). - -Doom 3 BFG Edition Source Code 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. - -Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . - -In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __IMAGEOPTS_H__ -#define __IMAGEOPTS_H__ - -enum textureType_t -{ - TT_DISABLED, - TT_2D, - TT_CUBIC, - // RB begin - TT_2D_ARRAY, - TT_2D_MULTISAMPLE - // RB end -}; - -/* -================================================ -The internal *Texture Format Types*, ::textureFormat_t, are: -================================================ -*/ -enum textureFormat_t -{ - FMT_NONE, - - //------------------------ - // Standard color image formats - //------------------------ - - FMT_RGBA8, // 32 bpp - FMT_XRGB8, // 32 bpp - - //------------------------ - // Alpha channel only - //------------------------ - - // Alpha ends up being the same as L8A8 in our current implementation, because straight - // alpha gives 0 for color, but we want 1. - FMT_ALPHA, - - //------------------------ - // Luminance replicates the value across RGB with a constant A of 255 - // Intensity replicates the value across RGBA - //------------------------ - - FMT_L8A8, // 16 bpp - FMT_LUM8, // 8 bpp - FMT_INT8, // 8 bpp - - //------------------------ - // Compressed texture formats - //------------------------ - - FMT_DXT1, // 4 bpp - FMT_DXT5, // 8 bpp - - //------------------------ - // Depth buffer formats - //------------------------ - - FMT_DEPTH, // 24 bpp - - //------------------------ - // - //------------------------ - - FMT_X16, // 16 bpp - FMT_Y16_X16, // 32 bpp - FMT_RGB565, // 16 bpp - - // RB: don't change above for legacy .bimage compatibility - FMT_ETC1_RGB8_OES, // 4 bpp - FMT_SHADOW_ARRAY, // 32 bpp * 6 - FMT_RGBA16F, // 64 bpp - FMT_RGBA32F, // 128 bpp - FMT_R32F, // 32 bpp - // RB end -}; - -int BitsForFormat( textureFormat_t format ); - -/* -================================================ -DXT5 color formats -================================================ -*/ -enum textureColor_t -{ - CFM_DEFAULT, // RGBA - CFM_NORMAL_DXT5, // XY format and use the fast DXT5 compressor - CFM_YCOCG_DXT5, // convert RGBA to CoCg_Y format - CFM_GREEN_ALPHA, // Copy the alpha channel to green - - // RB: don't change above for legacy .bimage compatibility - CFM_YCOCG_RGBA8, - // RB end -}; - -/* -================================================ -idImageOpts hold parameters for texture operations. -================================================ -*/ -class idImageOpts -{ -public: - idImageOpts(); - - bool operator==( const idImageOpts& opts ); - - //--------------------------------------------------- - // these determine the physical memory size and layout - //--------------------------------------------------- - - textureType_t textureType; - textureFormat_t format; - textureColor_t colorFormat; - int width; - int height; // not needed for cube maps - int numLevels; // if 0, will be 1 for NEAREST / LINEAR filters, otherwise based on size - bool gammaMips; // if true, mips will be generated with gamma correction - bool readback; // 360 specific - cpu reads back from this texture, so allocate with cached memory - // RB: for MSAA FBO targets - int msaaSamples; - // RB end -}; - -/* -======================== -idImageOpts::idImageOpts -======================== -*/ -ID_INLINE idImageOpts::idImageOpts() -{ - format = FMT_NONE; - colorFormat = CFM_DEFAULT; - width = 0; - height = 0; - numLevels = 0; - textureType = TT_2D; - gammaMips = false; - readback = false; - // RB begin - msaaSamples = 0; - // RB end -}; - -/* -======================== -idImageOpts::operator== -======================== -*/ -ID_INLINE bool idImageOpts::operator==( const idImageOpts& opts ) -{ - return ( memcmp( this, &opts, sizeof( *this ) ) == 0 ); -} - -#endif \ No newline at end of file diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image_process.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image_process.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image_process.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image_process.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" /* ================ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image_program.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image_program.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Image_program.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Image_program.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -56,7 +56,7 @@ // tr_imageprogram.c -#include "tr_local.h" +#include "RenderCommon.h" /* @@ -419,8 +419,7 @@ ID_TIME_T* timestamps, textureUsage_t* usage ) { idToken token; - float scale; - ID_TIME_T timestamp; + ID_TIME_T timestamp; src.ReadToken( &token ); @@ -454,7 +453,7 @@ src.ReadToken( &token ); AppendToken( token ); - scale = token.GetFloatValue(); + float scale = token.GetFloatValue(); // process it if( pic ) @@ -637,7 +636,7 @@ if( pic ) { int c; - c = *width** height * 4; + c = *width * *height * 4; for( i = 0 ; i < c ; i += 4 ) { ( *pic )[i + 1] = @@ -662,7 +661,7 @@ if( pic ) { int c; - c = *width** height * 4; + c = *width * *height * 4; for( i = 0 ; i < c ; i += 4 ) { ( *pic )[i + 3] = ( ( *pic )[i + 0] + ( *pic )[i + 1] + ( *pic )[i + 2] ) / 3; diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Interaction.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Interaction.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Interaction.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Interaction.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" /* =========================================================================== diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Material.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Material.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Material.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Material.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -32,7 +32,7 @@ #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" /* diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_beam.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_beam.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_beam.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_beam.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" /* diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -32,7 +32,7 @@ #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" #include "Model_ase.h" #include "Model_lwo.h" diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ModelDecal.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ModelDecal.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ModelDecal.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ModelDecal.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -31,7 +31,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" #include "../idlib/geometry/DrawVert_intrinsics.h" diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_liquid.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_liquid.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_liquid.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_liquid.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" #define LIQUID_MAX_SKIP_FRAMES 5 diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ModelManager.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ModelManager.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ModelManager.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ModelManager.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #include "precompiled.h" #include "Model_local.h" -#include "tr_local.h" // just for R_FreeWorldInteractions and R_CreateWorldInteractions +#include "RenderCommon.h" // just for R_FreeWorldInteractions and R_CreateWorldInteractions idCVar binaryLoadRenderModels( "binaryLoadRenderModels", "1", 0, "enable binary load/write of render models" ); idCVar preload_MapModels( "preload_MapModels", "1", CVAR_SYSTEM | CVAR_BOOL, "preload models during begin or end levelload" ); diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_md3.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_md3.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_md3.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_md3.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" #include "Model_md3.h" diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_md5.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_md5.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_md5.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_md5.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" #if defined(USE_INTRINSICS) diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ModelOverlay.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ModelOverlay.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ModelOverlay.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ModelOverlay.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -31,7 +31,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" #include "../idlib/geometry/DrawVert_intrinsics.h" diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_prt.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_prt.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_prt.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_prt.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" static const char* parametricParticle_SnapshotName = "_ParametricParticle_Snapshot_"; diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_sprite.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_sprite.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/Model_sprite.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/Model_sprite.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/gl_backend.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/gl_backend.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/gl_backend.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/gl_backend.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,632 +0,0 @@ -/* -=========================================================================== - -Doom 3 BFG Edition GPL Source Code -Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. -Copyright (C) 2013-2015 Robert Beckebans - -This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). - -Doom 3 BFG Edition Source Code 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. - -Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . - -In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#pragma hdrstop -#include "precompiled.h" - -#include "../tr_local.h" -#include "../../framework/Common_local.h" - -idCVar r_drawFlickerBox( "r_drawFlickerBox", "0", CVAR_RENDERER | CVAR_BOOL, "visual test for dropping frames" ); -idCVar stereoRender_warp( "stereoRender_warp", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "use the optical warping renderprog instead of stereoDeGhost" ); -idCVar stereoRender_warpStrength( "stereoRender_warpStrength", "1.45", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "amount of pre-distortion" ); - -idCVar stereoRender_warpCenterX( "stereoRender_warpCenterX", "0.5", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "center for left eye, right eye will be 1.0 - this" ); -idCVar stereoRender_warpCenterY( "stereoRender_warpCenterY", "0.5", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "center for both eyes" ); -idCVar stereoRender_warpParmZ( "stereoRender_warpParmZ", "0", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "development parm" ); -idCVar stereoRender_warpParmW( "stereoRender_warpParmW", "0", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "development parm" ); -idCVar stereoRender_warpTargetFraction( "stereoRender_warpTargetFraction", "1.0", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "fraction of half-width the through-lens view covers" ); - -idCVar r_showSwapBuffers( "r_showSwapBuffers", "0", CVAR_BOOL, "Show timings from GL_BlockingSwapBuffers" ); -idCVar r_syncEveryFrame( "r_syncEveryFrame", "1", CVAR_BOOL, "Don't let the GPU buffer execution past swapbuffers" ); - -static int swapIndex; // 0 or 1 into renderSync -static GLsync renderSync[2]; - -void GLimp_SwapBuffers(); -void RB_SetMVP( const idRenderMatrix& mvp ); - -/* -============================================================================ - -RENDER BACK END THREAD FUNCTIONS - -============================================================================ -*/ - -/* -============= -RB_DrawFlickerBox -============= -*/ -static void RB_DrawFlickerBox() -{ - if( !r_drawFlickerBox.GetBool() ) - { - return; - } - if( tr.frameCount & 1 ) - { - glClearColor( 1, 0, 0, 1 ); - } - else - { - glClearColor( 0, 1, 0, 1 ); - } - glScissor( 0, 0, 256, 256 ); - glClear( GL_COLOR_BUFFER_BIT ); -} - -/* -============= -RB_SetBuffer -============= -*/ -static void RB_SetBuffer( const void* data ) -{ - // see which draw buffer we want to render the frame to - - const setBufferCommand_t* cmd = ( const setBufferCommand_t* )data; - - RENDERLOG_PRINTF( "---------- RB_SetBuffer ---------- to buffer # %d\n", cmd->buffer ); - - GL_Scissor( 0, 0, tr.GetWidth(), tr.GetHeight() ); - - // clear screen for debugging - // automatically enable this with several other debug tools - // that might leave unrendered portions of the screen - if( r_clear.GetFloat() || idStr::Length( r_clear.GetString() ) != 1 || r_singleArea.GetBool() || r_showOverDraw.GetBool() ) - { - float c[3]; - if( sscanf( r_clear.GetString(), "%f %f %f", &c[0], &c[1], &c[2] ) == 3 ) - { - GL_Clear( true, false, false, 0, c[0], c[1], c[2], 1.0f, true ); - } - else if( r_clear.GetInteger() == 2 ) - { - GL_Clear( true, false, false, 0, 0.0f, 0.0f, 0.0f, 1.0f, true ); - } - else if( r_showOverDraw.GetBool() ) - { - GL_Clear( true, false, false, 0, 1.0f, 1.0f, 1.0f, 1.0f, true ); - } - else - { - GL_Clear( true, false, false, 0, 0.4f, 0.0f, 0.25f, 1.0f, true ); - } - } -} - -/* -============= -GL_BlockingSwapBuffers - -We want to exit this with the GPU idle, right at vsync -============= -*/ -const void GL_BlockingSwapBuffers() -{ - RENDERLOG_PRINTF( "***************** GL_BlockingSwapBuffers *****************\n\n\n" ); - - const int beforeFinish = Sys_Milliseconds(); - - if( !glConfig.syncAvailable ) - { - glFinish(); - } - - const int beforeSwap = Sys_Milliseconds(); - if( r_showSwapBuffers.GetBool() && beforeSwap - beforeFinish > 1 ) - { - common->Printf( "%i msec to glFinish\n", beforeSwap - beforeFinish ); - } - - GLimp_SwapBuffers(); - - const int beforeFence = Sys_Milliseconds(); - if( r_showSwapBuffers.GetBool() && beforeFence - beforeSwap > 1 ) - { - common->Printf( "%i msec to swapBuffers\n", beforeFence - beforeSwap ); - } - - if( glConfig.syncAvailable ) - { - swapIndex ^= 1; - - if( glIsSync( renderSync[swapIndex] ) ) - { - glDeleteSync( renderSync[swapIndex] ); - } - // draw something tiny to ensure the sync is after the swap - const int start = Sys_Milliseconds(); - glScissor( 0, 0, 1, 1 ); - glEnable( GL_SCISSOR_TEST ); - glClear( GL_COLOR_BUFFER_BIT ); - renderSync[swapIndex] = glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 ); - const int end = Sys_Milliseconds(); - if( r_showSwapBuffers.GetBool() && end - start > 1 ) - { - common->Printf( "%i msec to start fence\n", end - start ); - } - - GLsync syncToWaitOn; - if( r_syncEveryFrame.GetBool() ) - { - syncToWaitOn = renderSync[swapIndex]; - } - else - { - syncToWaitOn = renderSync[!swapIndex]; - } - - if( glIsSync( syncToWaitOn ) ) - { - for( GLenum r = GL_TIMEOUT_EXPIRED; r == GL_TIMEOUT_EXPIRED; ) - { - r = glClientWaitSync( syncToWaitOn, GL_SYNC_FLUSH_COMMANDS_BIT, 1000 * 1000 ); - } - } - } - - const int afterFence = Sys_Milliseconds(); - if( r_showSwapBuffers.GetBool() && afterFence - beforeFence > 1 ) - { - common->Printf( "%i msec to wait on fence\n", afterFence - beforeFence ); - } - - const int64 exitBlockTime = Sys_Microseconds(); - - static int64 prevBlockTime; - if( r_showSwapBuffers.GetBool() && prevBlockTime ) - { - const int delta = ( int )( exitBlockTime - prevBlockTime ); - common->Printf( "blockToBlock: %i\n", delta ); - } - prevBlockTime = exitBlockTime; -} - -/* -==================== -R_MakeStereoRenderImage -==================== -*/ -static void R_MakeStereoRenderImage( idImage* image ) -{ - idImageOpts opts; - opts.width = renderSystem->GetWidth(); - opts.height = renderSystem->GetHeight(); - opts.numLevels = 1; - opts.format = FMT_RGBA8; - image->AllocImage( opts, TF_LINEAR, TR_CLAMP ); -} - -/* -==================== -RB_StereoRenderExecuteBackEndCommands - -Renders the draw list twice, with slight modifications for left eye / right eye -==================== -*/ -void RB_StereoRenderExecuteBackEndCommands( const emptyCommand_t* const allCmds ) -{ - uint64 backEndStartTime = Sys_Microseconds(); - - // If we are in a monoscopic context, this draws to the only buffer, and is - // the same as GL_BACK. In a quad-buffer stereo context, this is necessary - // to prevent GL from forcing the rendering to go to both BACK_LEFT and - // BACK_RIGHT at a performance penalty. - // To allow stereo deghost processing, the views have to be copied to separate - // textures anyway, so there isn't any benefit to rendering to BACK_RIGHT for - // that eye. - glDrawBuffer( GL_BACK_LEFT ); - - // create the stereoRenderImage if we haven't already - static idImage* stereoRenderImages[2]; - for( int i = 0; i < 2; i++ ) - { - if( stereoRenderImages[i] == NULL ) - { - stereoRenderImages[i] = globalImages->ImageFromFunction( va( "_stereoRender%i", i ), R_MakeStereoRenderImage ); - } - - // resize the stereo render image if the main window has changed size - if( stereoRenderImages[i]->GetUploadWidth() != renderSystem->GetWidth() || - stereoRenderImages[i]->GetUploadHeight() != renderSystem->GetHeight() ) - { - stereoRenderImages[i]->Resize( renderSystem->GetWidth(), renderSystem->GetHeight() ); - } - } - - // In stereoRender mode, the front end has generated two RC_DRAW_VIEW commands - // with slightly different origins for each eye. - - // TODO: only do the copy after the final view has been rendered, not mirror subviews? - - // Render the 3D draw views from the screen origin so all the screen relative - // texture mapping works properly, then copy the portion we are going to use - // off to a texture. - bool foundEye[2] = { false, false }; - - for( int stereoEye = 1; stereoEye >= -1; stereoEye -= 2 ) - { - // set up the target texture we will draw to - const int targetEye = ( stereoEye == 1 ) ? 1 : 0; - - // Set the back end into a known default state to fix any stale render state issues - GL_SetDefaultState(); - renderProgManager.Unbind(); - renderProgManager.ZeroUniforms(); - - for( const emptyCommand_t* cmds = allCmds; cmds != NULL; cmds = ( const emptyCommand_t* )cmds->next ) - { - switch( cmds->commandId ) - { - case RC_NOP: - break; - case RC_DRAW_VIEW_GUI: - case RC_DRAW_VIEW_3D: - { - const drawSurfsCommand_t* const dsc = ( const drawSurfsCommand_t* )cmds; - const viewDef_t& eyeViewDef = *dsc->viewDef; - - if( eyeViewDef.renderView.viewEyeBuffer && eyeViewDef.renderView.viewEyeBuffer != stereoEye ) - { - // this is the render view for the other eye - continue; - } - - foundEye[ targetEye ] = true; - RB_DrawView( dsc, stereoEye ); - if( cmds->commandId == RC_DRAW_VIEW_GUI ) - { - } - } - break; - case RC_SET_BUFFER: - RB_SetBuffer( cmds ); - break; - case RC_COPY_RENDER: - RB_CopyRender( cmds ); - break; - case RC_POST_PROCESS: - { - postProcessCommand_t* cmd = ( postProcessCommand_t* )cmds; - if( cmd->viewDef->renderView.viewEyeBuffer != stereoEye ) - { - break; - } - RB_PostProcess( cmds ); - } - break; - default: - common->Error( "RB_ExecuteBackEndCommands: bad commandId" ); - break; - } - } - - // copy to the target - stereoRenderImages[ targetEye ]->CopyFramebuffer( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() ); - } - - // perform the final compositing / warping / deghosting to the actual framebuffer(s) - assert( foundEye[0] && foundEye[1] ); - - GL_SetDefaultState(); - - RB_SetMVP( renderMatrix_identity ); - - // If we are in quad-buffer pixel format but testing another 3D mode, - // make sure we draw to both eyes. This is likely to be sub-optimal - // performance on most cards and drivers, but it is better than getting - // a confusing, half-ghosted view. - if( renderSystem->GetStereo3DMode() != STEREO3D_QUAD_BUFFER ) - { - glDrawBuffer( GL_BACK ); - } - - GL_State( GLS_DEPTHFUNC_ALWAYS ); - GL_Cull( CT_TWO_SIDED ); - - // We just want to do a quad pass - so make sure we disable any texgen and - // set the texture matrix to the identity so we don't get anomalies from - // any stale uniform data being present from a previous draw call - const float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; - const float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f }; - renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_S, texS ); - renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_T, texT ); - - // disable any texgen - const float texGenEnabled[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - renderProgManager.SetRenderParm( RENDERPARM_TEXGEN_0_ENABLED, texGenEnabled ); - - renderProgManager.BindShader_Texture(); - GL_Color( 1, 1, 1, 1 ); - - switch( renderSystem->GetStereo3DMode() ) - { - case STEREO3D_QUAD_BUFFER: - glDrawBuffer( GL_BACK_RIGHT ); - GL_SelectTexture( 0 ); - stereoRenderImages[1]->Bind(); - GL_SelectTexture( 1 ); - stereoRenderImages[0]->Bind(); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - glDrawBuffer( GL_BACK_LEFT ); - GL_SelectTexture( 1 ); - stereoRenderImages[1]->Bind(); - GL_SelectTexture( 0 ); - stereoRenderImages[0]->Bind(); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - break; - case STEREO3D_HDMI_720: - // HDMI 720P 3D - GL_SelectTexture( 0 ); - stereoRenderImages[1]->Bind(); - GL_SelectTexture( 1 ); - stereoRenderImages[0]->Bind(); - GL_ViewportAndScissor( 0, 0, 1280, 720 ); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - GL_SelectTexture( 0 ); - stereoRenderImages[0]->Bind(); - GL_SelectTexture( 1 ); - stereoRenderImages[1]->Bind(); - GL_ViewportAndScissor( 0, 750, 1280, 720 ); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - // force the HDMI 720P 3D guard band to a constant color - glScissor( 0, 720, 1280, 30 ); - glClear( GL_COLOR_BUFFER_BIT ); - break; - default: - case STEREO3D_SIDE_BY_SIDE: - if( stereoRender_warp.GetBool() ) - { - // this is the Rift warp - // renderSystem->GetWidth() / GetHeight() have returned equal values (640 for initial Rift) - // and we are going to warp them onto a symetric square region of each half of the screen - - renderProgManager.BindShader_StereoWarp(); - - // clear the entire screen to black - // we could be smart and only clear the areas we aren't going to draw on, but - // clears are fast... - glScissor( 0, 0, glConfig.nativeScreenWidth, glConfig.nativeScreenHeight ); - glClearColor( 0, 0, 0, 0 ); - glClear( GL_COLOR_BUFFER_BIT ); - - // the size of the box that will get the warped pixels - // With the 7" displays, this will be less than half the screen width - const int pixelDimensions = ( glConfig.nativeScreenWidth >> 1 ) * stereoRender_warpTargetFraction.GetFloat(); - - // Always scissor to the half-screen boundary, but the viewports - // might cross that boundary if the lenses can be adjusted closer - // together. - glViewport( ( glConfig.nativeScreenWidth >> 1 ) - pixelDimensions, - ( glConfig.nativeScreenHeight >> 1 ) - ( pixelDimensions >> 1 ), - pixelDimensions, pixelDimensions ); - glScissor( 0, 0, glConfig.nativeScreenWidth >> 1, glConfig.nativeScreenHeight ); - - idVec4 color( stereoRender_warpCenterX.GetFloat(), stereoRender_warpCenterY.GetFloat(), stereoRender_warpParmZ.GetFloat(), stereoRender_warpParmW.GetFloat() ); - // don't use GL_Color(), because we don't want to clamp - renderProgManager.SetRenderParm( RENDERPARM_COLOR, color.ToFloatPtr() ); - - GL_SelectTexture( 0 ); - stereoRenderImages[0]->Bind(); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - idVec4 color2( stereoRender_warpCenterX.GetFloat(), stereoRender_warpCenterY.GetFloat(), stereoRender_warpParmZ.GetFloat(), stereoRender_warpParmW.GetFloat() ); - // don't use GL_Color(), because we don't want to clamp - renderProgManager.SetRenderParm( RENDERPARM_COLOR, color2.ToFloatPtr() ); - - glViewport( ( glConfig.nativeScreenWidth >> 1 ), - ( glConfig.nativeScreenHeight >> 1 ) - ( pixelDimensions >> 1 ), - pixelDimensions, pixelDimensions ); - glScissor( glConfig.nativeScreenWidth >> 1, 0, glConfig.nativeScreenWidth >> 1, glConfig.nativeScreenHeight ); - - GL_SelectTexture( 0 ); - stereoRenderImages[1]->Bind(); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - break; - } - // a non-warped side-by-side-uncompressed (dual input cable) is rendered - // just like STEREO3D_SIDE_BY_SIDE_COMPRESSED, so fall through. - case STEREO3D_SIDE_BY_SIDE_COMPRESSED: - GL_SelectTexture( 0 ); - stereoRenderImages[0]->Bind(); - GL_SelectTexture( 1 ); - stereoRenderImages[1]->Bind(); - GL_ViewportAndScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() ); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - GL_SelectTexture( 0 ); - stereoRenderImages[1]->Bind(); - GL_SelectTexture( 1 ); - stereoRenderImages[0]->Bind(); - GL_ViewportAndScissor( renderSystem->GetWidth(), 0, renderSystem->GetWidth(), renderSystem->GetHeight() ); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - break; - - case STEREO3D_TOP_AND_BOTTOM_COMPRESSED: - GL_SelectTexture( 1 ); - stereoRenderImages[0]->Bind(); - GL_SelectTexture( 0 ); - stereoRenderImages[1]->Bind(); - GL_ViewportAndScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() ); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - GL_SelectTexture( 1 ); - stereoRenderImages[1]->Bind(); - GL_SelectTexture( 0 ); - stereoRenderImages[0]->Bind(); - GL_ViewportAndScissor( 0, renderSystem->GetHeight(), renderSystem->GetWidth(), renderSystem->GetHeight() ); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - break; - - case STEREO3D_INTERLACED: - // every other scanline - GL_SelectTexture( 0 ); - stereoRenderImages[0]->Bind(); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - - GL_SelectTexture( 1 ); - stereoRenderImages[1]->Bind(); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - - GL_ViewportAndScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() * 2 ); - renderProgManager.BindShader_StereoInterlace(); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - GL_SelectTexture( 0 ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - - GL_SelectTexture( 1 ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - - break; - } - - // debug tool - RB_DrawFlickerBox(); - - // make sure the drawing is actually started - glFlush(); - - // we may choose to sync to the swapbuffers before the next frame - - // stop rendering on this thread - uint64 backEndFinishTime = Sys_Microseconds(); - backEnd.pc.totalMicroSec = backEndFinishTime - backEndStartTime; -} - -/* -==================== -RB_ExecuteBackEndCommands - -This function will be called syncronously if running without -smp extensions, or asyncronously by another thread. -==================== -*/ -void RB_ExecuteBackEndCommands( const emptyCommand_t* cmds ) -{ - // r_debugRenderToTexture - int c_draw3d = 0; - int c_draw2d = 0; - int c_setBuffers = 0; - int c_copyRenders = 0; - - resolutionScale.SetCurrentGPUFrameTime( commonLocal.GetRendererGPUMicroseconds() ); - - renderLog.StartFrame(); - - if( cmds->commandId == RC_NOP && !cmds->next ) - { - return; - } - - if( renderSystem->GetStereo3DMode() != STEREO3D_OFF ) - { - RB_StereoRenderExecuteBackEndCommands( cmds ); - renderLog.EndFrame(); - return; - } - - uint64 backEndStartTime = Sys_Microseconds(); - - // needed for editor rendering - GL_SetDefaultState(); - - // If we have a stereo pixel format, this will draw to both - // the back left and back right buffers, which will have a - // performance penalty. - glDrawBuffer( GL_BACK ); - - for( ; cmds != NULL; cmds = ( const emptyCommand_t* )cmds->next ) - { - switch( cmds->commandId ) - { - case RC_NOP: - break; - case RC_DRAW_VIEW_3D: - case RC_DRAW_VIEW_GUI: - RB_DrawView( cmds, 0 ); - if( ( ( const drawSurfsCommand_t* )cmds )->viewDef->viewEntitys ) - { - c_draw3d++; - } - else - { - c_draw2d++; - } - break; - case RC_SET_BUFFER: - //RB_SetBuffer( cmds ); - c_setBuffers++; - break; - case RC_COPY_RENDER: - RB_CopyRender( cmds ); - c_copyRenders++; - break; - case RC_POST_PROCESS: - RB_PostProcess( cmds ); - break; - default: - common->Error( "RB_ExecuteBackEndCommands: bad commandId" ); - break; - } - } - - RB_DrawFlickerBox(); - - // Fix for the steam overlay not showing up while in game without Shell/Debug/Console/Menu also rendering - glColorMask( 1, 1, 1, 1 ); - - glFlush(); - - // stop rendering on this thread - uint64 backEndFinishTime = Sys_Microseconds(); - backEnd.pc.totalMicroSec = backEndFinishTime - backEndStartTime; - - if( r_debugRenderToTexture.GetInteger() == 1 ) - { - common->Printf( "3d: %i, 2d: %i, SetBuf: %i, CpyRenders: %i, CpyFrameBuf: %i\n", c_draw3d, c_draw2d, c_setBuffers, c_copyRenders, backEnd.pc.c_copyFrameBuffer ); - backEnd.pc.c_copyFrameBuffer = 0; - } - renderLog.EndFrame(); -} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/gl_GraphicsAPIWrapper.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/gl_GraphicsAPIWrapper.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/gl_GraphicsAPIWrapper.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/gl_GraphicsAPIWrapper.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,727 +0,0 @@ -/* -=========================================================================== - -Doom 3 BFG Edition GPL Source Code -Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. -Copyright (C) 2013-2014 Robert Beckebans - -This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). - -Doom 3 BFG Edition Source Code 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. - -Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . - -In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#pragma hdrstop -#include "precompiled.h" - -#include "../tr_local.h" - -/* -==================== -GL_SelectTexture -==================== -*/ -void GL_SelectTexture( int unit ) -{ - if( backEnd.glState.currenttmu == unit ) - { - return; - } - - if( unit < 0 || unit >= glConfig.maxTextureImageUnits ) - { - common->Warning( "GL_SelectTexture: unit = %i", unit ); - return; - } - - RENDERLOG_PRINTF( "GL_SelectTexture( %i );\n", unit ); - - backEnd.glState.currenttmu = unit; -} - -/* -==================== -GL_Cull - -This handles the flipping needed when the view being -rendered is a mirored view. -==================== -*/ -void GL_Cull( int cullType ) -{ - if( backEnd.glState.faceCulling == cullType ) - { - return; - } - - if( cullType == CT_TWO_SIDED ) - { - glDisable( GL_CULL_FACE ); - } - else - { - if( backEnd.glState.faceCulling == CT_TWO_SIDED ) - { - glEnable( GL_CULL_FACE ); - } - - if( cullType == CT_BACK_SIDED ) - { - if( backEnd.viewDef->isMirror ) - { - glCullFace( GL_FRONT ); - } - else - { - glCullFace( GL_BACK ); - } - } - else - { - if( backEnd.viewDef->isMirror ) - { - glCullFace( GL_BACK ); - } - else - { - glCullFace( GL_FRONT ); - } - } - } - - backEnd.glState.faceCulling = cullType; -} - -/* -==================== -GL_Scissor -==================== -*/ -void GL_Scissor( int x /* left*/, int y /* bottom */, int w, int h ) -{ - glScissor( x, y, w, h ); -} - -/* -==================== -GL_Viewport -==================== -*/ -void GL_Viewport( int x /* left */, int y /* bottom */, int w, int h ) -{ - glViewport( x, y, w, h ); -} - -/* -==================== -GL_PolygonOffset -==================== -*/ -void GL_PolygonOffset( float scale, float bias ) -{ - backEnd.glState.polyOfsScale = scale; - backEnd.glState.polyOfsBias = bias; - if( backEnd.glState.glStateBits & GLS_POLYGON_OFFSET ) - { - glPolygonOffset( scale, bias ); - } -} - -/* -======================== -GL_DepthBoundsTest -======================== -*/ -void GL_DepthBoundsTest( const float zmin, const float zmax ) -{ - if( !glConfig.depthBoundsTestAvailable || zmin > zmax ) - { - return; - } - - if( zmin == 0.0f && zmax == 0.0f ) - { - glDisable( GL_DEPTH_BOUNDS_TEST_EXT ); - } - else - { - glEnable( GL_DEPTH_BOUNDS_TEST_EXT ); - glDepthBoundsEXT( zmin, zmax ); - } -} - -/* -======================== -GL_StartDepthPass -======================== -*/ -void GL_StartDepthPass( const idScreenRect& rect ) -{ -} - -/* -======================== -GL_FinishDepthPass -======================== -*/ -void GL_FinishDepthPass() -{ -} - -/* -======================== -GL_GetDepthPassRect -======================== -*/ -void GL_GetDepthPassRect( idScreenRect& rect ) -{ - rect.Clear(); -} - -/* -==================== -GL_Color -==================== -*/ -/* -void GL_Color( float* color ) -{ - if( color == NULL ) - { - return; - } - GL_Color( color[0], color[1], color[2], color[3] ); -} -*/ - -// RB begin -void GL_Color( const idVec3& color ) -{ - GL_Color( color[0], color[1], color[2], 1.0f ); -} - -void GL_Color( const idVec4& color ) -{ - GL_Color( color[0], color[1], color[2], color[3] ); -} -// RB end - -/* -==================== -GL_Color -==================== -*/ -void GL_Color( float r, float g, float b ) -{ - GL_Color( r, g, b, 1.0f ); -} - -/* -==================== -GL_Color -==================== -*/ -void GL_Color( float r, float g, float b, float a ) -{ - float parm[4]; - parm[0] = idMath::ClampFloat( 0.0f, 1.0f, r ); - parm[1] = idMath::ClampFloat( 0.0f, 1.0f, g ); - parm[2] = idMath::ClampFloat( 0.0f, 1.0f, b ); - parm[3] = idMath::ClampFloat( 0.0f, 1.0f, a ); - renderProgManager.SetRenderParm( RENDERPARM_COLOR, parm ); -} - -/* -======================== -GL_Clear -======================== -*/ -void GL_Clear( bool color, bool depth, bool stencil, byte stencilValue, float r, float g, float b, float a, bool clearHDR ) -{ - int clearFlags = 0; - if( color ) - { - glClearColor( r, g, b, a ); - clearFlags |= GL_COLOR_BUFFER_BIT; - } - if( depth ) - { - clearFlags |= GL_DEPTH_BUFFER_BIT; - } - if( stencil ) - { - glClearStencil( stencilValue ); - clearFlags |= GL_STENCIL_BUFFER_BIT; - } - glClear( clearFlags ); - - // RB begin - if( r_useHDR.GetBool() && clearHDR && globalFramebuffers.hdrFBO != NULL ) - { - bool isDefaultFramebufferActive = Framebuffer::IsDefaultFramebufferActive(); - - globalFramebuffers.hdrFBO->Bind(); - glClear( clearFlags ); - - if( isDefaultFramebufferActive ) - { - Framebuffer::Unbind(); - } - } - // RB end -} - -/* -======================== -GL_SetDefaultState - -This should initialize all GL state that any part of the entire program -may touch, including the editor. -======================== -*/ -void GL_SetDefaultState() -{ - RENDERLOG_PRINTF( "--- GL_SetDefaultState ---\n" ); - - glClearDepth( 1.0f ); - - // make sure our GL state vector is set correctly - memset( &backEnd.glState, 0, sizeof( backEnd.glState ) ); - GL_State( 0, true ); - - // RB begin - Framebuffer::Unbind(); - // RB end - - // These are changed by GL_Cull - glCullFace( GL_FRONT_AND_BACK ); - glEnable( GL_CULL_FACE ); - - // These are changed by GL_State - glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); - glBlendFunc( GL_ONE, GL_ZERO ); - glDepthMask( GL_TRUE ); - glDepthFunc( GL_LESS ); - glDisable( GL_STENCIL_TEST ); - glDisable( GL_POLYGON_OFFSET_FILL ); - glDisable( GL_POLYGON_OFFSET_LINE ); - glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - - // These should never be changed - // DG: deprecated in opengl 3.2 and not needed because we don't do fixed function pipeline - // glShadeModel( GL_SMOOTH ); - // DG end - glEnable( GL_DEPTH_TEST ); - glEnable( GL_BLEND ); - glEnable( GL_SCISSOR_TEST ); - glDrawBuffer( GL_BACK ); - glReadBuffer( GL_BACK ); - - if( r_useScissor.GetBool() ) - { - glScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() ); - } - - // RB: don't keep renderprogs that were enabled during level load - renderProgManager.Unbind(); - // RB end -} - -/* -==================== -GL_State - -This routine is responsible for setting the most commonly changed state -==================== -*/ -void GL_State( uint64 stateBits, bool forceGlState ) -{ - uint64 diff = stateBits ^ backEnd.glState.glStateBits; - - if( !r_useStateCaching.GetBool() || forceGlState ) - { - // make sure everything is set all the time, so we - // can see if our delta checking is screwing up - diff = 0xFFFFFFFFFFFFFFFF; - } - else if( diff == 0 ) - { - return; - } - - // - // check depthFunc bits - // - if( diff & GLS_DEPTHFUNC_BITS ) - { - switch( stateBits & GLS_DEPTHFUNC_BITS ) - { - case GLS_DEPTHFUNC_EQUAL: - glDepthFunc( GL_EQUAL ); - break; - case GLS_DEPTHFUNC_ALWAYS: - glDepthFunc( GL_ALWAYS ); - break; - case GLS_DEPTHFUNC_LESS: - glDepthFunc( GL_LEQUAL ); - break; - case GLS_DEPTHFUNC_GREATER: - glDepthFunc( GL_GEQUAL ); - break; - } - } - - // - // check blend bits - // - if( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) - { - GLenum srcFactor = GL_ONE; - GLenum dstFactor = GL_ZERO; - - switch( stateBits & GLS_SRCBLEND_BITS ) - { - case GLS_SRCBLEND_ZERO: - srcFactor = GL_ZERO; - break; - case GLS_SRCBLEND_ONE: - srcFactor = GL_ONE; - break; - case GLS_SRCBLEND_DST_COLOR: - srcFactor = GL_DST_COLOR; - break; - case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: - srcFactor = GL_ONE_MINUS_DST_COLOR; - break; - case GLS_SRCBLEND_SRC_ALPHA: - srcFactor = GL_SRC_ALPHA; - break; - case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: - srcFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - case GLS_SRCBLEND_DST_ALPHA: - srcFactor = GL_DST_ALPHA; - break; - case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: - srcFactor = GL_ONE_MINUS_DST_ALPHA; - break; - default: - assert( !"GL_State: invalid src blend state bits\n" ); - break; - } - - switch( stateBits & GLS_DSTBLEND_BITS ) - { - case GLS_DSTBLEND_ZERO: - dstFactor = GL_ZERO; - break; - case GLS_DSTBLEND_ONE: - dstFactor = GL_ONE; - break; - case GLS_DSTBLEND_SRC_COLOR: - dstFactor = GL_SRC_COLOR; - break; - case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: - dstFactor = GL_ONE_MINUS_SRC_COLOR; - break; - case GLS_DSTBLEND_SRC_ALPHA: - dstFactor = GL_SRC_ALPHA; - break; - case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: - dstFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - case GLS_DSTBLEND_DST_ALPHA: - dstFactor = GL_DST_ALPHA; - break; - case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: - dstFactor = GL_ONE_MINUS_DST_ALPHA; - break; - default: - assert( !"GL_State: invalid dst blend state bits\n" ); - break; - } - - // Only actually update GL's blend func if blending is enabled. - if( srcFactor == GL_ONE && dstFactor == GL_ZERO ) - { - glDisable( GL_BLEND ); - } - else - { - glEnable( GL_BLEND ); - glBlendFunc( srcFactor, dstFactor ); - } - } - - // - // check depthmask - // - if( diff & GLS_DEPTHMASK ) - { - if( stateBits & GLS_DEPTHMASK ) - { - glDepthMask( GL_FALSE ); - } - else - { - glDepthMask( GL_TRUE ); - } - } - - // - // check colormask - // - if( diff & ( GLS_REDMASK | GLS_GREENMASK | GLS_BLUEMASK | GLS_ALPHAMASK ) ) - { - GLboolean r = ( stateBits & GLS_REDMASK ) ? GL_FALSE : GL_TRUE; - GLboolean g = ( stateBits & GLS_GREENMASK ) ? GL_FALSE : GL_TRUE; - GLboolean b = ( stateBits & GLS_BLUEMASK ) ? GL_FALSE : GL_TRUE; - GLboolean a = ( stateBits & GLS_ALPHAMASK ) ? GL_FALSE : GL_TRUE; - glColorMask( r, g, b, a ); - } - - // - // fill/line mode - // - if( diff & GLS_POLYMODE_LINE ) - { - if( stateBits & GLS_POLYMODE_LINE ) - { - glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); - } - else - { - glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - } - } - - // - // polygon offset - // - if( diff & GLS_POLYGON_OFFSET ) - { - if( stateBits & GLS_POLYGON_OFFSET ) - { - glPolygonOffset( backEnd.glState.polyOfsScale, backEnd.glState.polyOfsBias ); - glEnable( GL_POLYGON_OFFSET_FILL ); - glEnable( GL_POLYGON_OFFSET_LINE ); - } - else - { - glDisable( GL_POLYGON_OFFSET_FILL ); - glDisable( GL_POLYGON_OFFSET_LINE ); - } - } - -#if !defined( USE_CORE_PROFILE ) - // - // alpha test - // - if( diff & ( GLS_ALPHATEST_FUNC_BITS | GLS_ALPHATEST_FUNC_REF_BITS ) ) - { - if( ( stateBits & GLS_ALPHATEST_FUNC_BITS ) != 0 ) - { - glEnable( GL_ALPHA_TEST ); - - GLenum func = GL_ALWAYS; - switch( stateBits & GLS_ALPHATEST_FUNC_BITS ) - { - case GLS_ALPHATEST_FUNC_LESS: - func = GL_LESS; - break; - case GLS_ALPHATEST_FUNC_EQUAL: - func = GL_EQUAL; - break; - case GLS_ALPHATEST_FUNC_GREATER: - func = GL_GEQUAL; - break; - default: - assert( false ); - } - GLclampf ref = ( ( stateBits & GLS_ALPHATEST_FUNC_REF_BITS ) >> GLS_ALPHATEST_FUNC_REF_SHIFT ) / ( float )0xFF; - glAlphaFunc( func, ref ); - } - else - { - glDisable( GL_ALPHA_TEST ); - } - } -#endif - - // - // stencil - // - if( diff & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS ) ) - { - if( ( stateBits & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS ) ) != 0 ) - { - glEnable( GL_STENCIL_TEST ); - } - else - { - glDisable( GL_STENCIL_TEST ); - } - } - if( diff & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_FUNC_REF_BITS | GLS_STENCIL_FUNC_MASK_BITS ) ) - { - GLuint ref = GLuint( ( stateBits & GLS_STENCIL_FUNC_REF_BITS ) >> GLS_STENCIL_FUNC_REF_SHIFT ); - GLuint mask = GLuint( ( stateBits & GLS_STENCIL_FUNC_MASK_BITS ) >> GLS_STENCIL_FUNC_MASK_SHIFT ); - GLenum func = 0; - - switch( stateBits & GLS_STENCIL_FUNC_BITS ) - { - case GLS_STENCIL_FUNC_NEVER: - func = GL_NEVER; - break; - case GLS_STENCIL_FUNC_LESS: - func = GL_LESS; - break; - case GLS_STENCIL_FUNC_EQUAL: - func = GL_EQUAL; - break; - case GLS_STENCIL_FUNC_LEQUAL: - func = GL_LEQUAL; - break; - case GLS_STENCIL_FUNC_GREATER: - func = GL_GREATER; - break; - case GLS_STENCIL_FUNC_NOTEQUAL: - func = GL_NOTEQUAL; - break; - case GLS_STENCIL_FUNC_GEQUAL: - func = GL_GEQUAL; - break; - case GLS_STENCIL_FUNC_ALWAYS: - func = GL_ALWAYS; - break; - } - glStencilFunc( func, ref, mask ); - } - if( diff & ( GLS_STENCIL_OP_FAIL_BITS | GLS_STENCIL_OP_ZFAIL_BITS | GLS_STENCIL_OP_PASS_BITS ) ) - { - GLenum sFail = 0; - GLenum zFail = 0; - GLenum pass = 0; - - switch( stateBits & GLS_STENCIL_OP_FAIL_BITS ) - { - case GLS_STENCIL_OP_FAIL_KEEP: - sFail = GL_KEEP; - break; - case GLS_STENCIL_OP_FAIL_ZERO: - sFail = GL_ZERO; - break; - case GLS_STENCIL_OP_FAIL_REPLACE: - sFail = GL_REPLACE; - break; - case GLS_STENCIL_OP_FAIL_INCR: - sFail = GL_INCR; - break; - case GLS_STENCIL_OP_FAIL_DECR: - sFail = GL_DECR; - break; - case GLS_STENCIL_OP_FAIL_INVERT: - sFail = GL_INVERT; - break; - case GLS_STENCIL_OP_FAIL_INCR_WRAP: - sFail = GL_INCR_WRAP; - break; - case GLS_STENCIL_OP_FAIL_DECR_WRAP: - sFail = GL_DECR_WRAP; - break; - } - switch( stateBits & GLS_STENCIL_OP_ZFAIL_BITS ) - { - case GLS_STENCIL_OP_ZFAIL_KEEP: - zFail = GL_KEEP; - break; - case GLS_STENCIL_OP_ZFAIL_ZERO: - zFail = GL_ZERO; - break; - case GLS_STENCIL_OP_ZFAIL_REPLACE: - zFail = GL_REPLACE; - break; - case GLS_STENCIL_OP_ZFAIL_INCR: - zFail = GL_INCR; - break; - case GLS_STENCIL_OP_ZFAIL_DECR: - zFail = GL_DECR; - break; - case GLS_STENCIL_OP_ZFAIL_INVERT: - zFail = GL_INVERT; - break; - case GLS_STENCIL_OP_ZFAIL_INCR_WRAP: - zFail = GL_INCR_WRAP; - break; - case GLS_STENCIL_OP_ZFAIL_DECR_WRAP: - zFail = GL_DECR_WRAP; - break; - } - switch( stateBits & GLS_STENCIL_OP_PASS_BITS ) - { - case GLS_STENCIL_OP_PASS_KEEP: - pass = GL_KEEP; - break; - case GLS_STENCIL_OP_PASS_ZERO: - pass = GL_ZERO; - break; - case GLS_STENCIL_OP_PASS_REPLACE: - pass = GL_REPLACE; - break; - case GLS_STENCIL_OP_PASS_INCR: - pass = GL_INCR; - break; - case GLS_STENCIL_OP_PASS_DECR: - pass = GL_DECR; - break; - case GLS_STENCIL_OP_PASS_INVERT: - pass = GL_INVERT; - break; - case GLS_STENCIL_OP_PASS_INCR_WRAP: - pass = GL_INCR_WRAP; - break; - case GLS_STENCIL_OP_PASS_DECR_WRAP: - pass = GL_DECR_WRAP; - break; - } - glStencilOp( sFail, zFail, pass ); - } - - backEnd.glState.glStateBits = stateBits; -} - -/* -================= -GL_GetCurrentState -================= -*/ -uint64 GL_GetCurrentState() -{ - return backEnd.glState.glStateBits; -} - -/* -======================== -GL_GetCurrentStateMinusStencil -======================== -*/ -uint64 GL_GetCurrentStateMinusStencil() -{ - return GL_GetCurrentState() & ~( GLS_STENCIL_OP_BITS | GLS_STENCIL_FUNC_BITS | GLS_STENCIL_FUNC_REF_BITS | GLS_STENCIL_FUNC_MASK_BITS ); -} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/gl_Image.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/gl_Image.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/gl_Image.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/gl_Image.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,664 +0,0 @@ -/* -=========================================================================== - -Doom 3 BFG Edition GPL Source Code -Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. -Copyright (C) 2013-2016 Robert Beckebans - -This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). - -Doom 3 BFG Edition Source Code 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. - -Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . - -In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ -#pragma hdrstop -#include "precompiled.h" - -/* -================================================================================================ -Contains the Image implementation for OpenGL. -================================================================================================ -*/ - -#include "../tr_local.h" - -/* -======================== -idImage::SubImageUpload -======================== -*/ -void idImage::SubImageUpload( int mipLevel, int x, int y, int z, int width, int height, const void* pic, int pixelPitch ) const -{ - assert( x >= 0 && y >= 0 && mipLevel >= 0 && width >= 0 && height >= 0 && mipLevel < opts.numLevels ); - - int compressedSize = 0; - - if( IsCompressed() ) - { - assert( !( x & 3 ) && !( y & 3 ) ); - - // compressed size may be larger than the dimensions due to padding to quads - int quadW = ( width + 3 ) & ~3; - int quadH = ( height + 3 ) & ~3; - compressedSize = quadW * quadH * BitsForFormat( opts.format ) / 8; - - int padW = ( opts.width + 3 ) & ~3; - int padH = ( opts.height + 3 ) & ~3; - - assert( x + width <= padW && y + height <= padH ); - // upload the non-aligned value, OpenGL understands that there - // will be padding - if( x + width > opts.width ) - { - width = opts.width - x; - } - if( y + height > opts.height ) - { - height = opts.height - x; - } - } - else - { - assert( x + width <= opts.width && y + height <= opts.height ); - } - - int target; - int uploadTarget; - if( opts.textureType == TT_2D ) - { - target = GL_TEXTURE_2D; - uploadTarget = GL_TEXTURE_2D; - } - else if( opts.textureType == TT_CUBIC ) - { - target = GL_TEXTURE_CUBE_MAP; - uploadTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z; - } - else - { - assert( !"invalid opts.textureType" ); - target = GL_TEXTURE_2D; - uploadTarget = GL_TEXTURE_2D; - } - - glBindTexture( target, texnum ); - - if( pixelPitch != 0 ) - { - glPixelStorei( GL_UNPACK_ROW_LENGTH, pixelPitch ); - } - - if( opts.format == FMT_RGB565 ) - { -#if !defined(USE_GLES3) - glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_TRUE ); -#endif - } - -#if defined(DEBUG) || defined(__ANDROID__) - GL_CheckErrors(); -#endif - if( IsCompressed() ) - { - glCompressedTexSubImage2D( uploadTarget, mipLevel, x, y, width, height, internalFormat, compressedSize, pic ); - } - else - { - - // make sure the pixel store alignment is correct so that lower mips get created - // properly for odd shaped textures - this fixes the mip mapping issues with - // fonts - int unpackAlignment = width * BitsForFormat( ( textureFormat_t )opts.format ) / 8; - if( ( unpackAlignment & 3 ) == 0 ) - { - glPixelStorei( GL_UNPACK_ALIGNMENT, 4 ); - } - else - { - glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); - } - - glTexSubImage2D( uploadTarget, mipLevel, x, y, width, height, dataFormat, dataType, pic ); - } - -#if defined(DEBUG) || defined(__ANDROID__) - GL_CheckErrors(); -#endif - - if( opts.format == FMT_RGB565 ) - { - glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE ); - } - if( pixelPitch != 0 ) - { - glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); - } -} - -/* -======================== -idImage::SetPixel -======================== -*/ -void idImage::SetPixel( int mipLevel, int x, int y, const void* data, int dataSize ) -{ - SubImageUpload( mipLevel, x, y, 0, 1, 1, data ); -} - -/* -======================== -idImage::SetTexParameters -======================== -*/ -void idImage::SetTexParameters() -{ - int target = GL_TEXTURE_2D; - switch( opts.textureType ) - { - case TT_2D: - target = GL_TEXTURE_2D; - break; - case TT_CUBIC: - target = GL_TEXTURE_CUBE_MAP; - break; - // RB begin - case TT_2D_ARRAY: - target = GL_TEXTURE_2D_ARRAY; - break; - case TT_2D_MULTISAMPLE: - //target = GL_TEXTURE_2D_MULTISAMPLE; - //break; - // no texture parameters for MSAA FBO textures - return; - // RB end - default: - idLib::FatalError( "%s: bad texture type %d", GetName(), opts.textureType ); - return; - } - - // ALPHA, LUMINANCE, LUMINANCE_ALPHA, and INTENSITY have been removed - // in OpenGL 3.2. In order to mimic those modes, we use the swizzle operators -#if defined( USE_CORE_PROFILE ) - if( opts.colorFormat == CFM_GREEN_ALPHA ) - { - glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_GREEN ); - } - else if( opts.format == FMT_LUM8 ) - { - glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_RED ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_RED ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_RED ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_ONE ); - } - else if( opts.format == FMT_L8A8 ) - { - glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_RED ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_RED ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_RED ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_GREEN ); - } - else if( opts.format == FMT_ALPHA ) - { - glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_RED ); - } - else if( opts.format == FMT_INT8 ) - { - glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_RED ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_RED ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_RED ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_RED ); - } - else - { - glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_RED ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_GREEN ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_BLUE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_ALPHA ); - } -#else - if( opts.colorFormat == CFM_GREEN_ALPHA ) - { - glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_GREEN ); - } - else if( opts.format == FMT_ALPHA ) - { - glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_ONE ); - glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_RED ); - } -#endif - - switch( filter ) - { - case TF_DEFAULT: - if( r_useTrilinearFiltering.GetBool() ) - { - glTexParameterf( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); - } - else - { - glTexParameterf( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST ); - } - glTexParameterf( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - break; - case TF_LINEAR: - glTexParameterf( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameterf( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - break; - case TF_NEAREST: - case TF_NEAREST_MIPMAP: - glTexParameterf( target, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - glTexParameterf( target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - break; - default: - common->FatalError( "%s: bad texture filter %d", GetName(), filter ); - } - - if( glConfig.anisotropicFilterAvailable ) - { - // only do aniso filtering on mip mapped images - if( filter == TF_DEFAULT ) - { - int aniso = r_maxAnisotropicFiltering.GetInteger(); - if( aniso > glConfig.maxTextureAnisotropy ) - { - aniso = glConfig.maxTextureAnisotropy; - } - if( aniso < 0 ) - { - aniso = 0; - } - glTexParameterf( target, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso ); - } - else - { - glTexParameterf( target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); - } - } - - // RB: disabled use of unreliable extension that can make the game look worse - /* - if( glConfig.textureLODBiasAvailable && ( usage != TD_FONT ) ) - { - // use a blurring LOD bias in combination with high anisotropy to fix our aliasing grate textures... - glTexParameterf( target, GL_TEXTURE_LOD_BIAS_EXT, 0.5 ); //r_lodBias.GetFloat() ); - } - */ - // RB end - - // set the wrap/clamp modes - switch( repeat ) - { - case TR_REPEAT: - glTexParameterf( target, GL_TEXTURE_WRAP_S, GL_REPEAT ); - glTexParameterf( target, GL_TEXTURE_WRAP_T, GL_REPEAT ); - break; - case TR_CLAMP_TO_ZERO: - { - float color[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, color ); - glTexParameterf( target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); - glTexParameterf( target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); - } - break; - case TR_CLAMP_TO_ZERO_ALPHA: - { - float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, color ); - glTexParameterf( target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); - glTexParameterf( target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); - } - break; - case TR_CLAMP: - glTexParameterf( target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameterf( target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - break; - default: - common->FatalError( "%s: bad texture repeat %d", GetName(), repeat ); - } - - // RB: added shadow compare parameters for shadow map textures - if( opts.format == FMT_SHADOW_ARRAY ) - { - //glTexParameteri( target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - glTexParameteri( target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE ); - glTexParameteri( target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL ); - } -} - -/* -======================== -idImage::AllocImage - -Every image will pass through this function. Allocates all the necessary MipMap levels for the -Image, but doesn't put anything in them. - -This should not be done during normal game-play, if you can avoid it. -======================== -*/ -void idImage::AllocImage() -{ - GL_CheckErrors(); - PurgeImage(); - - int sRGB = r_useSRGB.GetInteger(); - - switch( opts.format ) - { - case FMT_RGBA8: - //internalFormat = GL_RGBA8; - //internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ? GL_SRGB8_ALPHA8 : GL_RGBA8; - internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ? GL_SRGB8_ALPHA8 : GL_RGBA8; - dataFormat = GL_RGBA; - dataType = GL_UNSIGNED_BYTE; - break; - case FMT_XRGB8: - internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ? GL_SRGB : GL_RGB; - dataFormat = GL_RGBA; - dataType = GL_UNSIGNED_BYTE; - break; - case FMT_RGB565: - //internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ? GL_SRGB : GL_RGB; - internalFormat = GL_RGB; - dataFormat = GL_RGB; - dataType = GL_UNSIGNED_SHORT_5_6_5; - break; - case FMT_ALPHA: -#if defined( USE_CORE_PROFILE ) -#if 1 - if( ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ) - { - internalFormat = GL_SRGB; - dataFormat = GL_RED; - } - else -#endif - { - internalFormat = GL_R8; - dataFormat = GL_RED; - } -#else - internalFormat = GL_ALPHA8; - dataFormat = GL_ALPHA; -#endif - dataType = GL_UNSIGNED_BYTE; - break; - case FMT_L8A8: -#if defined( USE_CORE_PROFILE ) - internalFormat = GL_RG8; - dataFormat = GL_RG; -#else - internalFormat = GL_LUMINANCE8_ALPHA8; - dataFormat = GL_LUMINANCE_ALPHA; -#endif - dataType = GL_UNSIGNED_BYTE; - break; - case FMT_LUM8: -#if defined( USE_CORE_PROFILE ) - internalFormat = GL_R8; - dataFormat = GL_RED; -#else - internalFormat = GL_LUMINANCE8; - dataFormat = GL_LUMINANCE; -#endif - dataType = GL_UNSIGNED_BYTE; - break; - case FMT_INT8: -#if defined( USE_CORE_PROFILE ) - internalFormat = GL_R8; - dataFormat = GL_RED; -#else - internalFormat = GL_INTENSITY8; - dataFormat = GL_LUMINANCE; -#endif - dataType = GL_UNSIGNED_BYTE; - break; - case FMT_DXT1: - internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - //internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - dataFormat = GL_RGBA; - dataType = GL_UNSIGNED_BYTE; - break; - case FMT_DXT5: - internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) && opts.colorFormat != CFM_YCOCG_DXT5 && opts.colorFormat != CFM_NORMAL_DXT5 ) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - //internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - dataFormat = GL_RGBA; - dataType = GL_UNSIGNED_BYTE; - break; - case FMT_DEPTH: - internalFormat = GL_DEPTH_COMPONENT; - dataFormat = GL_DEPTH_COMPONENT; - dataType = GL_UNSIGNED_BYTE; - break; - - case FMT_SHADOW_ARRAY: - internalFormat = GL_DEPTH_COMPONENT; - dataFormat = GL_DEPTH_COMPONENT; - dataType = GL_UNSIGNED_BYTE; - break; - - case FMT_RGBA16F: - internalFormat = GL_RGBA16F; - dataFormat = GL_RGBA; - dataType = GL_UNSIGNED_BYTE; - break; - - case FMT_RGBA32F: - internalFormat = GL_RGBA32F; - dataFormat = GL_RGBA; - dataType = GL_UNSIGNED_BYTE; - break; - - case FMT_R32F: - internalFormat = GL_R32F; - dataFormat = GL_RED; - dataType = GL_UNSIGNED_BYTE; - break; - - case FMT_X16: - internalFormat = GL_INTENSITY16; - dataFormat = GL_LUMINANCE; - dataType = GL_UNSIGNED_SHORT; - break; - case FMT_Y16_X16: - internalFormat = GL_LUMINANCE16_ALPHA16; - dataFormat = GL_LUMINANCE_ALPHA; - dataType = GL_UNSIGNED_SHORT; - break; - default: - idLib::Error( "Unhandled image format %d in %s\n", opts.format, GetName() ); - } - - // if we don't have a rendering context, just return after we - // have filled in the parms. We must have the values set, or - // an image match from a shader before OpenGL starts would miss - // the generated texture - if( !R_IsInitialized() ) - { - return; - } - - // generate the texture number - glGenTextures( 1, ( GLuint* )&texnum ); - assert( texnum != TEXTURE_NOT_LOADED ); - - //---------------------------------------------------- - // allocate all the mip levels with NULL data - //---------------------------------------------------- - - int numSides; - int target; - int uploadTarget; - if( opts.textureType == TT_2D ) - { - target = uploadTarget = GL_TEXTURE_2D; - numSides = 1; - } - else if( opts.textureType == TT_CUBIC ) - { - target = GL_TEXTURE_CUBE_MAP; - uploadTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X; - numSides = 6; - } - // RB begin - else if( opts.textureType == TT_2D_ARRAY ) - { - target = GL_TEXTURE_2D_ARRAY; - uploadTarget = GL_TEXTURE_2D_ARRAY; - numSides = 6; - } - else if( opts.textureType == TT_2D_MULTISAMPLE ) - { - target = GL_TEXTURE_2D_MULTISAMPLE; - uploadTarget = GL_TEXTURE_2D_MULTISAMPLE; - numSides = 1; - } - // RB end - else - { - assert( !"opts.textureType" ); - target = uploadTarget = GL_TEXTURE_2D; - numSides = 1; - } - - glBindTexture( target, texnum ); - - if( opts.textureType == TT_2D_ARRAY ) - { - glTexImage3D( uploadTarget, 0, internalFormat, opts.width, opts.height, numSides, 0, dataFormat, GL_UNSIGNED_BYTE, NULL ); - } - else if( opts.textureType == TT_2D_MULTISAMPLE ) - { - glTexImage2DMultisample( uploadTarget, opts.msaaSamples, internalFormat, opts.width, opts.height, GL_FALSE ); - } - else - { - for( int side = 0; side < numSides; side++ ) - { - int w = opts.width; - int h = opts.height; - if( opts.textureType == TT_CUBIC ) - { - h = w; - } - for( int level = 0; level < opts.numLevels; level++ ) - { - - // clear out any previous error - GL_CheckErrors(); - - if( IsCompressed() ) - { - int compressedSize = ( ( ( w + 3 ) / 4 ) * ( ( h + 3 ) / 4 ) * int64( 16 ) * BitsForFormat( opts.format ) ) / 8; - - // Even though the OpenGL specification allows the 'data' pointer to be NULL, for some - // drivers we actually need to upload data to get it to allocate the texture. - // However, on 32-bit systems we may fail to allocate a large block of memory for large - // textures. We handle this case by using HeapAlloc directly and allowing the allocation - // to fail in which case we simply pass down NULL to glCompressedTexImage2D and hope for the best. - // As of 2011-10-6 using NVIDIA hardware and drivers we have to allocate the memory with HeapAlloc - // with the exact size otherwise large image allocation (for instance for physical page textures) - // may fail on Vista 32-bit. - - // RB begin -#if defined(_WIN32) - void* data = HeapAlloc( GetProcessHeap(), 0, compressedSize ); - glCompressedTexImage2D( uploadTarget + side, level, internalFormat, w, h, 0, compressedSize, data ); - if( data != NULL ) - { - HeapFree( GetProcessHeap(), 0, data ); - } -#else - byte* data = ( byte* )Mem_Alloc( compressedSize, TAG_TEMP ); - glCompressedTexImage2D( uploadTarget + side, level, internalFormat, w, h, 0, compressedSize, data ); - if( data != NULL ) - { - Mem_Free( data ); - } -#endif - // RB end - } - else - { - glTexImage2D( uploadTarget + side, level, internalFormat, w, h, 0, dataFormat, dataType, NULL ); - } - - GL_CheckErrors(); - - w = Max( 1, w >> 1 ); - h = Max( 1, h >> 1 ); - } - } - - glTexParameteri( target, GL_TEXTURE_MAX_LEVEL, opts.numLevels - 1 ); - } - - // see if we messed anything up - GL_CheckErrors(); - - SetTexParameters(); - - GL_CheckErrors(); -} - -/* -======================== -idImage::PurgeImage -======================== -*/ -void idImage::PurgeImage() -{ - if( texnum != TEXTURE_NOT_LOADED ) - { - glDeleteTextures( 1, ( GLuint* )&texnum ); // this should be the ONLY place it is ever called! - texnum = TEXTURE_NOT_LOADED; - } - // clear all the current binding caches, so the next bind will do a real one - for( int i = 0 ; i < MAX_MULTITEXTURE_UNITS ; i++ ) - { - backEnd.glState.tmu[i].current2DMap = TEXTURE_NOT_LOADED; - backEnd.glState.tmu[i].current2DArray = TEXTURE_NOT_LOADED; - backEnd.glState.tmu[i].currentCubeMap = TEXTURE_NOT_LOADED; - } -} - -/* -======================== -idImage::Resize -======================== -*/ -void idImage::Resize( int width, int height ) -{ - if( opts.width == width && opts.height == height ) - { - return; - } - opts.width = width; - opts.height = height; - AllocImage(); -} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/Image_GL.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/Image_GL.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/Image_GL.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/Image_GL.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,903 @@ +/* +=========================================================================== + +Doom 3 BFG Edition GPL Source Code +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2013-2016 Robert Beckebans + +This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). + +Doom 3 BFG Edition Source Code 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. + +Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . + +In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ +#pragma hdrstop +#include "precompiled.h" + +/* +================================================================================================ +Contains the Image implementation for OpenGL. +================================================================================================ +*/ + +#include "../RenderCommon.h" + +/* +==================== +idImage::idImage +==================== +*/ +idImage::idImage( const char* name ) : imgName( name ) +{ + texnum = TEXTURE_NOT_LOADED; + internalFormat = 0; + dataFormat = 0; + dataType = 0; + generatorFunction = NULL; + filter = TF_DEFAULT; + repeat = TR_REPEAT; + usage = TD_DEFAULT; + cubeFiles = CF_2D; + + referencedOutsideLevelLoad = false; + levelLoadReferenced = false; + defaulted = false; + sourceFileTime = FILE_NOT_FOUND_TIMESTAMP; + binaryFileTime = FILE_NOT_FOUND_TIMESTAMP; + refCount = 0; +} + +/* +==================== +idImage::~idImage +==================== +*/ +idImage::~idImage() +{ + PurgeImage(); +} + +/* +============== +Bind + +Automatically enables 2D mapping or cube mapping if needed +============== +*/ +void idImage::Bind() +{ + RENDERLOG_PRINTF( "idImage::Bind( %s )\n", GetName() ); + + // load the image if necessary (FIXME: not SMP safe!) + if( !IsLoaded() ) + { + // load the image on demand here, which isn't our normal game operating mode + ActuallyLoadImage( true ); + } + + const int texUnit = tr.backend.GetCurrentTextureUnit(); + + // RB: added support for more types + tmu_t* tmu = &glcontext.tmu[texUnit]; + // bind the texture + if( opts.textureType == TT_2D ) + { + if( tmu->current2DMap != texnum ) + { + tmu->current2DMap = texnum; + +#if !defined(USE_GLES2) && !defined(USE_GLES3) + if( glConfig.directStateAccess ) + { + glBindMultiTextureEXT( GL_TEXTURE0 + texUnit, GL_TEXTURE_2D, texnum ); + } + else +#endif + { + glActiveTexture( GL_TEXTURE0 + texUnit ); + glBindTexture( GL_TEXTURE_2D, texnum ); + } + } + } + else if( opts.textureType == TT_CUBIC ) + { + if( tmu->currentCubeMap != texnum ) + { + tmu->currentCubeMap = texnum; + +#if !defined(USE_GLES2) && !defined(USE_GLES3) + if( glConfig.directStateAccess ) + { + glBindMultiTextureEXT( GL_TEXTURE0 + texUnit, GL_TEXTURE_CUBE_MAP, texnum ); + } + else +#endif + { + glActiveTexture( GL_TEXTURE0 + texUnit ); + glBindTexture( GL_TEXTURE_CUBE_MAP, texnum ); + } + } + } + else if( opts.textureType == TT_2D_ARRAY ) + { + if( tmu->current2DArray != texnum ) + { + tmu->current2DArray = texnum; + +#if !defined(USE_GLES2) && !defined(USE_GLES3) + if( glConfig.directStateAccess ) + { + glBindMultiTextureEXT( GL_TEXTURE0 + texUnit, GL_TEXTURE_2D_ARRAY, texnum ); + } + else +#endif + { + glActiveTexture( GL_TEXTURE0 + texUnit ); + glBindTexture( GL_TEXTURE_2D_ARRAY, texnum ); + } + } + } + else if( opts.textureType == TT_2D_MULTISAMPLE ) + { + if( tmu->current2DMap != texnum ) + { + tmu->current2DMap = texnum; + +#if !defined(USE_GLES2) && !defined(USE_GLES3) + if( glConfig.directStateAccess ) + { + glBindMultiTextureEXT( GL_TEXTURE0 + texUnit, GL_TEXTURE_2D_MULTISAMPLE, texnum ); + } + else +#endif + { + glActiveTexture( GL_TEXTURE0 + texUnit ); + glBindTexture( GL_TEXTURE_2D_MULTISAMPLE, texnum ); + } + } + } + // RB end +} + +/* +==================== +CopyFramebuffer +==================== +*/ +void idImage::CopyFramebuffer( int x, int y, int imageWidth, int imageHeight ) +{ + int target = GL_TEXTURE_2D; + switch( opts.textureType ) + { + case TT_2D: + target = GL_TEXTURE_2D; + break; + case TT_CUBIC: + target = GL_TEXTURE_CUBE_MAP; + break; + case TT_2D_ARRAY: + target = GL_TEXTURE_2D_ARRAY; + break; + case TT_2D_MULTISAMPLE: + target = GL_TEXTURE_2D_MULTISAMPLE; + break; + default: + //idLib::FatalError( "%s: bad texture type %d", GetName(), opts.textureType ); + return; + } + + glBindTexture( target, texnum ); + +#if !defined(USE_GLES2) + if( Framebuffer::IsDefaultFramebufferActive() ) + { + glReadBuffer( GL_BACK ); + } +#endif + + opts.width = imageWidth; + opts.height = imageHeight; + +#if defined(USE_GLES2) + glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, x, y, imageWidth, imageHeight, 0 ); +#else + if( r_useHDR.GetBool() && globalFramebuffers.hdrFBO->IsBound() ) + { + + //if( backEnd.glState.currentFramebuffer != NULL && backEnd.glState.currentFramebuffer->IsMultiSampled() ) + +#if defined(USE_HDR_MSAA) + if( globalFramebuffers.hdrFBO->IsMultiSampled() ) + { + glBindFramebuffer( GL_READ_FRAMEBUFFER, globalFramebuffers.hdrFBO->GetFramebuffer() ); + glBindFramebuffer( GL_DRAW_FRAMEBUFFER, globalFramebuffers.hdrNonMSAAFBO->GetFramebuffer() ); + glBlitFramebuffer( 0, 0, glConfig.nativeScreenWidth, glConfig.nativeScreenHeight, + 0, 0, glConfig.nativeScreenWidth, glConfig.nativeScreenHeight, + GL_COLOR_BUFFER_BIT, + GL_LINEAR ); + + globalFramebuffers.hdrNonMSAAFBO->Bind(); + + glCopyTexImage2D( target, 0, GL_RGBA16F, x, y, imageWidth, imageHeight, 0 ); + + globalFramebuffers.hdrFBO->Bind(); + } + else +#endif + { + glCopyTexImage2D( target, 0, GL_RGBA16F, x, y, imageWidth, imageHeight, 0 ); + } + } + else + { + glCopyTexImage2D( target, 0, GL_RGBA8, x, y, imageWidth, imageHeight, 0 ); + } +#endif + + // these shouldn't be necessary if the image was initialized properly + glTexParameterf( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameterf( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + glTexParameterf( target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameterf( target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + + tr.backend.pc.c_copyFrameBuffer++; +} + +/* +==================== +CopyDepthbuffer +==================== +*/ +void idImage::CopyDepthbuffer( int x, int y, int imageWidth, int imageHeight ) +{ + glBindTexture( ( opts.textureType == TT_CUBIC ) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, texnum ); + + opts.width = imageWidth; + opts.height = imageHeight; + glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, x, y, imageWidth, imageHeight, 0 ); + + tr.backend.pc.c_copyFrameBuffer++; +} + +/* +======================== +idImage::SubImageUpload +======================== +*/ +void idImage::SubImageUpload( int mipLevel, int x, int y, int z, int width, int height, const void* pic, int pixelPitch ) const +{ + assert( x >= 0 && y >= 0 && mipLevel >= 0 && width >= 0 && height >= 0 && mipLevel < opts.numLevels ); + + int compressedSize = 0; + + if( IsCompressed() ) + { + assert( !( x & 3 ) && !( y & 3 ) ); + + // compressed size may be larger than the dimensions due to padding to quads + int quadW = ( width + 3 ) & ~3; + int quadH = ( height + 3 ) & ~3; + compressedSize = quadW * quadH * BitsForFormat( opts.format ) / 8; + + int padW = ( opts.width + 3 ) & ~3; + int padH = ( opts.height + 3 ) & ~3; + + assert( x + width <= padW && y + height <= padH ); + // upload the non-aligned value, OpenGL understands that there + // will be padding + if( x + width > opts.width ) + { + width = opts.width - x; + } + if( y + height > opts.height ) + { + height = opts.height - x; + } + } + else + { + assert( x + width <= opts.width && y + height <= opts.height ); + } + + int target; + int uploadTarget; + if( opts.textureType == TT_2D ) + { + target = GL_TEXTURE_2D; + uploadTarget = GL_TEXTURE_2D; + } + else if( opts.textureType == TT_CUBIC ) + { + target = GL_TEXTURE_CUBE_MAP; + uploadTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z; + } + else + { + assert( !"invalid opts.textureType" ); + target = GL_TEXTURE_2D; + uploadTarget = GL_TEXTURE_2D; + } + + glBindTexture( target, texnum ); + + if( pixelPitch != 0 ) + { + glPixelStorei( GL_UNPACK_ROW_LENGTH, pixelPitch ); + } + + if( opts.format == FMT_RGB565 ) + { +#if !defined(USE_GLES3) + glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_TRUE ); +#endif + } + +#if defined(DEBUG) || defined(__ANDROID__) + GL_CheckErrors(); +#endif + if( IsCompressed() ) + { + glCompressedTexSubImage2D( uploadTarget, mipLevel, x, y, width, height, internalFormat, compressedSize, pic ); + } + else + { + + // make sure the pixel store alignment is correct so that lower mips get created + // properly for odd shaped textures - this fixes the mip mapping issues with + // fonts + int unpackAlignment = width * BitsForFormat( ( textureFormat_t )opts.format ) / 8; + if( ( unpackAlignment & 3 ) == 0 ) + { + glPixelStorei( GL_UNPACK_ALIGNMENT, 4 ); + } + else + { + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + } + + glTexSubImage2D( uploadTarget, mipLevel, x, y, width, height, dataFormat, dataType, pic ); + } + +#if defined(DEBUG) || defined(__ANDROID__) + GL_CheckErrors(); +#endif + + if( opts.format == FMT_RGB565 ) + { + glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE ); + } + if( pixelPitch != 0 ) + { + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); + } +} + +/* +======================== +idImage::SetPixel +======================== +*/ +void idImage::SetPixel( int mipLevel, int x, int y, const void* data, int dataSize ) +{ + SubImageUpload( mipLevel, x, y, 0, 1, 1, data ); +} + +/* +======================== +idImage::SetTexParameters +======================== +*/ +void idImage::SetTexParameters() +{ + int target = GL_TEXTURE_2D; + switch( opts.textureType ) + { + case TT_2D: + target = GL_TEXTURE_2D; + break; + case TT_CUBIC: + target = GL_TEXTURE_CUBE_MAP; + break; + // RB begin + case TT_2D_ARRAY: + target = GL_TEXTURE_2D_ARRAY; + break; + case TT_2D_MULTISAMPLE: + //target = GL_TEXTURE_2D_MULTISAMPLE; + //break; + // no texture parameters for MSAA FBO textures + return; + // RB end + default: + idLib::FatalError( "%s: bad texture type %d", GetName(), opts.textureType ); + return; + } + + // ALPHA, LUMINANCE, LUMINANCE_ALPHA, and INTENSITY have been removed + // in OpenGL 3.2. In order to mimic those modes, we use the swizzle operators +#if defined( USE_CORE_PROFILE ) + if( opts.colorFormat == CFM_GREEN_ALPHA ) + { + glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_GREEN ); + } + else if( opts.format == FMT_LUM8 ) + { + glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_RED ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_RED ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_RED ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_ONE ); + } + else if( opts.format == FMT_L8A8 ) + { + glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_RED ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_RED ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_RED ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_GREEN ); + } + else if( opts.format == FMT_ALPHA ) + { + glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_RED ); + } + else if( opts.format == FMT_INT8 ) + { + glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_RED ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_RED ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_RED ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_RED ); + } + else + { + glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_RED ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_GREEN ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_BLUE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_ALPHA ); + } +#else + if( opts.colorFormat == CFM_GREEN_ALPHA ) + { + glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_GREEN ); + } + else if( opts.format == FMT_ALPHA ) + { + glTexParameteri( target, GL_TEXTURE_SWIZZLE_R, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_G, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_B, GL_ONE ); + glTexParameteri( target, GL_TEXTURE_SWIZZLE_A, GL_RED ); + } +#endif + + switch( filter ) + { + case TF_DEFAULT: + if( r_useTrilinearFiltering.GetBool() ) + { + glTexParameterf( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + } + else + { + glTexParameterf( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST ); + } + glTexParameterf( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + break; + case TF_LINEAR: + glTexParameterf( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameterf( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + break; + case TF_NEAREST: + case TF_NEAREST_MIPMAP: + glTexParameterf( target, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameterf( target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + break; + default: + common->FatalError( "%s: bad texture filter %d", GetName(), filter ); + } + + if( glConfig.anisotropicFilterAvailable ) + { + // only do aniso filtering on mip mapped images + if( filter == TF_DEFAULT ) + { + int aniso = r_maxAnisotropicFiltering.GetInteger(); + if( aniso > glConfig.maxTextureAnisotropy ) + { + aniso = glConfig.maxTextureAnisotropy; + } + if( aniso < 0 ) + { + aniso = 0; + } + glTexParameterf( target, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso ); + } + else + { + glTexParameterf( target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); + } + } + + // RB: disabled use of unreliable extension that can make the game look worse + /* + if( glConfig.textureLODBiasAvailable && ( usage != TD_FONT ) ) + { + // use a blurring LOD bias in combination with high anisotropy to fix our aliasing grate textures... + glTexParameterf( target, GL_TEXTURE_LOD_BIAS_EXT, 0.5 ); //r_lodBias.GetFloat() ); + } + */ + // RB end + + // set the wrap/clamp modes + switch( repeat ) + { + case TR_REPEAT: + glTexParameterf( target, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameterf( target, GL_TEXTURE_WRAP_T, GL_REPEAT ); + break; + case TR_CLAMP_TO_ZERO: + { + float color[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, color ); + glTexParameterf( target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); + glTexParameterf( target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); + } + break; + case TR_CLAMP_TO_ZERO_ALPHA: + { + float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, color ); + glTexParameterf( target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); + glTexParameterf( target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); + } + break; + case TR_CLAMP: + glTexParameterf( target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameterf( target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + break; + default: + common->FatalError( "%s: bad texture repeat %d", GetName(), repeat ); + } + + // RB: added shadow compare parameters for shadow map textures + if( opts.format == FMT_SHADOW_ARRAY ) + { + //glTexParameteri( target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + glTexParameteri( target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE ); + glTexParameteri( target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL ); + } +} + +/* +======================== +idImage::AllocImage + +Every image will pass through this function. Allocates all the necessary MipMap levels for the +Image, but doesn't put anything in them. + +This should not be done during normal game-play, if you can avoid it. +======================== +*/ +void idImage::AllocImage() +{ + GL_CheckErrors(); + PurgeImage(); + + int sRGB = r_useSRGB.GetInteger(); + + switch( opts.format ) + { + case FMT_RGBA8: + //internalFormat = GL_RGBA8; + //internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ? GL_SRGB8_ALPHA8 : GL_RGBA8; + internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ? GL_SRGB8_ALPHA8 : GL_RGBA8; + dataFormat = GL_RGBA; + dataType = GL_UNSIGNED_BYTE; + break; + case FMT_XRGB8: + internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ? GL_SRGB : GL_RGB; + dataFormat = GL_RGBA; + dataType = GL_UNSIGNED_BYTE; + break; + case FMT_RGB565: + //internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ? GL_SRGB : GL_RGB; + internalFormat = GL_RGB; + dataFormat = GL_RGB; + dataType = GL_UNSIGNED_SHORT_5_6_5; + break; + case FMT_ALPHA: +#if defined( USE_CORE_PROFILE ) +#if 1 + if( ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ) + { + internalFormat = GL_SRGB; + dataFormat = GL_RED; + } + else +#endif + { + internalFormat = GL_R8; + dataFormat = GL_RED; + } +#else + internalFormat = GL_ALPHA8; + dataFormat = GL_ALPHA; +#endif + dataType = GL_UNSIGNED_BYTE; + break; + case FMT_L8A8: +#if defined( USE_CORE_PROFILE ) + internalFormat = GL_RG8; + dataFormat = GL_RG; +#else + internalFormat = GL_LUMINANCE8_ALPHA8; + dataFormat = GL_LUMINANCE_ALPHA; +#endif + dataType = GL_UNSIGNED_BYTE; + break; + case FMT_LUM8: +#if defined( USE_CORE_PROFILE ) + internalFormat = GL_R8; + dataFormat = GL_RED; +#else + internalFormat = GL_LUMINANCE8; + dataFormat = GL_LUMINANCE; +#endif + dataType = GL_UNSIGNED_BYTE; + break; + case FMT_INT8: +#if defined( USE_CORE_PROFILE ) + internalFormat = GL_R8; + dataFormat = GL_RED; +#else + internalFormat = GL_INTENSITY8; + dataFormat = GL_LUMINANCE; +#endif + dataType = GL_UNSIGNED_BYTE; + break; + case FMT_DXT1: + internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) ) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + //internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + dataFormat = GL_RGBA; + dataType = GL_UNSIGNED_BYTE; + break; + case FMT_DXT5: + internalFormat = ( glConfig.sRGBFramebufferAvailable && ( sRGB == 1 || sRGB == 3 ) && opts.colorFormat != CFM_YCOCG_DXT5 && opts.colorFormat != CFM_NORMAL_DXT5 ) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + //internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + dataFormat = GL_RGBA; + dataType = GL_UNSIGNED_BYTE; + break; + case FMT_DEPTH: + internalFormat = GL_DEPTH_COMPONENT; + dataFormat = GL_DEPTH_COMPONENT; + dataType = GL_UNSIGNED_BYTE; + break; + + case FMT_SHADOW_ARRAY: + internalFormat = GL_DEPTH_COMPONENT; + dataFormat = GL_DEPTH_COMPONENT; + dataType = GL_UNSIGNED_BYTE; + break; + + case FMT_RGBA16F: + internalFormat = GL_RGBA16F; + dataFormat = GL_RGBA; + dataType = GL_UNSIGNED_BYTE; + break; + + case FMT_RGBA32F: + internalFormat = GL_RGBA32F; + dataFormat = GL_RGBA; + dataType = GL_UNSIGNED_BYTE; + break; + + case FMT_R32F: + internalFormat = GL_R32F; + dataFormat = GL_RED; + dataType = GL_UNSIGNED_BYTE; + break; + + case FMT_X16: + internalFormat = GL_INTENSITY16; + dataFormat = GL_LUMINANCE; + dataType = GL_UNSIGNED_SHORT; + break; + case FMT_Y16_X16: + internalFormat = GL_LUMINANCE16_ALPHA16; + dataFormat = GL_LUMINANCE_ALPHA; + dataType = GL_UNSIGNED_SHORT; + break; + default: + idLib::Error( "Unhandled image format %d in %s\n", opts.format, GetName() ); + } + + // if we don't have a rendering context, just return after we + // have filled in the parms. We must have the values set, or + // an image match from a shader before OpenGL starts would miss + // the generated texture + if( !R_IsInitialized() ) + { + return; + } + + // generate the texture number + glGenTextures( 1, ( GLuint* )&texnum ); + assert( texnum != TEXTURE_NOT_LOADED ); + + //---------------------------------------------------- + // allocate all the mip levels with NULL data + //---------------------------------------------------- + + int numSides; + int target; + int uploadTarget; + if( opts.textureType == TT_2D ) + { + target = uploadTarget = GL_TEXTURE_2D; + numSides = 1; + } + else if( opts.textureType == TT_CUBIC ) + { + target = GL_TEXTURE_CUBE_MAP; + uploadTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X; + numSides = 6; + } + // RB begin + else if( opts.textureType == TT_2D_ARRAY ) + { + target = GL_TEXTURE_2D_ARRAY; + uploadTarget = GL_TEXTURE_2D_ARRAY; + numSides = 6; + } + else if( opts.textureType == TT_2D_MULTISAMPLE ) + { + target = GL_TEXTURE_2D_MULTISAMPLE; + uploadTarget = GL_TEXTURE_2D_MULTISAMPLE; + numSides = 1; + } + // RB end + else + { + assert( !"opts.textureType" ); + target = uploadTarget = GL_TEXTURE_2D; + numSides = 1; + } + + glBindTexture( target, texnum ); + + if( opts.textureType == TT_2D_ARRAY ) + { + glTexImage3D( uploadTarget, 0, internalFormat, opts.width, opts.height, numSides, 0, dataFormat, GL_UNSIGNED_BYTE, NULL ); + } + else if( opts.textureType == TT_2D_MULTISAMPLE ) + { + glTexImage2DMultisample( uploadTarget, opts.samples, internalFormat, opts.width, opts.height, GL_FALSE ); + } + else + { + for( int side = 0; side < numSides; side++ ) + { + int w = opts.width; + int h = opts.height; + if( opts.textureType == TT_CUBIC ) + { + h = w; + } + for( int level = 0; level < opts.numLevels; level++ ) + { + + // clear out any previous error + GL_CheckErrors(); + + if( IsCompressed() ) + { + int compressedSize = ( ( ( w + 3 ) / 4 ) * ( ( h + 3 ) / 4 ) * int64( 16 ) * BitsForFormat( opts.format ) ) / 8; + + // Even though the OpenGL specification allows the 'data' pointer to be NULL, for some + // drivers we actually need to upload data to get it to allocate the texture. + // However, on 32-bit systems we may fail to allocate a large block of memory for large + // textures. We handle this case by using HeapAlloc directly and allowing the allocation + // to fail in which case we simply pass down NULL to glCompressedTexImage2D and hope for the best. + // As of 2011-10-6 using NVIDIA hardware and drivers we have to allocate the memory with HeapAlloc + // with the exact size otherwise large image allocation (for instance for physical page textures) + // may fail on Vista 32-bit. + + // RB begin +#if defined(_WIN32) + void* data = HeapAlloc( GetProcessHeap(), 0, compressedSize ); + glCompressedTexImage2D( uploadTarget + side, level, internalFormat, w, h, 0, compressedSize, data ); + if( data != NULL ) + { + HeapFree( GetProcessHeap(), 0, data ); + } +#else + byte* data = ( byte* )Mem_Alloc( compressedSize, TAG_TEMP ); + glCompressedTexImage2D( uploadTarget + side, level, internalFormat, w, h, 0, compressedSize, data ); + if( data != NULL ) + { + Mem_Free( data ); + } +#endif + // RB end + } + else + { + glTexImage2D( uploadTarget + side, level, internalFormat, w, h, 0, dataFormat, dataType, NULL ); + } + + GL_CheckErrors(); + + w = Max( 1, w >> 1 ); + h = Max( 1, h >> 1 ); + } + } + + glTexParameteri( target, GL_TEXTURE_MAX_LEVEL, opts.numLevels - 1 ); + } + + // see if we messed anything up + GL_CheckErrors(); + + SetTexParameters(); + + GL_CheckErrors(); +} + +/* +======================== +idImage::PurgeImage +======================== +*/ +void idImage::PurgeImage() +{ + if( texnum != TEXTURE_NOT_LOADED ) + { + glDeleteTextures( 1, ( GLuint* )&texnum ); // this should be the ONLY place it is ever called! + texnum = TEXTURE_NOT_LOADED; + } + + // clear all the current binding caches, so the next bind will do a real one + for( int i = 0 ; i < MAX_MULTITEXTURE_UNITS ; i++ ) + { + glcontext.tmu[i].current2DMap = TEXTURE_NOT_LOADED; + glcontext.tmu[i].current2DArray = TEXTURE_NOT_LOADED; + glcontext.tmu[i].currentCubeMap = TEXTURE_NOT_LOADED; + } +} + +/* +======================== +idImage::Resize +======================== +*/ +void idImage::Resize( int width, int height ) +{ + if( opts.width == width && opts.height == height ) + { + return; + } + opts.width = width; + opts.height = height; + AllocImage(); +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/RenderBackend_GL.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/RenderBackend_GL.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/RenderBackend_GL.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/RenderBackend_GL.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,1677 @@ +/* +=========================================================================== + +Doom 3 BFG Edition GPL Source Code +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2013-2015 Robert Beckebans +Copyright (C) 2016-2017 Dustin Land + +This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). + +Doom 3 BFG Edition Source Code 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. + +Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . + +In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#pragma hdrstop +#include "precompiled.h" + +#include "../RenderCommon.h" +#include "../RenderBackend.h" +#include "../../framework/Common_local.h" + +idCVar r_drawFlickerBox( "r_drawFlickerBox", "0", CVAR_RENDERER | CVAR_BOOL, "visual test for dropping frames" ); +idCVar stereoRender_warp( "stereoRender_warp", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "use the optical warping renderprog instead of stereoDeGhost" ); +idCVar stereoRender_warpStrength( "stereoRender_warpStrength", "1.45", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "amount of pre-distortion" ); + +idCVar stereoRender_warpCenterX( "stereoRender_warpCenterX", "0.5", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "center for left eye, right eye will be 1.0 - this" ); +idCVar stereoRender_warpCenterY( "stereoRender_warpCenterY", "0.5", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "center for both eyes" ); +idCVar stereoRender_warpParmZ( "stereoRender_warpParmZ", "0", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "development parm" ); +idCVar stereoRender_warpParmW( "stereoRender_warpParmW", "0", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "development parm" ); +idCVar stereoRender_warpTargetFraction( "stereoRender_warpTargetFraction", "1.0", CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE, "fraction of half-width the through-lens view covers" ); + +idCVar r_showSwapBuffers( "r_showSwapBuffers", "0", CVAR_BOOL, "Show timings from GL_BlockingSwapBuffers" ); +idCVar r_syncEveryFrame( "r_syncEveryFrame", "1", CVAR_BOOL, "Don't let the GPU buffer execution past swapbuffers" ); + +static int swapIndex; // 0 or 1 into renderSync +static GLsync renderSync[2]; + +void GLimp_SwapBuffers(); +void RB_SetMVP( const idRenderMatrix& mvp ); + +glContext_t glcontext; + +/* +================== +GL_CheckErrors +================== +*/ +// RB: added filename, line parms +bool GL_CheckErrors_( const char* filename, int line ) +{ + int err; + char s[64]; + int i; + + if( r_ignoreGLErrors.GetBool() ) + { + return false; + } + + // check for up to 10 errors pending + bool error = false; + for( i = 0 ; i < 10 ; i++ ) + { + err = glGetError(); + if( err == GL_NO_ERROR ) + { + break; + } + + error = true; + switch( err ) + { + case GL_INVALID_ENUM: + strcpy( s, "GL_INVALID_ENUM" ); + break; + case GL_INVALID_VALUE: + strcpy( s, "GL_INVALID_VALUE" ); + break; + case GL_INVALID_OPERATION: + strcpy( s, "GL_INVALID_OPERATION" ); + break; +#if !defined(USE_GLES2) && !defined(USE_GLES3) + case GL_STACK_OVERFLOW: + strcpy( s, "GL_STACK_OVERFLOW" ); + break; + case GL_STACK_UNDERFLOW: + strcpy( s, "GL_STACK_UNDERFLOW" ); + break; +#endif + case GL_OUT_OF_MEMORY: + strcpy( s, "GL_OUT_OF_MEMORY" ); + break; + default: + idStr::snPrintf( s, sizeof( s ), "%i", err ); + break; + } + + common->Printf( "caught OpenGL error: %s in file %s line %i\n", s, filename, line ); + } + + return error; +} +// RB end + +/* +============= +idRenderBackend::DrawElementsWithCounters +============= +*/ +void idRenderBackend::DrawElementsWithCounters( const drawSurf_t* surf ) +{ + // get vertex buffer + const vertCacheHandle_t vbHandle = surf->ambientCache; + idVertexBuffer* vertexBuffer; + if( vertexCache.CacheIsStatic( vbHandle ) ) + { + vertexBuffer = &vertexCache.staticData.vertexBuffer; + } + else + { + const uint64 frameNum = ( int )( vbHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK; + if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) + { + idLib::Warning( "RB_DrawElementsWithCounters, vertexBuffer == NULL" ); + return; + } + vertexBuffer = &vertexCache.frameData[vertexCache.drawListNum].vertexBuffer; + } + const int vertOffset = ( int )( vbHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK; + + // get index buffer + const vertCacheHandle_t ibHandle = surf->indexCache; + idIndexBuffer* indexBuffer; + if( vertexCache.CacheIsStatic( ibHandle ) ) + { + indexBuffer = &vertexCache.staticData.indexBuffer; + } + else + { + const uint64 frameNum = ( int )( ibHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK; + if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) + { + idLib::Warning( "RB_DrawElementsWithCounters, indexBuffer == NULL" ); + return; + } + indexBuffer = &vertexCache.frameData[vertexCache.drawListNum].indexBuffer; + } + // RB: 64 bit fixes, changed int to GLintptr + const GLintptr indexOffset = ( GLintptr )( ibHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK; + // RB end + + RENDERLOG_PRINTF( "Binding Buffers: %p:%i %p:%i\n", vertexBuffer, vertOffset, indexBuffer, indexOffset ); + + if( surf->jointCache ) + { + // DG: this happens all the time in the erebus1 map with blendlight.vfp, + // so don't call assert (through verify) here until it's fixed (if fixable) + // else the game crashes on linux when using debug builds + + // FIXME: fix this properly if possible? + // RB: yes but it would require an additional blend light skinned shader + //if( !verify( renderProgManager.ShaderUsesJoints() ) ) + if( !renderProgManager.ShaderUsesJoints() ) + // DG end + { + return; + } + } + else + { + if( !verify( !renderProgManager.ShaderUsesJoints() || renderProgManager.ShaderHasOptionalSkinning() ) ) + { + return; + } + } + + + if( surf->jointCache ) + { + idJointBuffer jointBuffer; + if( !vertexCache.GetJointBuffer( surf->jointCache, &jointBuffer ) ) + { + idLib::Warning( "RB_DrawElementsWithCounters, jointBuffer == NULL" ); + return; + } + assert( ( jointBuffer.GetOffset() & ( glConfig.uniformBufferOffsetAlignment - 1 ) ) == 0 ); + + // RB: 64 bit fixes, changed GLuint to GLintptr + const GLintptr ubo = reinterpret_cast< GLintptr >( jointBuffer.GetAPIObject() ); + // RB end + + glBindBufferRange( GL_UNIFORM_BUFFER, 0, ubo, jointBuffer.GetOffset(), jointBuffer.GetNumJoints() * sizeof( idJointMat ) ); + } + + renderProgManager.CommitUniforms(); + + // RB: 64 bit fixes, changed GLuint to GLintptr + if( currentIndexBuffer != ( GLintptr )indexBuffer->GetAPIObject() || !r_useStateCaching.GetBool() ) + { + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ( GLintptr )indexBuffer->GetAPIObject() ); + currentIndexBuffer = ( GLintptr )indexBuffer->GetAPIObject(); + } + + if( ( vertexLayout != LAYOUT_DRAW_VERT ) || ( currentVertexBuffer != ( GLintptr )vertexBuffer->GetAPIObject() ) || !r_useStateCaching.GetBool() ) + { + glBindBuffer( GL_ARRAY_BUFFER, ( GLintptr )vertexBuffer->GetAPIObject() ); + currentVertexBuffer = ( GLintptr )vertexBuffer->GetAPIObject(); + + glEnableVertexAttribArray( PC_ATTRIB_INDEX_VERTEX ); + glEnableVertexAttribArray( PC_ATTRIB_INDEX_NORMAL ); + glEnableVertexAttribArray( PC_ATTRIB_INDEX_COLOR ); + glEnableVertexAttribArray( PC_ATTRIB_INDEX_COLOR2 ); + glEnableVertexAttribArray( PC_ATTRIB_INDEX_ST ); + glEnableVertexAttribArray( PC_ATTRIB_INDEX_TANGENT ); + +#if defined(USE_GLES2) || defined(USE_GLES3) + glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_XYZ_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_NORMAL, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_NORMAL_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_COLOR_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_COLOR2_OFFSET ) ); +#if defined(USE_ANGLE) + glVertexAttribPointer( PC_ATTRIB_INDEX_ST, 2, GL_HALF_FLOAT_OES, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_ST_OFFSET ) ); +#else + glVertexAttribPointer( PC_ATTRIB_INDEX_ST, 2, GL_HALF_FLOAT, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_ST_OFFSET ) ); +#endif + glVertexAttribPointer( PC_ATTRIB_INDEX_TANGENT, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_TANGENT_OFFSET ) ); + +#else + glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof( idDrawVert ), ( void* )( DRAWVERT_XYZ_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_NORMAL, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( DRAWVERT_NORMAL_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( DRAWVERT_COLOR_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( DRAWVERT_COLOR2_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_ST, 2, GL_HALF_FLOAT, GL_TRUE, sizeof( idDrawVert ), ( void* )( DRAWVERT_ST_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_TANGENT, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( DRAWVERT_TANGENT_OFFSET ) ); +#endif // #if defined(USE_GLES2) || defined(USE_GLES3) + + vertexLayout = LAYOUT_DRAW_VERT; + } + // RB end + +#if defined(USE_GLES3) //defined(USE_GLES2) + glDrawElements( GL_TRIANGLES, + r_singleTriangle.GetBool() ? 3 : surf->numIndexes, + GL_INDEX_TYPE, + ( triIndex_t* )indexOffset ); +#else + glDrawElementsBaseVertex( GL_TRIANGLES, + r_singleTriangle.GetBool() ? 3 : surf->numIndexes, + GL_INDEX_TYPE, + ( triIndex_t* )indexOffset, + vertOffset / sizeof( idDrawVert ) ); +#endif + + // RB: added stats + pc.c_drawElements++; + pc.c_drawIndexes += surf->numIndexes; + // RB end +} + + +/* +========================================================================================================= + +GL COMMANDS + +========================================================================================================= +*/ + +/* +================== +idRenderBackend::GL_StartFrame +================== +*/ +void idRenderBackend::GL_StartFrame() +{ + +} + +/* +================== +idRenderBackend::GL_EndFrame +================== +*/ +void idRenderBackend::GL_EndFrame() +{ + // Fix for the steam overlay not showing up while in game without Shell/Debug/Console/Menu also rendering + glColorMask( 1, 1, 1, 1 ); + + glFlush(); +} + +/* +======================== +GL_SetDefaultState + +This should initialize all GL state that any part of the entire program +may touch, including the editor. +======================== +*/ +void idRenderBackend::GL_SetDefaultState() +{ + RENDERLOG_PRINTF( "--- GL_SetDefaultState ---\n" ); + + glClearDepth( 1.0f ); + + // make sure our GL state vector is set correctly + memset( &glcontext.tmu, 0, sizeof( glcontext.tmu ) ); + currenttmu = 0; + currentVertexBuffer = 0; + currentIndexBuffer = 0; + currentFramebuffer = 0; + faceCulling = 0; + vertexLayout = LAYOUT_UNKNOWN; + polyOfsScale = 0.0f; + polyOfsBias = 0.0f; + glStateBits = 0; + + hdrAverageLuminance = 0; + hdrMaxLuminance = 0; + hdrTime = 0; + hdrKey = 0; + + GL_State( 0, true ); + + // RB begin + Framebuffer::Unbind(); + // RB end + + // These are changed by GL_Cull + glCullFace( GL_FRONT_AND_BACK ); + glEnable( GL_CULL_FACE ); + + // These are changed by GL_State + glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + glBlendFunc( GL_ONE, GL_ZERO ); + glDepthMask( GL_TRUE ); + glDepthFunc( GL_LESS ); + glDisable( GL_STENCIL_TEST ); + glDisable( GL_POLYGON_OFFSET_FILL ); + glDisable( GL_POLYGON_OFFSET_LINE ); + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + + // These should never be changed + // DG: deprecated in opengl 3.2 and not needed because we don't do fixed function pipeline + // glShadeModel( GL_SMOOTH ); + // DG end + glEnable( GL_DEPTH_TEST ); + glEnable( GL_BLEND ); + glEnable( GL_SCISSOR_TEST ); + glDrawBuffer( GL_BACK ); + glReadBuffer( GL_BACK ); + + if( r_useScissor.GetBool() ) + { + glScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() ); + } + + // RB: don't keep renderprogs that were enabled during level load + renderProgManager.Unbind(); + // RB end +} + +/* +==================== +idRenderBackend::GL_State + +This routine is responsible for setting the most commonly changed state +==================== +*/ +void idRenderBackend::GL_State( uint64 stateBits, bool forceGlState ) +{ + uint64 diff = stateBits ^ glStateBits; + + if( !r_useStateCaching.GetBool() || forceGlState ) + { + // make sure everything is set all the time, so we + // can see if our delta checking is screwing up + diff = 0xFFFFFFFFFFFFFFFF; + } + else if( diff == 0 ) + { + return; + } + + // + // check depthFunc bits + // + if( diff & GLS_DEPTHFUNC_BITS ) + { + switch( stateBits & GLS_DEPTHFUNC_BITS ) + { + case GLS_DEPTHFUNC_EQUAL: + glDepthFunc( GL_EQUAL ); + break; + case GLS_DEPTHFUNC_ALWAYS: + glDepthFunc( GL_ALWAYS ); + break; + case GLS_DEPTHFUNC_LESS: + glDepthFunc( GL_LEQUAL ); + break; + case GLS_DEPTHFUNC_GREATER: + glDepthFunc( GL_GEQUAL ); + break; + } + } + + // + // check blend bits + // + if( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) + { + GLenum srcFactor = GL_ONE; + GLenum dstFactor = GL_ZERO; + + switch( stateBits & GLS_SRCBLEND_BITS ) + { + case GLS_SRCBLEND_ZERO: + srcFactor = GL_ZERO; + break; + case GLS_SRCBLEND_ONE: + srcFactor = GL_ONE; + break; + case GLS_SRCBLEND_DST_COLOR: + srcFactor = GL_DST_COLOR; + break; + case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: + srcFactor = GL_ONE_MINUS_DST_COLOR; + break; + case GLS_SRCBLEND_SRC_ALPHA: + srcFactor = GL_SRC_ALPHA; + break; + case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: + srcFactor = GL_ONE_MINUS_SRC_ALPHA; + break; + case GLS_SRCBLEND_DST_ALPHA: + srcFactor = GL_DST_ALPHA; + break; + case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: + srcFactor = GL_ONE_MINUS_DST_ALPHA; + break; + default: + assert( !"GL_State: invalid src blend state bits\n" ); + break; + } + + switch( stateBits & GLS_DSTBLEND_BITS ) + { + case GLS_DSTBLEND_ZERO: + dstFactor = GL_ZERO; + break; + case GLS_DSTBLEND_ONE: + dstFactor = GL_ONE; + break; + case GLS_DSTBLEND_SRC_COLOR: + dstFactor = GL_SRC_COLOR; + break; + case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: + dstFactor = GL_ONE_MINUS_SRC_COLOR; + break; + case GLS_DSTBLEND_SRC_ALPHA: + dstFactor = GL_SRC_ALPHA; + break; + case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: + dstFactor = GL_ONE_MINUS_SRC_ALPHA; + break; + case GLS_DSTBLEND_DST_ALPHA: + dstFactor = GL_DST_ALPHA; + break; + case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: + dstFactor = GL_ONE_MINUS_DST_ALPHA; + break; + default: + assert( !"GL_State: invalid dst blend state bits\n" ); + break; + } + + // Only actually update GL's blend func if blending is enabled. + if( srcFactor == GL_ONE && dstFactor == GL_ZERO ) + { + glDisable( GL_BLEND ); + } + else + { + glEnable( GL_BLEND ); + glBlendFunc( srcFactor, dstFactor ); + } + } + + // + // check depthmask + // + if( diff & GLS_DEPTHMASK ) + { + if( stateBits & GLS_DEPTHMASK ) + { + glDepthMask( GL_FALSE ); + } + else + { + glDepthMask( GL_TRUE ); + } + } + + // + // check colormask + // + if( diff & ( GLS_REDMASK | GLS_GREENMASK | GLS_BLUEMASK | GLS_ALPHAMASK ) ) + { + GLboolean r = ( stateBits & GLS_REDMASK ) ? GL_FALSE : GL_TRUE; + GLboolean g = ( stateBits & GLS_GREENMASK ) ? GL_FALSE : GL_TRUE; + GLboolean b = ( stateBits & GLS_BLUEMASK ) ? GL_FALSE : GL_TRUE; + GLboolean a = ( stateBits & GLS_ALPHAMASK ) ? GL_FALSE : GL_TRUE; + glColorMask( r, g, b, a ); + } + + // + // fill/line mode + // + if( diff & GLS_POLYMODE_LINE ) + { + if( stateBits & GLS_POLYMODE_LINE ) + { + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + } + else + { + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + } + } + + // + // polygon offset + // + if( diff & GLS_POLYGON_OFFSET ) + { + if( stateBits & GLS_POLYGON_OFFSET ) + { + glPolygonOffset( polyOfsScale, polyOfsBias ); + glEnable( GL_POLYGON_OFFSET_FILL ); + glEnable( GL_POLYGON_OFFSET_LINE ); + } + else + { + glDisable( GL_POLYGON_OFFSET_FILL ); + glDisable( GL_POLYGON_OFFSET_LINE ); + } + } + +#if !defined( USE_CORE_PROFILE ) + // + // alpha test + // + if( diff & ( GLS_ALPHATEST_FUNC_BITS | GLS_ALPHATEST_FUNC_REF_BITS ) ) + { + if( ( stateBits & GLS_ALPHATEST_FUNC_BITS ) != 0 ) + { + glEnable( GL_ALPHA_TEST ); + + GLenum func = GL_ALWAYS; + switch( stateBits & GLS_ALPHATEST_FUNC_BITS ) + { + case GLS_ALPHATEST_FUNC_LESS: + func = GL_LESS; + break; + case GLS_ALPHATEST_FUNC_EQUAL: + func = GL_EQUAL; + break; + case GLS_ALPHATEST_FUNC_GREATER: + func = GL_GEQUAL; + break; + default: + assert( false ); + } + GLclampf ref = ( ( stateBits & GLS_ALPHATEST_FUNC_REF_BITS ) >> GLS_ALPHATEST_FUNC_REF_SHIFT ) / ( float )0xFF; + glAlphaFunc( func, ref ); + } + else + { + glDisable( GL_ALPHA_TEST ); + } + } +#endif + + // + // stencil + // + if( diff & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS ) ) + { + if( ( stateBits & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS ) ) != 0 ) + { + glEnable( GL_STENCIL_TEST ); + } + else + { + glDisable( GL_STENCIL_TEST ); + } + } + if( diff & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_FUNC_REF_BITS | GLS_STENCIL_FUNC_MASK_BITS ) ) + { + GLuint ref = GLuint( ( stateBits & GLS_STENCIL_FUNC_REF_BITS ) >> GLS_STENCIL_FUNC_REF_SHIFT ); + GLuint mask = GLuint( ( stateBits & GLS_STENCIL_FUNC_MASK_BITS ) >> GLS_STENCIL_FUNC_MASK_SHIFT ); + GLenum func = 0; + + switch( stateBits & GLS_STENCIL_FUNC_BITS ) + { + case GLS_STENCIL_FUNC_NEVER: + func = GL_NEVER; + break; + case GLS_STENCIL_FUNC_LESS: + func = GL_LESS; + break; + case GLS_STENCIL_FUNC_EQUAL: + func = GL_EQUAL; + break; + case GLS_STENCIL_FUNC_LEQUAL: + func = GL_LEQUAL; + break; + case GLS_STENCIL_FUNC_GREATER: + func = GL_GREATER; + break; + case GLS_STENCIL_FUNC_NOTEQUAL: + func = GL_NOTEQUAL; + break; + case GLS_STENCIL_FUNC_GEQUAL: + func = GL_GEQUAL; + break; + case GLS_STENCIL_FUNC_ALWAYS: + func = GL_ALWAYS; + break; + } + glStencilFunc( func, ref, mask ); + } + if( diff & ( GLS_STENCIL_OP_FAIL_BITS | GLS_STENCIL_OP_ZFAIL_BITS | GLS_STENCIL_OP_PASS_BITS ) ) + { + GLenum sFail = 0; + GLenum zFail = 0; + GLenum pass = 0; + + switch( stateBits & GLS_STENCIL_OP_FAIL_BITS ) + { + case GLS_STENCIL_OP_FAIL_KEEP: + sFail = GL_KEEP; + break; + case GLS_STENCIL_OP_FAIL_ZERO: + sFail = GL_ZERO; + break; + case GLS_STENCIL_OP_FAIL_REPLACE: + sFail = GL_REPLACE; + break; + case GLS_STENCIL_OP_FAIL_INCR: + sFail = GL_INCR; + break; + case GLS_STENCIL_OP_FAIL_DECR: + sFail = GL_DECR; + break; + case GLS_STENCIL_OP_FAIL_INVERT: + sFail = GL_INVERT; + break; + case GLS_STENCIL_OP_FAIL_INCR_WRAP: + sFail = GL_INCR_WRAP; + break; + case GLS_STENCIL_OP_FAIL_DECR_WRAP: + sFail = GL_DECR_WRAP; + break; + } + switch( stateBits & GLS_STENCIL_OP_ZFAIL_BITS ) + { + case GLS_STENCIL_OP_ZFAIL_KEEP: + zFail = GL_KEEP; + break; + case GLS_STENCIL_OP_ZFAIL_ZERO: + zFail = GL_ZERO; + break; + case GLS_STENCIL_OP_ZFAIL_REPLACE: + zFail = GL_REPLACE; + break; + case GLS_STENCIL_OP_ZFAIL_INCR: + zFail = GL_INCR; + break; + case GLS_STENCIL_OP_ZFAIL_DECR: + zFail = GL_DECR; + break; + case GLS_STENCIL_OP_ZFAIL_INVERT: + zFail = GL_INVERT; + break; + case GLS_STENCIL_OP_ZFAIL_INCR_WRAP: + zFail = GL_INCR_WRAP; + break; + case GLS_STENCIL_OP_ZFAIL_DECR_WRAP: + zFail = GL_DECR_WRAP; + break; + } + switch( stateBits & GLS_STENCIL_OP_PASS_BITS ) + { + case GLS_STENCIL_OP_PASS_KEEP: + pass = GL_KEEP; + break; + case GLS_STENCIL_OP_PASS_ZERO: + pass = GL_ZERO; + break; + case GLS_STENCIL_OP_PASS_REPLACE: + pass = GL_REPLACE; + break; + case GLS_STENCIL_OP_PASS_INCR: + pass = GL_INCR; + break; + case GLS_STENCIL_OP_PASS_DECR: + pass = GL_DECR; + break; + case GLS_STENCIL_OP_PASS_INVERT: + pass = GL_INVERT; + break; + case GLS_STENCIL_OP_PASS_INCR_WRAP: + pass = GL_INCR_WRAP; + break; + case GLS_STENCIL_OP_PASS_DECR_WRAP: + pass = GL_DECR_WRAP; + break; + } + glStencilOp( sFail, zFail, pass ); + } + + glStateBits = stateBits; +} + +/* +==================== +idRenderBackend::SelectTexture +==================== +*/ +void idRenderBackend::GL_SelectTexture( int unit ) +{ + if( currenttmu == unit ) + { + return; + } + + if( unit < 0 || unit >= glConfig.maxTextureImageUnits ) + { + common->Warning( "GL_SelectTexture: unit = %i", unit ); + return; + } + + RENDERLOG_PRINTF( "GL_SelectTexture( %i );\n", unit ); + + currenttmu = unit; +} + +/* +==================== +idRenderBackend::GL_Cull + +This handles the flipping needed when the view being +rendered is a mirored view. +==================== +*/ +void idRenderBackend::GL_Cull( cullType_t cullType ) +{ + if( faceCulling == cullType ) + { + return; + } + + if( cullType == CT_TWO_SIDED ) + { + glDisable( GL_CULL_FACE ); + } + else + { + if( faceCulling == CT_TWO_SIDED ) + { + glEnable( GL_CULL_FACE ); + } + + if( cullType == CT_BACK_SIDED ) + { + if( viewDef->isMirror ) + { + glCullFace( GL_FRONT ); + } + else + { + glCullFace( GL_BACK ); + } + } + else + { + if( viewDef->isMirror ) + { + glCullFace( GL_BACK ); + } + else + { + glCullFace( GL_FRONT ); + } + } + } + + faceCulling = cullType; +} + +/* +==================== +idRenderBackend::GL_Scissor +==================== +*/ +void idRenderBackend::GL_Scissor( int x /* left*/, int y /* bottom */, int w, int h ) +{ + glScissor( x, y, w, h ); +} + +/* +==================== +idRenderBackend::GL_Viewport +==================== +*/ +void idRenderBackend::GL_Viewport( int x /* left */, int y /* bottom */, int w, int h ) +{ + glViewport( x, y, w, h ); +} + +/* +==================== +idRenderBackend::GL_PolygonOffset +==================== +*/ +void idRenderBackend::GL_PolygonOffset( float scale, float bias ) +{ + polyOfsScale = scale; + polyOfsBias = bias; + + if( glStateBits & GLS_POLYGON_OFFSET ) + { + glPolygonOffset( scale, bias ); + } +} + +/* +======================== +idRenderBackend::GL_DepthBoundsTest +======================== +*/ +void idRenderBackend::GL_DepthBoundsTest( const float zmin, const float zmax ) +{ + if( !glConfig.depthBoundsTestAvailable || zmin > zmax ) + { + return; + } + + if( zmin == 0.0f && zmax == 0.0f ) + { + glDisable( GL_DEPTH_BOUNDS_TEST_EXT ); + } + else + { + glEnable( GL_DEPTH_BOUNDS_TEST_EXT ); + glDepthBoundsEXT( zmin, zmax ); + } +} + +/* +==================== +idRenderBackend::GL_Color +==================== +*/ +void idRenderBackend::GL_Color( float r, float g, float b, float a ) +{ + float parm[4]; + parm[0] = idMath::ClampFloat( 0.0f, 1.0f, r ); + parm[1] = idMath::ClampFloat( 0.0f, 1.0f, g ); + parm[2] = idMath::ClampFloat( 0.0f, 1.0f, b ); + parm[3] = idMath::ClampFloat( 0.0f, 1.0f, a ); + renderProgManager.SetRenderParm( RENDERPARM_COLOR, parm ); +} + +/* +======================== +idRenderBackend::GL_Clear +======================== +*/ +void idRenderBackend::GL_Clear( bool color, bool depth, bool stencil, byte stencilValue, float r, float g, float b, float a, bool clearHDR ) +{ + int clearFlags = 0; + if( color ) + { + glClearColor( r, g, b, a ); + clearFlags |= GL_COLOR_BUFFER_BIT; + } + if( depth ) + { + clearFlags |= GL_DEPTH_BUFFER_BIT; + } + if( stencil ) + { + glClearStencil( stencilValue ); + clearFlags |= GL_STENCIL_BUFFER_BIT; + } + glClear( clearFlags ); + + // RB begin + if( r_useHDR.GetBool() && clearHDR && globalFramebuffers.hdrFBO != NULL ) + { + bool isDefaultFramebufferActive = Framebuffer::IsDefaultFramebufferActive(); + + globalFramebuffers.hdrFBO->Bind(); + glClear( clearFlags ); + + if( isDefaultFramebufferActive ) + { + Framebuffer::Unbind(); + } + } + // RB end +} + + +/* +================= +idRenderBackend::GL_GetCurrentState +================= +*/ +uint64 idRenderBackend::GL_GetCurrentState() const +{ + return tr.backend.glStateBits; +} + +/* +======================== +idRenderBackend::GL_GetCurrentStateMinusStencil +======================== +*/ +uint64 idRenderBackend::GL_GetCurrentStateMinusStencil() const +{ + return GL_GetCurrentState() & ~( GLS_STENCIL_OP_BITS | GLS_STENCIL_FUNC_BITS | GLS_STENCIL_FUNC_REF_BITS | GLS_STENCIL_FUNC_MASK_BITS ); +} + + +/* +============= +idRenderBackend::CheckCVars + +See if some cvars that we watch have changed +============= +*/ +void idRenderBackend::CheckCVars() +{ + // gamma stuff + if( r_gamma.IsModified() || r_brightness.IsModified() ) + { + r_gamma.ClearModified(); + r_brightness.ClearModified(); + R_SetColorMappings(); + } + + // filtering + if( r_maxAnisotropicFiltering.IsModified() || r_useTrilinearFiltering.IsModified() || r_lodBias.IsModified() ) + { + idLib::Printf( "Updating texture filter parameters.\n" ); + r_maxAnisotropicFiltering.ClearModified(); + r_useTrilinearFiltering.ClearModified(); + r_lodBias.ClearModified(); + + for( int i = 0 ; i < globalImages->images.Num() ; i++ ) + { + if( globalImages->images[i] ) + { + globalImages->images[i]->Bind(); + globalImages->images[i]->SetTexParameters(); + } + } + } + + extern idCVar r_useSeamlessCubeMap; + if( r_useSeamlessCubeMap.IsModified() ) + { + r_useSeamlessCubeMap.ClearModified(); + if( glConfig.seamlessCubeMapAvailable ) + { + if( r_useSeamlessCubeMap.GetBool() ) + { + glEnable( GL_TEXTURE_CUBE_MAP_SEAMLESS ); + } + else + { + glDisable( GL_TEXTURE_CUBE_MAP_SEAMLESS ); + } + } + } + + extern idCVar r_useSRGB; + if( r_useSRGB.IsModified() ) + { + r_useSRGB.ClearModified(); + if( glConfig.sRGBFramebufferAvailable ) + { + if( r_useSRGB.GetBool() && r_useSRGB.GetInteger() != 3 ) + { + glEnable( GL_FRAMEBUFFER_SRGB ); + } + else + { + glDisable( GL_FRAMEBUFFER_SRGB ); + } + } + } + + if( r_antiAliasing.IsModified() ) + { + switch( r_antiAliasing.GetInteger() ) + { + case ANTI_ALIASING_MSAA_2X: + case ANTI_ALIASING_MSAA_4X: + case ANTI_ALIASING_MSAA_8X: + if( r_antiAliasing.GetInteger() > 0 ) + { + glEnable( GL_MULTISAMPLE ); + } + break; + + default: + glDisable( GL_MULTISAMPLE ); + break; + } + } + + if( r_useHDR.IsModified() || r_useHalfLambertLighting.IsModified() ) + { + r_useHDR.ClearModified(); + r_useHalfLambertLighting.ClearModified(); + renderProgManager.KillAllShaders(); + renderProgManager.LoadAllShaders(); + } + + // RB: turn off shadow mapping for OpenGL drivers that are too slow + switch( glConfig.driverType ) + { + case GLDRV_OPENGL_ES2: + case GLDRV_OPENGL_ES3: + //case GLDRV_OPENGL_MESA: + r_useShadowMapping.SetInteger( 0 ); + break; + + default: + break; + } + // RB end +} + +/* +============================================================================ + +RENDER BACK END THREAD FUNCTIONS + +============================================================================ +*/ + +/* +============= +idRenderBackend::DrawFlickerBox +============= +*/ +void idRenderBackend::DrawFlickerBox() +{ + if( !r_drawFlickerBox.GetBool() ) + { + return; + } + if( tr.frameCount & 1 ) + { + glClearColor( 1, 0, 0, 1 ); + } + else + { + glClearColor( 0, 1, 0, 1 ); + } + glScissor( 0, 0, 256, 256 ); + glClear( GL_COLOR_BUFFER_BIT ); +} + +/* +============= +idRenderBackend::SetBuffer +============= +*/ +void idRenderBackend::SetBuffer( const void* data ) +{ + // see which draw buffer we want to render the frame to + + const setBufferCommand_t* cmd = ( const setBufferCommand_t* )data; + + RENDERLOG_PRINTF( "---------- RB_SetBuffer ---------- to buffer # %d\n", cmd->buffer ); + + GL_Scissor( 0, 0, tr.GetWidth(), tr.GetHeight() ); + + // clear screen for debugging + // automatically enable this with several other debug tools + // that might leave unrendered portions of the screen + if( r_clear.GetFloat() || idStr::Length( r_clear.GetString() ) != 1 || r_singleArea.GetBool() || r_showOverDraw.GetBool() ) + { + float c[3]; + if( sscanf( r_clear.GetString(), "%f %f %f", &c[0], &c[1], &c[2] ) == 3 ) + { + GL_Clear( true, false, false, 0, c[0], c[1], c[2], 1.0f, true ); + } + else if( r_clear.GetInteger() == 2 ) + { + GL_Clear( true, false, false, 0, 0.0f, 0.0f, 0.0f, 1.0f, true ); + } + else if( r_showOverDraw.GetBool() ) + { + GL_Clear( true, false, false, 0, 1.0f, 1.0f, 1.0f, 1.0f, true ); + } + else + { + GL_Clear( true, false, false, 0, 0.4f, 0.0f, 0.25f, 1.0f, true ); + } + } +} + +/* +============= +GL_BlockingSwapBuffers + +We want to exit this with the GPU idle, right at vsync +============= +*/ +void idRenderBackend::BlockingSwapBuffers() +{ + RENDERLOG_PRINTF( "***************** GL_BlockingSwapBuffers *****************\n\n\n" ); + + const int beforeFinish = Sys_Milliseconds(); + + if( !glConfig.syncAvailable ) + { + glFinish(); + } + + const int beforeSwap = Sys_Milliseconds(); + if( r_showSwapBuffers.GetBool() && beforeSwap - beforeFinish > 1 ) + { + common->Printf( "%i msec to glFinish\n", beforeSwap - beforeFinish ); + } + + GLimp_SwapBuffers(); + + const int beforeFence = Sys_Milliseconds(); + if( r_showSwapBuffers.GetBool() && beforeFence - beforeSwap > 1 ) + { + common->Printf( "%i msec to swapBuffers\n", beforeFence - beforeSwap ); + } + + if( glConfig.syncAvailable ) + { + swapIndex ^= 1; + + if( glIsSync( renderSync[swapIndex] ) ) + { + glDeleteSync( renderSync[swapIndex] ); + } + // draw something tiny to ensure the sync is after the swap + const int start = Sys_Milliseconds(); + glScissor( 0, 0, 1, 1 ); + glEnable( GL_SCISSOR_TEST ); + glClear( GL_COLOR_BUFFER_BIT ); + renderSync[swapIndex] = glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 ); + const int end = Sys_Milliseconds(); + if( r_showSwapBuffers.GetBool() && end - start > 1 ) + { + common->Printf( "%i msec to start fence\n", end - start ); + } + + GLsync syncToWaitOn; + if( r_syncEveryFrame.GetBool() ) + { + syncToWaitOn = renderSync[swapIndex]; + } + else + { + syncToWaitOn = renderSync[!swapIndex]; + } + + if( glIsSync( syncToWaitOn ) ) + { + for( GLenum r = GL_TIMEOUT_EXPIRED; r == GL_TIMEOUT_EXPIRED; ) + { + r = glClientWaitSync( syncToWaitOn, GL_SYNC_FLUSH_COMMANDS_BIT, 1000 * 1000 ); + } + } + } + + const int afterFence = Sys_Milliseconds(); + if( r_showSwapBuffers.GetBool() && afterFence - beforeFence > 1 ) + { + common->Printf( "%i msec to wait on fence\n", afterFence - beforeFence ); + } + + const int64 exitBlockTime = Sys_Microseconds(); + + static int64 prevBlockTime; + if( r_showSwapBuffers.GetBool() && prevBlockTime ) + { + const int delta = ( int )( exitBlockTime - prevBlockTime ); + common->Printf( "blockToBlock: %i\n", delta ); + } + prevBlockTime = exitBlockTime; +} + +/* +============= +idRenderBackend::idRenderBackend +============= +*/ +idRenderBackend::idRenderBackend() +{ + Init(); +} + +/* +============= +idRenderBackend::~idRenderBackend +============= +*/ +idRenderBackend::~idRenderBackend() +{ + +} + +/* +============= +idRenderBackend::Init +============= +*/ +void idRenderBackend::Init() +{ + memset( glcontext.tmu, 0, sizeof( glcontext.tmu ) ); + memset( glcontext.stencilOperations, 0, sizeof( glcontext.stencilOperations ) ); +} + +/* +==================== +R_MakeStereoRenderImage +==================== +*/ +static void R_MakeStereoRenderImage( idImage* image ) +{ + idImageOpts opts; + opts.width = renderSystem->GetWidth(); + opts.height = renderSystem->GetHeight(); + opts.numLevels = 1; + opts.format = FMT_RGBA8; + image->AllocImage( opts, TF_LINEAR, TR_CLAMP ); +} + +/* +==================== +idRenderBackend::StereoRenderExecuteBackEndCommands + +Renders the draw list twice, with slight modifications for left eye / right eye +==================== +*/ +void idRenderBackend::StereoRenderExecuteBackEndCommands( const emptyCommand_t* const allCmds ) +{ + uint64 backEndStartTime = Sys_Microseconds(); + + // If we are in a monoscopic context, this draws to the only buffer, and is + // the same as GL_BACK. In a quad-buffer stereo context, this is necessary + // to prevent GL from forcing the rendering to go to both BACK_LEFT and + // BACK_RIGHT at a performance penalty. + // To allow stereo deghost processing, the views have to be copied to separate + // textures anyway, so there isn't any benefit to rendering to BACK_RIGHT for + // that eye. + glDrawBuffer( GL_BACK_LEFT ); + + // create the stereoRenderImage if we haven't already + static idImage* stereoRenderImages[2]; + for( int i = 0; i < 2; i++ ) + { + if( stereoRenderImages[i] == NULL ) + { + stereoRenderImages[i] = globalImages->ImageFromFunction( va( "_stereoRender%i", i ), R_MakeStereoRenderImage ); + } + + // resize the stereo render image if the main window has changed size + if( stereoRenderImages[i]->GetUploadWidth() != renderSystem->GetWidth() || + stereoRenderImages[i]->GetUploadHeight() != renderSystem->GetHeight() ) + { + stereoRenderImages[i]->Resize( renderSystem->GetWidth(), renderSystem->GetHeight() ); + } + } + + // In stereoRender mode, the front end has generated two RC_DRAW_VIEW commands + // with slightly different origins for each eye. + + // TODO: only do the copy after the final view has been rendered, not mirror subviews? + + // Render the 3D draw views from the screen origin so all the screen relative + // texture mapping works properly, then copy the portion we are going to use + // off to a texture. + bool foundEye[2] = { false, false }; + + for( int stereoEye = 1; stereoEye >= -1; stereoEye -= 2 ) + { + // set up the target texture we will draw to + const int targetEye = ( stereoEye == 1 ) ? 1 : 0; + + // Set the back end into a known default state to fix any stale render state issues + GL_SetDefaultState(); + + renderProgManager.Unbind(); + renderProgManager.ZeroUniforms(); + + for( const emptyCommand_t* cmds = allCmds; cmds != NULL; cmds = ( const emptyCommand_t* )cmds->next ) + { + switch( cmds->commandId ) + { + case RC_NOP: + break; + case RC_DRAW_VIEW_GUI: + case RC_DRAW_VIEW_3D: + { + const drawSurfsCommand_t* const dsc = ( const drawSurfsCommand_t* )cmds; + const viewDef_t& eyeViewDef = *dsc->viewDef; + + if( eyeViewDef.renderView.viewEyeBuffer && eyeViewDef.renderView.viewEyeBuffer != stereoEye ) + { + // this is the render view for the other eye + continue; + } + + foundEye[ targetEye ] = true; + DrawView( dsc, stereoEye ); + if( cmds->commandId == RC_DRAW_VIEW_GUI ) + { + } + } + break; + case RC_SET_BUFFER: + SetBuffer( cmds ); + break; + case RC_COPY_RENDER: + CopyRender( cmds ); + break; + case RC_POST_PROCESS: + { + postProcessCommand_t* cmd = ( postProcessCommand_t* )cmds; + if( cmd->viewDef->renderView.viewEyeBuffer != stereoEye ) + { + break; + } + PostProcess( cmds ); + } + break; + default: + common->Error( "RB_ExecuteBackEndCommands: bad commandId" ); + break; + } + } + + // copy to the target + stereoRenderImages[ targetEye ]->CopyFramebuffer( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() ); + } + + // perform the final compositing / warping / deghosting to the actual framebuffer(s) + assert( foundEye[0] && foundEye[1] ); + + GL_SetDefaultState(); + + RB_SetMVP( renderMatrix_identity ); + + // If we are in quad-buffer pixel format but testing another 3D mode, + // make sure we draw to both eyes. This is likely to be sub-optimal + // performance on most cards and drivers, but it is better than getting + // a confusing, half-ghosted view. + if( renderSystem->GetStereo3DMode() != STEREO3D_QUAD_BUFFER ) + { + glDrawBuffer( GL_BACK ); + } + + GL_State( GLS_DEPTHFUNC_ALWAYS ); + GL_Cull( CT_TWO_SIDED ); + + // We just want to do a quad pass - so make sure we disable any texgen and + // set the texture matrix to the identity so we don't get anomalies from + // any stale uniform data being present from a previous draw call + const float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; + const float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f }; + renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_S, texS ); + renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_T, texT ); + + // disable any texgen + const float texGenEnabled[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + renderProgManager.SetRenderParm( RENDERPARM_TEXGEN_0_ENABLED, texGenEnabled ); + + renderProgManager.BindShader_Texture(); + GL_Color( 1, 1, 1, 1 ); + + switch( renderSystem->GetStereo3DMode() ) + { + case STEREO3D_QUAD_BUFFER: + glDrawBuffer( GL_BACK_RIGHT ); + GL_SelectTexture( 0 ); + stereoRenderImages[1]->Bind(); + GL_SelectTexture( 1 ); + stereoRenderImages[0]->Bind(); + DrawElementsWithCounters( &unitSquareSurface ); + + glDrawBuffer( GL_BACK_LEFT ); + GL_SelectTexture( 1 ); + stereoRenderImages[1]->Bind(); + GL_SelectTexture( 0 ); + stereoRenderImages[0]->Bind(); + DrawElementsWithCounters( &unitSquareSurface ); + break; + + case STEREO3D_HDMI_720: + // HDMI 720P 3D + GL_SelectTexture( 0 ); + stereoRenderImages[1]->Bind(); + GL_SelectTexture( 1 ); + stereoRenderImages[0]->Bind(); + GL_ViewportAndScissor( 0, 0, 1280, 720 ); + DrawElementsWithCounters( &unitSquareSurface ); + + GL_SelectTexture( 0 ); + stereoRenderImages[0]->Bind(); + GL_SelectTexture( 1 ); + stereoRenderImages[1]->Bind(); + GL_ViewportAndScissor( 0, 750, 1280, 720 ); + DrawElementsWithCounters( &unitSquareSurface ); + + // force the HDMI 720P 3D guard band to a constant color + glScissor( 0, 720, 1280, 30 ); + glClear( GL_COLOR_BUFFER_BIT ); + break; + + default: + case STEREO3D_SIDE_BY_SIDE: + if( stereoRender_warp.GetBool() ) + { + // this is the Rift warp + // renderSystem->GetWidth() / GetHeight() have returned equal values (640 for initial Rift) + // and we are going to warp them onto a symetric square region of each half of the screen + + renderProgManager.BindShader_StereoWarp(); + + // clear the entire screen to black + // we could be smart and only clear the areas we aren't going to draw on, but + // clears are fast... + glScissor( 0, 0, glConfig.nativeScreenWidth, glConfig.nativeScreenHeight ); + glClearColor( 0, 0, 0, 0 ); + glClear( GL_COLOR_BUFFER_BIT ); + + // the size of the box that will get the warped pixels + // With the 7" displays, this will be less than half the screen width + const int pixelDimensions = ( glConfig.nativeScreenWidth >> 1 ) * stereoRender_warpTargetFraction.GetFloat(); + + // Always scissor to the half-screen boundary, but the viewports + // might cross that boundary if the lenses can be adjusted closer + // together. + glViewport( ( glConfig.nativeScreenWidth >> 1 ) - pixelDimensions, + ( glConfig.nativeScreenHeight >> 1 ) - ( pixelDimensions >> 1 ), + pixelDimensions, pixelDimensions ); + glScissor( 0, 0, glConfig.nativeScreenWidth >> 1, glConfig.nativeScreenHeight ); + + idVec4 color( stereoRender_warpCenterX.GetFloat(), stereoRender_warpCenterY.GetFloat(), stereoRender_warpParmZ.GetFloat(), stereoRender_warpParmW.GetFloat() ); + // don't use GL_Color(), because we don't want to clamp + renderProgManager.SetRenderParm( RENDERPARM_COLOR, color.ToFloatPtr() ); + + GL_SelectTexture( 0 ); + stereoRenderImages[0]->Bind(); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); + DrawElementsWithCounters( &unitSquareSurface ); + + idVec4 color2( stereoRender_warpCenterX.GetFloat(), stereoRender_warpCenterY.GetFloat(), stereoRender_warpParmZ.GetFloat(), stereoRender_warpParmW.GetFloat() ); + // don't use GL_Color(), because we don't want to clamp + renderProgManager.SetRenderParm( RENDERPARM_COLOR, color2.ToFloatPtr() ); + + glViewport( ( glConfig.nativeScreenWidth >> 1 ), + ( glConfig.nativeScreenHeight >> 1 ) - ( pixelDimensions >> 1 ), + pixelDimensions, pixelDimensions ); + glScissor( glConfig.nativeScreenWidth >> 1, 0, glConfig.nativeScreenWidth >> 1, glConfig.nativeScreenHeight ); + + GL_SelectTexture( 0 ); + stereoRenderImages[1]->Bind(); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); + DrawElementsWithCounters( &unitSquareSurface ); + break; + } + + // a non-warped side-by-side-uncompressed (dual input cable) is rendered + // just like STEREO3D_SIDE_BY_SIDE_COMPRESSED, so fall through. + case STEREO3D_SIDE_BY_SIDE_COMPRESSED: + GL_SelectTexture( 0 ); + stereoRenderImages[0]->Bind(); + GL_SelectTexture( 1 ); + stereoRenderImages[1]->Bind(); + GL_ViewportAndScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() ); + DrawElementsWithCounters( &unitSquareSurface ); + + GL_SelectTexture( 0 ); + stereoRenderImages[1]->Bind(); + GL_SelectTexture( 1 ); + stereoRenderImages[0]->Bind(); + GL_ViewportAndScissor( renderSystem->GetWidth(), 0, renderSystem->GetWidth(), renderSystem->GetHeight() ); + DrawElementsWithCounters( &unitSquareSurface ); + break; + + case STEREO3D_TOP_AND_BOTTOM_COMPRESSED: + GL_SelectTexture( 1 ); + stereoRenderImages[0]->Bind(); + GL_SelectTexture( 0 ); + stereoRenderImages[1]->Bind(); + GL_ViewportAndScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() ); + DrawElementsWithCounters( &unitSquareSurface ); + + GL_SelectTexture( 1 ); + stereoRenderImages[1]->Bind(); + GL_SelectTexture( 0 ); + stereoRenderImages[0]->Bind(); + GL_ViewportAndScissor( 0, renderSystem->GetHeight(), renderSystem->GetWidth(), renderSystem->GetHeight() ); + DrawElementsWithCounters( &unitSquareSurface ); + break; + + case STEREO3D_INTERLACED: + // every other scanline + GL_SelectTexture( 0 ); + stereoRenderImages[0]->Bind(); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + + GL_SelectTexture( 1 ); + stereoRenderImages[1]->Bind(); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + + GL_ViewportAndScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() * 2 ); + renderProgManager.BindShader_StereoInterlace(); + DrawElementsWithCounters( &unitSquareSurface ); + + GL_SelectTexture( 0 ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + GL_SelectTexture( 1 ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + break; + } + + // debug tool + DrawFlickerBox(); + + // make sure the drawing is actually started + glFlush(); + + // we may choose to sync to the swapbuffers before the next frame + + // stop rendering on this thread + uint64 backEndFinishTime = Sys_Microseconds(); + pc.totalMicroSec = backEndFinishTime - backEndStartTime; +} + +/* +==================== +RB_ExecuteBackEndCommands + +This function will be called syncronously if running without +smp extensions, or asyncronously by another thread. +==================== +*/ +void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds ) +{ + // r_debugRenderToTexture + int c_draw3d = 0; + int c_draw2d = 0; + int c_setBuffers = 0; + int c_copyRenders = 0; + + resolutionScale.SetCurrentGPUFrameTime( commonLocal.GetRendererGPUMicroseconds() ); + + renderLog.StartFrame(); + + if( cmds->commandId == RC_NOP && !cmds->next ) + { + return; + } + + if( renderSystem->GetStereo3DMode() != STEREO3D_OFF ) + { + StereoRenderExecuteBackEndCommands( cmds ); + renderLog.EndFrame(); + return; + } + + uint64 backEndStartTime = Sys_Microseconds(); + + // needed for editor rendering + GL_SetDefaultState(); + + // If we have a stereo pixel format, this will draw to both + // the back left and back right buffers, which will have a + // performance penalty. + glDrawBuffer( GL_BACK ); + + for( ; cmds != NULL; cmds = ( const emptyCommand_t* )cmds->next ) + { + switch( cmds->commandId ) + { + case RC_NOP: + break; + case RC_DRAW_VIEW_3D: + case RC_DRAW_VIEW_GUI: + DrawView( cmds, 0 ); + if( ( ( const drawSurfsCommand_t* )cmds )->viewDef->viewEntitys ) + { + c_draw3d++; + } + else + { + c_draw2d++; + } + break; + case RC_SET_BUFFER: + //RB_SetBuffer( cmds ); + c_setBuffers++; + break; + case RC_COPY_RENDER: + CopyRender( cmds ); + c_copyRenders++; + break; + case RC_POST_PROCESS: + PostProcess( cmds ); + break; + default: + common->Error( "RB_ExecuteBackEndCommands: bad commandId" ); + break; + } + } + + DrawFlickerBox(); + + // Fix for the steam overlay not showing up while in game without Shell/Debug/Console/Menu also rendering + glColorMask( 1, 1, 1, 1 ); + + glFlush(); + + // stop rendering on this thread + uint64 backEndFinishTime = Sys_Microseconds(); + pc.totalMicroSec = backEndFinishTime - backEndStartTime; + + if( r_debugRenderToTexture.GetInteger() == 1 ) + { + common->Printf( "3d: %i, 2d: %i, SetBuf: %i, CpyRenders: %i, CpyFrameBuf: %i\n", c_draw3d, c_draw2d, c_setBuffers, c_copyRenders, pc.c_copyFrameBuffer ); + pc.c_copyFrameBuffer = 0; + } + + renderLog.EndFrame(); +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/RenderDebug_GL.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/RenderDebug_GL.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/OpenGL/RenderDebug_GL.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/OpenGL/RenderDebug_GL.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,3115 @@ +/* +=========================================================================== + +Doom 3 BFG Edition GPL Source Code +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2014-2016 Robert Beckebans +Copyright (C) 2014-2016 Kot in Action Creative Artel +Copyright (C) 2016-2017 Dustin Land + +This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). + +Doom 3 BFG Edition Source Code 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. + +Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . + +In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#pragma hdrstop +#include "precompiled.h" + +#include "../RenderCommon.h" +#include "../simplex.h" // line font definition + +idCVar r_showCenterOfProjection( "r_showCenterOfProjection", "0", CVAR_RENDERER | CVAR_BOOL, "Draw a cross to show the center of projection" ); +idCVar r_showLines( "r_showLines", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = draw alternate horizontal lines, 2 = draw alternate vertical lines" ); + + + +debugLine_t rb_debugLines[ MAX_DEBUG_LINES ]; +int rb_numDebugLines = 0; +int rb_debugLineTime = 0; + +debugText_t rb_debugText[ MAX_DEBUG_TEXT ]; +int rb_numDebugText = 0; +int rb_debugTextTime = 0; + +debugPolygon_t rb_debugPolygons[ MAX_DEBUG_POLYGONS ]; +int rb_numDebugPolygons = 0; +int rb_debugPolygonTime = 0; + +static void RB_DrawText( const char* text, const idVec3& origin, float scale, const idVec4& color, const idMat3& viewAxis, const int align ); + +void RB_SetMVP( const idRenderMatrix& mvp ); + +/* +================ +RB_DrawBounds +================ +*/ +void RB_DrawBounds( const idBounds& bounds ) +{ + if( bounds.IsCleared() ) + { + return; + } + glBegin( GL_LINE_LOOP ); + glVertex3f( bounds[0][0], bounds[0][1], bounds[0][2] ); + glVertex3f( bounds[0][0], bounds[1][1], bounds[0][2] ); + glVertex3f( bounds[1][0], bounds[1][1], bounds[0][2] ); + glVertex3f( bounds[1][0], bounds[0][1], bounds[0][2] ); + glEnd(); + glBegin( GL_LINE_LOOP ); + glVertex3f( bounds[0][0], bounds[0][1], bounds[1][2] ); + glVertex3f( bounds[0][0], bounds[1][1], bounds[1][2] ); + glVertex3f( bounds[1][0], bounds[1][1], bounds[1][2] ); + glVertex3f( bounds[1][0], bounds[0][1], bounds[1][2] ); + glEnd(); + + glBegin( GL_LINES ); + glVertex3f( bounds[0][0], bounds[0][1], bounds[0][2] ); + glVertex3f( bounds[0][0], bounds[0][1], bounds[1][2] ); + + glVertex3f( bounds[0][0], bounds[1][1], bounds[0][2] ); + glVertex3f( bounds[0][0], bounds[1][1], bounds[1][2] ); + + glVertex3f( bounds[1][0], bounds[0][1], bounds[0][2] ); + glVertex3f( bounds[1][0], bounds[0][1], bounds[1][2] ); + + glVertex3f( bounds[1][0], bounds[1][1], bounds[0][2] ); + glVertex3f( bounds[1][0], bounds[1][1], bounds[1][2] ); + glEnd(); +} + + +/* +================ +idRenderBackend::DBG_SimpleSurfaceSetup +================ +*/ +void idRenderBackend::DBG_SimpleSurfaceSetup( const drawSurf_t* drawSurf ) +{ + // change the matrix if needed + if( drawSurf->space != currentSpace ) + { + // RB begin + RB_SetMVP( drawSurf->space->mvp ); + //qglLoadMatrixf( drawSurf->space->modelViewMatrix ); + // RB end + currentSpace = drawSurf->space; + } + + // change the scissor if needed + if( !currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) + { + GL_Scissor( viewDef->viewport.x1 + drawSurf->scissorRect.x1, + viewDef->viewport.y1 + drawSurf->scissorRect.y1, + drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1, + drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 ); + + currentScissor = drawSurf->scissorRect; + } +} + +/* +================ +idRenderBackend::DBG_SimpleWorldSetup +================ +*/ +void idRenderBackend::DBG_SimpleWorldSetup() +{ + currentSpace = &viewDef->worldSpace; + + // RB begin + RB_SetMVP( viewDef->worldSpace.mvp ); + // RB end + + GL_Scissor( viewDef->viewport.x1 + viewDef->scissor.x1, + viewDef->viewport.y1 + viewDef->scissor.y1, + viewDef->scissor.x2 + 1 - viewDef->scissor.x1, + viewDef->scissor.y2 + 1 - viewDef->scissor.y1 ); + + currentScissor = viewDef->scissor; +} + +/* +================= +idRenderBackend::DBG_PolygonClear + +This will cover the entire screen with normal rasterization. +Texturing is disabled, but the existing glColor, glDepthMask, +glColorMask, and the enabled state of depth buffering and +stenciling will matter. +================= +*/ +void idRenderBackend::DBG_PolygonClear() +{ + glPushMatrix(); + glPushAttrib( GL_ALL_ATTRIB_BITS ); + glLoadIdentity(); + glDisable( GL_TEXTURE_2D ); + glDisable( GL_DEPTH_TEST ); + glDisable( GL_CULL_FACE ); + glDisable( GL_SCISSOR_TEST ); + glBegin( GL_POLYGON ); + glVertex3f( -20, -20, -10 ); + glVertex3f( 20, -20, -10 ); + glVertex3f( 20, 20, -10 ); + glVertex3f( -20, 20, -10 ); + glEnd(); + glPopAttrib(); + glPopMatrix(); +} + +/* +==================== +idRenderBackend::DBG_ShowDestinationAlpha +==================== +*/ +void idRenderBackend::DBG_ShowDestinationAlpha() +{ + GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + GL_Color( 1, 1, 1 ); + + DBG_PolygonClear(); +} + +/* +=================== +idRenderBackend::DBG_ScanStencilBuffer + +Debugging tool to see what values are in the stencil buffer +=================== +*/ +void idRenderBackend::DBG_ScanStencilBuffer() +{ + int counts[256]; + int i; + byte* stencilReadback; + + memset( counts, 0, sizeof( counts ) ); + + stencilReadback = ( byte* )R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight(), TAG_RENDER_TOOLS ); + glReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); + + for( i = 0; i < renderSystem->GetWidth() * renderSystem->GetHeight(); i++ ) + { + counts[ stencilReadback[i] ]++; + } + + R_StaticFree( stencilReadback ); + + // print some stats (not supposed to do from back end in SMP...) + common->Printf( "stencil values:\n" ); + for( i = 0; i < 255; i++ ) + { + if( counts[i] ) + { + common->Printf( "%i: %i\n", i, counts[i] ); + } + } +} + + +/* +=================== +idRenderBackend::DBG_CountStencilBuffer + +Print an overdraw count based on stencil index values +=================== +*/ +void idRenderBackend::DBG_CountStencilBuffer() +{ + int count; + int i; + byte* stencilReadback; + + + stencilReadback = ( byte* )R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight(), TAG_RENDER_TOOLS ); + glReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); + + count = 0; + for( i = 0; i < renderSystem->GetWidth() * renderSystem->GetHeight(); i++ ) + { + count += stencilReadback[i]; + } + + R_StaticFree( stencilReadback ); + + // print some stats (not supposed to do from back end in SMP...) + common->Printf( "overdraw: %5.1f\n", ( float )count / ( renderSystem->GetWidth() * renderSystem->GetHeight() ) ); +} + +/* +=================== +idRenderBackend::DBG_ColorByStencilBuffer + +Sets the screen colors based on the contents of the +stencil buffer. Stencil of 0 = black, 1 = red, 2 = green, +3 = blue, ..., 7+ = white +=================== +*/ +void idRenderBackend::DBG_ColorByStencilBuffer() +{ + int i; + static idVec3 colors[8] = + { + idVec3( 0, 0, 0 ), + idVec3( 1, 0, 0 ), + idVec3( 0, 1, 0 ), + idVec3( 0, 0, 1 ), + idVec3( 0, 1, 1 ), + idVec3( 1, 0, 1 ), + idVec3( 1, 1, 0 ), + idVec3( 1, 1, 1 ), + }; + + // clear color buffer to white (>6 passes) + GL_Clear( true, false, false, 0, 1.0f, 1.0f, 1.0f, 1.0f ); + + // now draw color for each stencil value + glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + for( i = 0; i < 6; i++ ) + { + GL_Color( colors[i] ); + renderProgManager.BindShader_Color(); + glStencilFunc( GL_EQUAL, i, 255 ); + + DBG_PolygonClear(); + } + + glStencilFunc( GL_ALWAYS, 0, 255 ); +} + +/* +================== +idRenderBackend::DBG_ShowOverdraw +================== +*/ +void idRenderBackend::DBG_ShowOverdraw() +{ + const idMaterial* material; + int i; + drawSurf_t** drawSurfs; + const drawSurf_t* surf; + int numDrawSurfs; + viewLight_t* vLight; + + if( r_showOverDraw.GetInteger() == 0 ) + { + return; + } + + material = declManager->FindMaterial( "textures/common/overdrawtest", false ); + if( material == NULL ) + { + return; + } + + drawSurfs = viewDef->drawSurfs; + numDrawSurfs = viewDef->numDrawSurfs; + + int interactions = 0; + for( vLight = viewDef->viewLights; vLight; vLight = vLight->next ) + { + for( surf = vLight->localInteractions; surf; surf = surf->nextOnLight ) + { + interactions++; + } + for( surf = vLight->globalInteractions; surf; surf = surf->nextOnLight ) + { + interactions++; + } + } + + // FIXME: can't frame alloc from the renderer back-end + drawSurf_t** newDrawSurfs = ( drawSurf_t** )R_FrameAlloc( numDrawSurfs + interactions * sizeof( newDrawSurfs[0] ), FRAME_ALLOC_DRAW_SURFACE_POINTER ); + + for( i = 0; i < numDrawSurfs; i++ ) + { + surf = drawSurfs[i]; + if( surf->material ) + { + const_cast( surf )->material = material; + } + newDrawSurfs[i] = const_cast( surf ); + } + + for( vLight = viewDef->viewLights; vLight; vLight = vLight->next ) + { + for( surf = vLight->localInteractions; surf; surf = surf->nextOnLight ) + { + const_cast( surf )->material = material; + newDrawSurfs[i++] = const_cast( surf ); + } + for( surf = vLight->globalInteractions; surf; surf = surf->nextOnLight ) + { + const_cast( surf )->material = material; + newDrawSurfs[i++] = const_cast( surf ); + } + vLight->localInteractions = NULL; + vLight->globalInteractions = NULL; + } + + switch( r_showOverDraw.GetInteger() ) + { + case 1: // geometry overdraw + const_cast( viewDef )->drawSurfs = newDrawSurfs; + const_cast( viewDef )->numDrawSurfs = numDrawSurfs; + break; + case 2: // light interaction overdraw + const_cast( viewDef )->drawSurfs = &newDrawSurfs[numDrawSurfs]; + const_cast( viewDef )->numDrawSurfs = interactions; + break; + case 3: // geometry + light interaction overdraw + const_cast( viewDef )->drawSurfs = newDrawSurfs; + const_cast( viewDef )->numDrawSurfs += interactions; + break; + } +} + +/* +=================== +idRenderBackend::DBG_ShowIntensity + +Debugging tool to see how much dynamic range a scene is using. +The greatest of the rgb values at each pixel will be used, with +the resulting color shading from red at 0 to green at 128 to blue at 255 +=================== +*/ +void idRenderBackend::DBG_ShowIntensity() +{ + byte* colorReadback; + int i, j, c; + + if( !r_showIntensity.GetBool() ) + { + return; + } + + colorReadback = ( byte* )R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight() * 4, TAG_RENDER_TOOLS ); + glReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_RGBA, GL_UNSIGNED_BYTE, colorReadback ); + + c = renderSystem->GetWidth() * renderSystem->GetHeight() * 4; + for( i = 0; i < c; i += 4 ) + { + j = colorReadback[i]; + if( colorReadback[i + 1] > j ) + { + j = colorReadback[i + 1]; + } + if( colorReadback[i + 2] > j ) + { + j = colorReadback[i + 2]; + } + if( j < 128 ) + { + colorReadback[i + 0] = 2 * ( 128 - j ); + colorReadback[i + 1] = 2 * j; + colorReadback[i + 2] = 0; + } + else + { + colorReadback[i + 0] = 0; + colorReadback[i + 1] = 2 * ( 255 - j ); + colorReadback[i + 2] = 2 * ( j - 128 ); + } + } + + // draw it back to the screen + glLoadIdentity(); + glMatrixMode( GL_PROJECTION ); + GL_State( GLS_DEPTHFUNC_ALWAYS ); + glPushMatrix(); + glLoadIdentity(); + glOrtho( 0, 1, 0, 1, -1, 1 ); + glRasterPos2f( 0, 0 ); + glPopMatrix(); + GL_Color( 1, 1, 1 ); + glMatrixMode( GL_MODELVIEW ); + + glDrawPixels( renderSystem->GetWidth(), renderSystem->GetHeight(), GL_RGBA , GL_UNSIGNED_BYTE, colorReadback ); + + R_StaticFree( colorReadback ); +} + + +/* +=================== +idRenderBackend::DBG_ShowDepthBuffer + +Draw the depth buffer as colors +=================== +*/ +void idRenderBackend::DBG_ShowDepthBuffer() +{ + void* depthReadback; + + if( !r_showDepth.GetBool() ) + { + return; + } + + glPushMatrix(); + glLoadIdentity(); + glMatrixMode( GL_PROJECTION ); + glPushMatrix(); + glLoadIdentity(); + glOrtho( 0, 1, 0, 1, -1, 1 ); + glRasterPos2f( 0, 0 ); + glPopMatrix(); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); + + GL_State( GLS_DEPTHFUNC_ALWAYS ); + GL_Color( 1, 1, 1 ); + + depthReadback = R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight() * 4, TAG_RENDER_TOOLS ); + memset( depthReadback, 0, renderSystem->GetWidth() * renderSystem->GetHeight() * 4 ); + + glReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_DEPTH_COMPONENT , GL_FLOAT, depthReadback ); + +#if 0 + for( i = 0; i < renderSystem->GetWidth() * renderSystem->GetHeight(); i++ ) + { + ( ( byte* )depthReadback )[i * 4] = + ( ( byte* )depthReadback )[i * 4 + 1] = + ( ( byte* )depthReadback )[i * 4 + 2] = 255 * ( ( float* )depthReadback )[i]; + ( ( byte* )depthReadback )[i * 4 + 3] = 1; + } +#endif + + glDrawPixels( renderSystem->GetWidth(), renderSystem->GetHeight(), GL_RGBA , GL_UNSIGNED_BYTE, depthReadback ); + R_StaticFree( depthReadback ); +} + +/* +================= +idRenderBackend::DBG_ShowLightCount + +This is a debugging tool that will draw each surface with a color +based on how many lights are effecting it +================= +*/ +void idRenderBackend::DBG_ShowLightCount() +{ + int i; + const drawSurf_t* surf; + const viewLight_t* vLight; + + if( !r_showLightCount.GetBool() ) + { + return; + } + + DBG_SimpleWorldSetup(); + + GL_Clear( false, false, true, 0, 0.0f, 0.0f, 0.0f, 0.0f ); + + // optionally count everything through walls + if( r_showLightCount.GetInteger() >= 2 ) + { + GL_State( GLS_DEPTHFUNC_EQUAL | GLS_STENCIL_OP_FAIL_KEEP | GLS_STENCIL_OP_ZFAIL_INCR | GLS_STENCIL_OP_PASS_INCR ); + } + else + { + GL_State( GLS_DEPTHFUNC_EQUAL | GLS_STENCIL_OP_FAIL_KEEP | GLS_STENCIL_OP_ZFAIL_KEEP | GLS_STENCIL_OP_PASS_INCR ); + } + + globalImages->defaultImage->Bind(); + + for( vLight = viewDef->viewLights; vLight; vLight = vLight->next ) + { + for( i = 0; i < 2; i++ ) + { + for( surf = i ? vLight->localInteractions : vLight->globalInteractions; surf; surf = ( drawSurf_t* )surf->nextOnLight ) + { + DBG_SimpleSurfaceSetup( surf ); + DrawElementsWithCounters( surf ); + } + } + } + + // display the results + DBG_ColorByStencilBuffer(); + + if( r_showLightCount.GetInteger() > 2 ) + { + DBG_CountStencilBuffer(); + } +} + +/* +==================== +idRenderBackend::DBG_RenderDrawSurfListWithFunction + +The triangle functions can check backEnd.currentSpace != surf->space +to see if they need to perform any new matrix setup. The modelview +matrix will already have been loaded, and backEnd.currentSpace will +be updated after the triangle function completes. +==================== +*/ +void idRenderBackend::DBG_RenderDrawSurfListWithFunction( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + currentSpace = NULL; + + for( int i = 0 ; i < numDrawSurfs ; i++ ) + { + const drawSurf_t* drawSurf = drawSurfs[i]; + if( drawSurf == NULL ) + { + continue; + } + + assert( drawSurf->space != NULL ); + + // RB begin +#if 1 + if( drawSurf->space != currentSpace ) + { + currentSpace = drawSurf->space; + + RB_SetMVP( drawSurf->space->mvp ); + } +#else + + if( drawSurf->space != NULL ) // is it ever NULL? Do we need to check? + { + // Set these values ahead of time so we don't have to reconstruct the matrices on the consoles + if( drawSurf->space->weaponDepthHack ) + { + RB_SetWeaponDepthHack(); + } + + if( drawSurf->space->modelDepthHack != 0.0f ) + { + RB_SetModelDepthHack( drawSurf->space->modelDepthHack ); + } + + // change the matrix if needed + if( drawSurf->space != backEnd.currentSpace ) + { + RB_LoadMatrixWithBypass( drawSurf->space->modelViewMatrix ); + } + + if( drawSurf->space->weaponDepthHack ) + { + RB_EnterWeaponDepthHack(); + } + + if( drawSurf->space->modelDepthHack != 0.0f ) + { + RB_EnterModelDepthHack( drawSurf->space->modelDepthHack ); + } + } +#endif + + if( drawSurf->jointCache ) + { + renderProgManager.BindShader_ColorSkinned(); + } + else + { + renderProgManager.BindShader_Color(); + } + // RB end + + // change the scissor if needed + if( r_useScissor.GetBool() && !currentScissor.Equals( drawSurf->scissorRect ) ) + { + currentScissor = drawSurf->scissorRect; + + GL_Scissor( viewDef->viewport.x1 + currentScissor.x1, + viewDef->viewport.y1 + currentScissor.y1, + currentScissor.x2 + 1 - currentScissor.x1, + currentScissor.y2 + 1 - currentScissor.y1 ); + } + + // render it + DrawElementsWithCounters( drawSurf ); + + // RB begin + /*if( drawSurf->space != NULL && ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) ) + { + RB_LeaveDepthHack(); + }*/ + // RB end + + currentSpace = drawSurf->space; + } +} + +/* +================= +idRenderBackend::DBG_ShowSilhouette + +Blacks out all edges, then adds color for each edge that a shadow +plane extends from, allowing you to see doubled edges + +FIXME: not thread safe! +================= +*/ +void idRenderBackend::DBG_ShowSilhouette() +{ + int i; + const drawSurf_t* surf; + const viewLight_t* vLight; + + if( !r_showSilhouette.GetBool() ) + { + return; + } + + // clear all triangle edges to black + + // RB + renderProgManager.BindShader_Color(); + + GL_Color( 0, 0, 0 ); + GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE ); + GL_Cull( CT_TWO_SIDED ); + + DBG_RenderDrawSurfListWithFunction( viewDef->drawSurfs, viewDef->numDrawSurfs ); + + + // now blend in edges that cast silhouettes + DBG_SimpleWorldSetup(); + + GL_Color( 0.5, 0, 0 ); + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); + + for( vLight = viewDef->viewLights; vLight; vLight = vLight->next ) + { + for( i = 0; i < 2; i++ ) + { + for( surf = i ? vLight->localShadows : vLight->globalShadows + ; surf; surf = ( drawSurf_t* )surf->nextOnLight ) + { + DBG_SimpleSurfaceSetup( surf ); + + const srfTriangles_t* tri = surf->frontEndGeo; + + idVertexBuffer vertexBuffer; + if( !vertexCache.GetVertexBuffer( tri->shadowCache, &vertexBuffer ) ) + { + continue; + } + + // RB: 64 bit fixes, changed GLuint to GLintptr + glBindBuffer( GL_ARRAY_BUFFER, ( GLintptr )vertexBuffer.GetAPIObject() ); + GLintptr vertOffset = vertexBuffer.GetOffset(); + // RB end + + glVertexPointer( 3, GL_FLOAT, sizeof( idShadowVert ), ( void* )vertOffset ); + glBegin( GL_LINES ); + + for( int j = 0; j < tri->numIndexes; j += 3 ) + { + int i1 = tri->indexes[j + 0]; + int i2 = tri->indexes[j + 1]; + int i3 = tri->indexes[j + 2]; + + if( ( i1 & 1 ) + ( i2 & 1 ) + ( i3 & 1 ) == 1 ) + { + if( ( i1 & 1 ) + ( i2 & 1 ) == 0 ) + { + glArrayElement( i1 ); + glArrayElement( i2 ); + } + else if( ( i1 & 1 ) + ( i3 & 1 ) == 0 ) + { + glArrayElement( i1 ); + glArrayElement( i3 ); + } + } + } + glEnd(); + + } + } + } + + GL_State( GLS_DEFAULT ); + GL_Color( 1, 1, 1 ); + GL_Cull( CT_FRONT_SIDED ); +} + +/* +===================== +idRenderBackend::DBG_ShowTris + +Debugging tool +===================== +*/ +void idRenderBackend::DBG_ShowTris( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + + modelTrace_t mt; + idVec3 end; + + if( r_showTris.GetInteger() == 0 ) + { + return; + } + + idVec4 color( 1, 1, 1, 1 ); + + GL_PolygonOffset( -1.0f, -2.0f ); + + switch( r_showTris.GetInteger() ) + { + case 1: // only draw visible ones + GL_State( GLS_DEPTHMASK | GLS_ALPHAMASK | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET ); + break; + case 2: // draw all front facing + case 3: // draw all + GL_State( GLS_DEPTHMASK | GLS_ALPHAMASK | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET | GLS_DEPTHFUNC_ALWAYS ); + break; + case 4: // only draw visible ones with blended lines + GL_State( GLS_DEPTHMASK | GLS_ALPHAMASK | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); + color[3] = 0.4f; + break; + } + + if( r_showTris.GetInteger() == 3 ) + { + GL_Cull( CT_TWO_SIDED ); + } + + GL_Color( color ); + + DBG_RenderDrawSurfListWithFunction( drawSurfs, numDrawSurfs ); + + if( r_showTris.GetInteger() == 3 ) + { + GL_Cull( CT_FRONT_SIDED ); + } +} + +/* +===================== +idRenderBackend::DBG_ShowSurfaceInfo + +Debugging tool +===================== +*/ + + +static idStr surfModelName, surfMatName; +static idVec3 surfPoint; +static bool surfTraced = false; + + +void idRenderSystemLocal::OnFrame() +{ + // Do tracing at a safe time to avoid threading issues. + modelTrace_t mt; + idVec3 start, end; + + surfTraced = false; + + if( !r_showSurfaceInfo.GetBool() ) + { + return; + } + + if( tr.primaryView == NULL ) + { + return; + } + + // start far enough away that we don't hit the player model + start = tr.primaryView->renderView.vieworg + tr.primaryView->renderView.viewaxis[0] * 32; + end = start + tr.primaryView->renderView.viewaxis[0] * 1000.0f; + if( !tr.primaryWorld->Trace( mt, start, end, 0.0f, false ) ) + { + return; + } + + surfPoint = mt.point; + surfModelName = mt.entity->hModel->Name(); + surfMatName = mt.material->GetName(); + surfTraced = true; +} + + +void idRenderBackend::DBG_ShowSurfaceInfo( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + if( !r_showSurfaceInfo.GetBool() || !surfTraced ) + { + return; + } + + // globalImages->BindNull(); + // qglDisable( GL_TEXTURE_2D ); + + DBG_SimpleWorldSetup(); + + // foresthale 2014-05-02: don't use a shader for tools + //renderProgManager.BindShader_TextureVertexColor(); + GL_SelectTexture( 0 ); + globalImages->whiteImage->Bind(); + + RB_SetVertexColorParms( SVC_MODULATE ); + // foresthale 2014-05-02: don't use a shader for tools + //renderProgManager.CommitUniforms(); + + GL_Color( 1, 1, 1 ); + + static float scale = -1; + static float bias = -2; + + GL_PolygonOffset( scale, bias ); + GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET ); + + // idVec3 trans[3]; + // float matrix[16]; + + // transform the object verts into global space + // R_AxisToModelMatrix( mt.entity->axis, mt.entity->origin, matrix ); + + tr.primaryWorld->DrawText( surfModelName, surfPoint + tr.primaryView->renderView.viewaxis[2] * 12, + 0.35f, colorRed, tr.primaryView->renderView.viewaxis ); + tr.primaryWorld->DrawText( surfMatName, surfPoint, + 0.35f, colorBlue, tr.primaryView->renderView.viewaxis ); +} + +/* +===================== +idRenderBackend::DBG_ShowViewEntitys + +Debugging tool +===================== +*/ +void idRenderBackend::DBG_ShowViewEntitys( viewEntity_t* vModels ) +{ + if( !r_showViewEntitys.GetBool() ) + { + return; + } + + if( r_showViewEntitys.GetInteger() >= 2 ) + { + common->Printf( "view entities: " ); + for( const viewEntity_t* vModel = vModels; vModel; vModel = vModel->next ) + { + if( vModel->entityDef->IsDirectlyVisible() ) + { + common->Printf( "<%i> ", vModel->entityDef->index ); + } + else + { + common->Printf( "%i ", vModel->entityDef->index ); + } + } + common->Printf( "\n" ); + } + + renderProgManager.BindShader_Color(); + + GL_Color( 1, 1, 1 ); + GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE ); + GL_Cull( CT_TWO_SIDED ); + + for( const viewEntity_t* vModel = vModels; vModel; vModel = vModel->next ) + { + idBounds b; + + //glLoadMatrixf( vModel->modelViewMatrix ); + + const idRenderEntityLocal* edef = vModel->entityDef; + if( !edef ) + { + continue; + } + + // draw the model bounds in white if directly visible, + // or, blue if it is only-for-sahdow + idVec4 color; + if( edef->IsDirectlyVisible() ) + { + color.Set( 1, 1, 1, 1 ); + } + else + { + color.Set( 0, 0, 1, 1 ); + } + GL_Color( color[0], color[1], color[2] ); + RB_DrawBounds( edef->localReferenceBounds ); + + // transform the upper bounds corner into global space + if( r_showViewEntitys.GetInteger() >= 2 ) + { + idVec3 corner; + R_LocalPointToGlobal( vModel->modelMatrix, edef->localReferenceBounds[1], corner ); + + tr.primaryWorld->DrawText( + va( "%i:%s", edef->index, edef->parms.hModel->Name() ), + corner, + 0.25f, color, + tr.primaryView->renderView.viewaxis ); + } + + // draw the actual bounds in yellow if different + if( r_showViewEntitys.GetInteger() >= 3 ) + { + GL_Color( 1, 1, 0 ); + // FIXME: cannot instantiate a dynamic model from the renderer back-end + idRenderModel* model = R_EntityDefDynamicModel( vModel->entityDef ); + if( !model ) + { + continue; // particles won't instantiate without a current view + } + b = model->Bounds( &vModel->entityDef->parms ); + if( b != vModel->entityDef->localReferenceBounds ) + { + RB_DrawBounds( b ); + } + } + } +} + +/* +===================== +idRenderBackend::DBG_ShowTexturePolarity + +Shade triangle red if they have a positive texture area +green if they have a negative texture area, or blue if degenerate area +===================== +*/ +void idRenderBackend::DBG_ShowTexturePolarity( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + int i, j; + drawSurf_t* drawSurf; + const srfTriangles_t* tri; + + if( !r_showTexturePolarity.GetBool() ) + { + return; + } + + GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); + + GL_Color( 1, 1, 1 ); + + for( i = 0; i < numDrawSurfs; i++ ) + { + drawSurf = drawSurfs[i]; + tri = drawSurf->frontEndGeo; + if( tri == NULL || tri->verts == NULL ) + { + continue; + } + + DBG_SimpleSurfaceSetup( drawSurf ); + + glBegin( GL_TRIANGLES ); + for( j = 0; j < tri->numIndexes; j += 3 ) + { + idDrawVert* a, *b, *c; + float d0[5], d1[5]; + float area; + + a = tri->verts + tri->indexes[j]; + b = tri->verts + tri->indexes[j + 1]; + c = tri->verts + tri->indexes[j + 2]; + + const idVec2 aST = a->GetTexCoord(); + const idVec2 bST = b->GetTexCoord(); + const idVec2 cST = c->GetTexCoord(); + + d0[3] = bST[0] - aST[0]; + d0[4] = bST[1] - aST[1]; + + d1[3] = cST[0] - aST[0]; + d1[4] = cST[1] - aST[1]; + + area = d0[3] * d1[4] - d0[4] * d1[3]; + + if( idMath::Fabs( area ) < 0.0001 ) + { + GL_Color( 0, 0, 1, 0.5 ); + } + else if( area < 0 ) + { + GL_Color( 1, 0, 0, 0.5 ); + } + else + { + GL_Color( 0, 1, 0, 0.5 ); + } + glVertex3fv( a->xyz.ToFloatPtr() ); + glVertex3fv( b->xyz.ToFloatPtr() ); + glVertex3fv( c->xyz.ToFloatPtr() ); + } + glEnd(); + } + + GL_State( GLS_DEFAULT ); +} + +/* +===================== +idRenderBackend::DBG_ShowUnsmoothedTangents + +Shade materials that are using unsmoothed tangents +===================== +*/ +void idRenderBackend::DBG_ShowUnsmoothedTangents( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + int i, j; + drawSurf_t* drawSurf; + const srfTriangles_t* tri; + + if( !r_showUnsmoothedTangents.GetBool() ) + { + return; + } + + GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); + + GL_Color( 0, 1, 0, 0.5 ); + + for( i = 0; i < numDrawSurfs; i++ ) + { + drawSurf = drawSurfs[i]; + + if( !drawSurf->material->UseUnsmoothedTangents() ) + { + continue; + } + + DBG_SimpleSurfaceSetup( drawSurf ); + + tri = drawSurf->frontEndGeo; + if( tri == NULL || tri->verts == NULL ) + { + continue; + } + + glBegin( GL_TRIANGLES ); + for( j = 0; j < tri->numIndexes; j += 3 ) + { + idDrawVert* a, *b, *c; + + a = tri->verts + tri->indexes[j]; + b = tri->verts + tri->indexes[j + 1]; + c = tri->verts + tri->indexes[j + 2]; + + glVertex3fv( a->xyz.ToFloatPtr() ); + glVertex3fv( b->xyz.ToFloatPtr() ); + glVertex3fv( c->xyz.ToFloatPtr() ); + } + glEnd(); + } + + GL_State( GLS_DEFAULT ); +} + +/* +===================== +RB_ShowTangentSpace + +Shade a triangle by the RGB colors of its tangent space +1 = tangents[0] +2 = tangents[1] +3 = normal +===================== +*/ +void idRenderBackend::DBG_ShowTangentSpace( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + int i, j; + drawSurf_t* drawSurf; + const srfTriangles_t* tri; + + if( !r_showTangentSpace.GetInteger() ) + { + return; + } + + GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); + + for( i = 0; i < numDrawSurfs; i++ ) + { + drawSurf = drawSurfs[i]; + + DBG_SimpleSurfaceSetup( drawSurf ); + + tri = drawSurf->frontEndGeo; + if( tri == NULL || tri->verts == NULL ) + { + continue; + } + + glBegin( GL_TRIANGLES ); + for( j = 0; j < tri->numIndexes; j++ ) + { + const idDrawVert* v; + + v = &tri->verts[tri->indexes[j]]; + + if( r_showTangentSpace.GetInteger() == 1 ) + { + const idVec3 vertexTangent = v->GetTangent(); + GL_Color( 0.5 + 0.5 * vertexTangent[0], 0.5 + 0.5 * vertexTangent[1], + 0.5 + 0.5 * vertexTangent[2], 0.5 ); + } + else if( r_showTangentSpace.GetInteger() == 2 ) + { + const idVec3 vertexBiTangent = v->GetBiTangent(); + GL_Color( 0.5 + 0.5 * vertexBiTangent[0], 0.5 + 0.5 * vertexBiTangent[1], + 0.5 + 0.5 * vertexBiTangent[2], 0.5 ); + } + else + { + const idVec3 vertexNormal = v->GetNormal(); + GL_Color( 0.5 + 0.5 * vertexNormal[0], 0.5 + 0.5 * vertexNormal[1], + 0.5 + 0.5 * vertexNormal[2], 0.5 ); + } + glVertex3fv( v->xyz.ToFloatPtr() ); + } + glEnd(); + } + + GL_State( GLS_DEFAULT ); +} + +/* +===================== +idRenderBackend::DBG_ShowVertexColor + +Draw each triangle with the solid vertex colors +===================== +*/ +void idRenderBackend::DBG_ShowVertexColor( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + int i, j; + drawSurf_t* drawSurf; + const srfTriangles_t* tri; + + if( !r_showVertexColor.GetBool() ) + { + return; + } + + // RB begin + renderProgManager.BindShader_VertexColor(); + + GL_State( GLS_DEPTHFUNC_LESS ); + + for( i = 0; i < numDrawSurfs; i++ ) + { + drawSurf = drawSurfs[i]; + + DBG_SimpleSurfaceSetup( drawSurf ); + + tri = drawSurf->frontEndGeo; + if( tri == NULL || tri->verts == NULL ) + { + continue; + } + + renderProgManager.CommitUniforms(); + + glBegin( GL_TRIANGLES ); + for( j = 0; j < tri->numIndexes; j++ ) + { + const idDrawVert* v; + + v = &tri->verts[tri->indexes[j]]; + glColor4ubv( v->color ); + glVertex3fv( v->xyz.ToFloatPtr() ); + } + glEnd(); + } + + // RB end + + GL_State( GLS_DEFAULT ); +} + +/* +===================== +idRenderBackend::DBG_ShowNormals + +Debugging tool +===================== +*/ +void idRenderBackend::DBG_ShowNormals( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + int i, j; + drawSurf_t* drawSurf; + idVec3 end; + const srfTriangles_t* tri; + float size; + bool showNumbers; + idVec3 pos; + + if( r_showNormals.GetFloat() == 0.0f ) + { + return; + } + + if( !r_debugLineDepthTest.GetBool() ) + { + GL_State( GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS ); + } + else + { + GL_State( GLS_POLYMODE_LINE ); + } + + size = r_showNormals.GetFloat(); + if( size < 0.0f ) + { + size = -size; + showNumbers = true; + } + else + { + showNumbers = false; + } + + for( i = 0; i < numDrawSurfs; i++ ) + { + drawSurf = drawSurfs[i]; + + DBG_SimpleSurfaceSetup( drawSurf ); + + tri = drawSurf->frontEndGeo; + if( tri == NULL || tri->verts == NULL ) + { + continue; + } + + // RB begin + renderProgManager.BindShader_VertexColor(); + + glBegin( GL_LINES ); + for( j = 0; j < tri->numVerts; j++ ) + { + const idVec3 normal = tri->verts[j].GetNormal(); + const idVec3 tangent = tri->verts[j].GetTangent(); + const idVec3 bitangent = tri->verts[j].GetBiTangent(); + + glColor3f( 0, 0, 1 ); + glVertex3fv( tri->verts[j].xyz.ToFloatPtr() ); + VectorMA( tri->verts[j].xyz, size, normal, end ); + glVertex3fv( end.ToFloatPtr() ); + + glColor3f( 1, 0, 0 ); + glVertex3fv( tri->verts[j].xyz.ToFloatPtr() ); + VectorMA( tri->verts[j].xyz, size, tangent, end ); + glVertex3fv( end.ToFloatPtr() ); + + glColor3f( 0, 1, 0 ); + glVertex3fv( tri->verts[j].xyz.ToFloatPtr() ); + VectorMA( tri->verts[j].xyz, size, bitangent, end ); + glVertex3fv( end.ToFloatPtr() ); + } + glEnd(); + + // RB end + } + + if( showNumbers ) + { + DBG_SimpleWorldSetup(); + + for( i = 0; i < numDrawSurfs; i++ ) + { + drawSurf = drawSurfs[i]; + tri = drawSurf->frontEndGeo; + if( tri == NULL || tri->verts == NULL ) + { + continue; + } + + for( j = 0; j < tri->numVerts; j++ ) + { + const idVec3 normal = tri->verts[j].GetNormal(); + const idVec3 tangent = tri->verts[j].GetTangent(); + R_LocalPointToGlobal( drawSurf->space->modelMatrix, tri->verts[j].xyz + tangent + normal * 0.2f, pos ); + RB_DrawText( va( "%d", j ), pos, 0.01f, colorWhite, viewDef->renderView.viewaxis, 1 ); + } + + for( j = 0; j < tri->numIndexes; j += 3 ) + { + const idVec3 normal = tri->verts[ tri->indexes[ j + 0 ] ].GetNormal(); + R_LocalPointToGlobal( drawSurf->space->modelMatrix, ( tri->verts[ tri->indexes[ j + 0 ] ].xyz + tri->verts[ tri->indexes[ j + 1 ] ].xyz + tri->verts[ tri->indexes[ j + 2 ] ].xyz ) * ( 1.0f / 3.0f ) + normal * 0.2f, pos ); + RB_DrawText( va( "%d", j / 3 ), pos, 0.01f, colorCyan, viewDef->renderView.viewaxis, 1 ); + } + } + } +} + +/* +===================== +idRenderBackend::DBG_ShowTextureVectors + +Draw texture vectors in the center of each triangle +===================== +*/ +void idRenderBackend::DBG_ShowTextureVectors( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + if( r_showTextureVectors.GetFloat() == 0.0f ) + { + return; + } + + GL_State( GLS_DEPTHFUNC_LESS ); + + for( int i = 0; i < numDrawSurfs; i++ ) + { + drawSurf_t* drawSurf = drawSurfs[i]; + + const srfTriangles_t* tri = drawSurf->frontEndGeo; + + if( tri == NULL || tri->verts == NULL ) + { + continue; + } + + DBG_SimpleSurfaceSetup( drawSurf ); + + // draw non-shared edges in yellow + glBegin( GL_LINES ); + + for( int j = 0; j < tri->numIndexes; j += 3 ) + { + float d0[5], d1[5]; + idVec3 temp; + idVec3 tangents[2]; + + const idDrawVert* a = &tri->verts[tri->indexes[j + 0]]; + const idDrawVert* b = &tri->verts[tri->indexes[j + 1]]; + const idDrawVert* c = &tri->verts[tri->indexes[j + 2]]; + + const idPlane plane( a->xyz, b->xyz, c->xyz ); + + // make the midpoint slightly above the triangle + const idVec3 mid = ( a->xyz + b->xyz + c->xyz ) * ( 1.0f / 3.0f ) + 0.1f * plane.Normal(); + + // calculate the texture vectors + const idVec2 aST = a->GetTexCoord(); + const idVec2 bST = b->GetTexCoord(); + const idVec2 cST = c->GetTexCoord(); + + d0[0] = b->xyz[0] - a->xyz[0]; + d0[1] = b->xyz[1] - a->xyz[1]; + d0[2] = b->xyz[2] - a->xyz[2]; + d0[3] = bST[0] - aST[0]; + d0[4] = bST[1] - aST[1]; + + d1[0] = c->xyz[0] - a->xyz[0]; + d1[1] = c->xyz[1] - a->xyz[1]; + d1[2] = c->xyz[2] - a->xyz[2]; + d1[3] = cST[0] - aST[0]; + d1[4] = cST[1] - aST[1]; + + const float area = d0[3] * d1[4] - d0[4] * d1[3]; + if( area == 0 ) + { + continue; + } + const float inva = 1.0f / area; + + temp[0] = ( d0[0] * d1[4] - d0[4] * d1[0] ) * inva; + temp[1] = ( d0[1] * d1[4] - d0[4] * d1[1] ) * inva; + temp[2] = ( d0[2] * d1[4] - d0[4] * d1[2] ) * inva; + temp.Normalize(); + tangents[0] = temp; + + temp[0] = ( d0[3] * d1[0] - d0[0] * d1[3] ) * inva; + temp[1] = ( d0[3] * d1[1] - d0[1] * d1[3] ) * inva; + temp[2] = ( d0[3] * d1[2] - d0[2] * d1[3] ) * inva; + temp.Normalize(); + tangents[1] = temp; + + // draw the tangents + tangents[0] = mid + tangents[0] * r_showTextureVectors.GetFloat(); + tangents[1] = mid + tangents[1] * r_showTextureVectors.GetFloat(); + + GL_Color( 1, 0, 0 ); + glVertex3fv( mid.ToFloatPtr() ); + glVertex3fv( tangents[0].ToFloatPtr() ); + + GL_Color( 0, 1, 0 ); + glVertex3fv( mid.ToFloatPtr() ); + glVertex3fv( tangents[1].ToFloatPtr() ); + } + + glEnd(); + } +} + +/* +===================== +idRenderBackend::DBG_ShowDominantTris + +Draw lines from each vertex to the dominant triangle center +===================== +*/ +void idRenderBackend::DBG_ShowDominantTris( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + int i, j; + drawSurf_t* drawSurf; + const srfTriangles_t* tri; + + if( !r_showDominantTri.GetBool() ) + { + return; + } + + GL_State( GLS_DEPTHFUNC_LESS ); + + GL_PolygonOffset( -1, -2 ); + glEnable( GL_POLYGON_OFFSET_LINE ); + + for( i = 0; i < numDrawSurfs; i++ ) + { + drawSurf = drawSurfs[i]; + + tri = drawSurf->frontEndGeo; + + if( tri == NULL || tri->verts == NULL ) + { + continue; + } + if( !tri->dominantTris ) + { + continue; + } + + DBG_SimpleSurfaceSetup( drawSurf ); + + GL_Color( 1, 1, 0 ); + glBegin( GL_LINES ); + + for( j = 0; j < tri->numVerts; j++ ) + { + const idDrawVert* a, *b, *c; + idVec3 mid; + + // find the midpoint of the dominant tri + + a = &tri->verts[j]; + b = &tri->verts[tri->dominantTris[j].v2]; + c = &tri->verts[tri->dominantTris[j].v3]; + + mid = ( a->xyz + b->xyz + c->xyz ) * ( 1.0f / 3.0f ); + + glVertex3fv( mid.ToFloatPtr() ); + glVertex3fv( a->xyz.ToFloatPtr() ); + } + + glEnd(); + } + glDisable( GL_POLYGON_OFFSET_LINE ); +} + +/* +===================== +idRenderBackend::DBG_ShowEdges + +Debugging tool +===================== +*/ +void idRenderBackend::DBG_ShowEdges( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + int i, j, k, m, n, o; + drawSurf_t* drawSurf; + const srfTriangles_t* tri; + const silEdge_t* edge; + int danglePlane; + + if( !r_showEdges.GetBool() ) + { + return; + } + + GL_State( GLS_DEPTHFUNC_ALWAYS ); + + for( i = 0; i < numDrawSurfs; i++ ) + { + drawSurf = drawSurfs[i]; + + tri = drawSurf->frontEndGeo; + + idDrawVert* ac = ( idDrawVert* )tri->verts; + if( !ac ) + { + continue; + } + + DBG_SimpleSurfaceSetup( drawSurf ); + + // draw non-shared edges in yellow + GL_Color( 1, 1, 0 ); + glBegin( GL_LINES ); + + for( j = 0; j < tri->numIndexes; j += 3 ) + { + for( k = 0; k < 3; k++ ) + { + int l, i1, i2; + l = ( k == 2 ) ? 0 : k + 1; + i1 = tri->indexes[j + k]; + i2 = tri->indexes[j + l]; + + // if these are used backwards, the edge is shared + for( m = 0; m < tri->numIndexes; m += 3 ) + { + for( n = 0; n < 3; n++ ) + { + o = ( n == 2 ) ? 0 : n + 1; + if( tri->indexes[m + n] == i2 && tri->indexes[m + o] == i1 ) + { + break; + } + } + if( n != 3 ) + { + break; + } + } + + // if we didn't find a backwards listing, draw it in yellow + if( m == tri->numIndexes ) + { + glVertex3fv( ac[ i1 ].xyz.ToFloatPtr() ); + glVertex3fv( ac[ i2 ].xyz.ToFloatPtr() ); + } + + } + } + + glEnd(); + + // draw dangling sil edges in red + if( !tri->silEdges ) + { + continue; + } + + // the plane number after all real planes + // is the dangling edge + danglePlane = tri->numIndexes / 3; + + GL_Color( 1, 0, 0 ); + + glBegin( GL_LINES ); + for( j = 0; j < tri->numSilEdges; j++ ) + { + edge = tri->silEdges + j; + + if( edge->p1 != danglePlane && edge->p2 != danglePlane ) + { + continue; + } + + glVertex3fv( ac[ edge->v1 ].xyz.ToFloatPtr() ); + glVertex3fv( ac[ edge->v2 ].xyz.ToFloatPtr() ); + } + glEnd(); + } +} + +/* +============== +RB_ShowLights + +Visualize all light volumes used in the current scene +r_showLights 1 : just print volumes numbers, highlighting ones covering the view +r_showLights 2 : also draw planes of each volume +r_showLights 3 : also draw edges of each volume +============== +*/ +void idRenderBackend::DBG_ShowLights() +{ + if( !r_showLights.GetInteger() ) + { + return; + } + + GL_State( GLS_DEFAULT ); + + renderProgManager.BindShader_Color(); + + GL_Cull( CT_TWO_SIDED ); + + common->Printf( "volumes: " ); // FIXME: not in back end! + + int count = 0; + for( viewLight_t* vLight = viewDef->viewLights; vLight != NULL; vLight = vLight->next ) + { + count++; + + // depth buffered planes + if( r_showLights.GetInteger() >= 2 ) + { + GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK ); + + // RB: show different light types + if( vLight->parallel ) + { + GL_Color( 1.0f, 0.0f, 0.0f, 0.25f ); + } + else if( vLight->pointLight ) + { + GL_Color( 0.0f, 0.0f, 1.0f, 0.25f ); + } + else + { + GL_Color( 0.0f, 1.0f, 0.0f, 0.25f ); + } + // RB end + + idRenderMatrix invProjectMVPMatrix; + idRenderMatrix::Multiply( viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix ); + RB_SetMVP( invProjectMVPMatrix ); + DrawElementsWithCounters( &zeroOneCubeSurface ); + } + + // non-hidden lines + if( r_showLights.GetInteger() >= 3 ) + { + GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE | GLS_DEPTHMASK ); + GL_Color( 1.0f, 1.0f, 1.0f ); + idRenderMatrix invProjectMVPMatrix; + idRenderMatrix::Multiply( viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix ); + RB_SetMVP( invProjectMVPMatrix ); + DrawElementsWithCounters( &zeroOneCubeSurface ); + } + + common->Printf( "%i ", vLight->lightDef->index ); + } + + common->Printf( " = %i total\n", count ); +} + +// RB begin +void idRenderBackend::DBG_ShowShadowMapLODs() +{ + if( !r_showShadowMapLODs.GetInteger() ) + { + return; + } + + GL_State( GLS_DEFAULT ); + + renderProgManager.BindShader_Color(); + + GL_Cull( CT_TWO_SIDED ); + + common->Printf( "volumes: " ); // FIXME: not in back end! + + int count = 0; + for( viewLight_t* vLight = viewDef->viewLights; vLight != NULL; vLight = vLight->next ) + { + if( !vLight->lightDef->LightCastsShadows() ) + { + continue; + } + + count++; + + // depth buffered planes + if( r_showShadowMapLODs.GetInteger() >= 1 ) + { + GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK ); + + idVec4 c; + if( vLight->shadowLOD == 0 ) + { + c = colorRed; + } + else if( vLight->shadowLOD == 1 ) + { + c = colorGreen; + } + else if( vLight->shadowLOD == 2 ) + { + c = colorBlue; + } + else if( vLight->shadowLOD == 3 ) + { + c = colorYellow; + } + else if( vLight->shadowLOD == 4 ) + { + c = colorMagenta; + } + else if( vLight->shadowLOD == 5 ) + { + c = colorCyan; + } + else + { + c = colorMdGrey; + } + + c[3] = 0.25f; + GL_Color( c ); + + idRenderMatrix invProjectMVPMatrix; + idRenderMatrix::Multiply( viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix ); + RB_SetMVP( invProjectMVPMatrix ); + DrawElementsWithCounters( &zeroOneCubeSurface ); + } + + // non-hidden lines + if( r_showShadowMapLODs.GetInteger() >= 2 ) + { + GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE | GLS_DEPTHMASK ); + GL_Color( 1.0f, 1.0f, 1.0f ); + idRenderMatrix invProjectMVPMatrix; + idRenderMatrix::Multiply( viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix ); + RB_SetMVP( invProjectMVPMatrix ); + DrawElementsWithCounters( &zeroOneCubeSurface ); + } + + common->Printf( "%i ", vLight->lightDef->index ); + } + + common->Printf( " = %i total\n", count ); +} +// RB end + +/* +===================== +idRenderBackend::DBG_ShowPortals + +Debugging tool, won't work correctly with SMP or when mirrors are present +===================== +*/ +void idRenderBackend::DBG_ShowPortals() +{ + if( !r_showPortals.GetBool() ) + { + return; + } + + // all portals are expressed in world coordinates + DBG_SimpleWorldSetup(); + + renderProgManager.BindShader_Color(); + GL_State( GLS_DEPTHFUNC_ALWAYS ); + + idRenderWorldLocal& world = *viewDef->renderWorld; + + // flood out through portals, setting area viewCount + for( int i = 0; i < world.numPortalAreas; i++ ) + { + portalArea_t* area = &world.portalAreas[i]; + + if( area->viewCount != tr.viewCount ) + { + continue; + } + + for( portal_t* p = area->portals; p; p = p->next ) + { + idWinding* w = p->w; + if( !w ) + { + continue; + } + + if( world.portalAreas[ p->intoArea ].viewCount != tr.viewCount ) + { + // red = can't see + GL_Color( 1, 0, 0 ); + } + else + { + // green = see through + GL_Color( 0, 1, 0 ); + } + + // RB begin + renderProgManager.CommitUniforms(); + // RB end + + glBegin( GL_LINE_LOOP ); + for( int j = 0; j < w->GetNumPoints(); j++ ) + { + glVertex3fv( ( *w )[j].ToFloatPtr() ); + } + glEnd(); + } + } +} + +/* +================ +idRenderBackend::DBG_ClearDebugText +================ +*/ +void RB_ClearDebugText( int time ) +{ + int i; + int num; + debugText_t* text; + + rb_debugTextTime = time; + + if( !time ) + { + // free up our strings + text = rb_debugText; + for( i = 0; i < MAX_DEBUG_TEXT; i++, text++ ) + { + text->text.Clear(); + } + rb_numDebugText = 0; + return; + } + + // copy any text that still needs to be drawn + num = 0; + text = rb_debugText; + for( i = 0; i < rb_numDebugText; i++, text++ ) + { + if( text->lifeTime > time ) + { + if( num != i ) + { + rb_debugText[ num ] = *text; + } + num++; + } + } + rb_numDebugText = num; +} + +/* +================ +RB_AddDebugText +================ +*/ +void RB_AddDebugText( const char* text, const idVec3& origin, float scale, const idVec4& color, const idMat3& viewAxis, const int align, const int lifetime, const bool depthTest ) +{ + debugText_t* debugText; + + if( rb_numDebugText < MAX_DEBUG_TEXT ) + { + debugText = &rb_debugText[ rb_numDebugText++ ]; + debugText->text = text; + debugText->origin = origin; + debugText->scale = scale; + debugText->color = color; + debugText->viewAxis = viewAxis; + debugText->align = align; + debugText->lifeTime = rb_debugTextTime + lifetime; + debugText->depthTest = depthTest; + } +} + +/* +================ +RB_DrawTextLength + + returns the length of the given text +================ +*/ +float RB_DrawTextLength( const char* text, float scale, int len ) +{ + int i, num, index, charIndex; + float spacing, textLen = 0.0f; + + if( text && *text ) + { + if( !len ) + { + len = strlen( text ); + } + for( i = 0; i < len; i++ ) + { + charIndex = text[i] - 32; + if( charIndex < 0 || charIndex > NUM_SIMPLEX_CHARS ) + { + continue; + } + num = simplex[charIndex][0] * 2; + spacing = simplex[charIndex][1]; + index = 2; + + while( index - 2 < num ) + { + if( simplex[charIndex][index] < 0 ) + { + index++; + continue; + } + index += 2; + if( simplex[charIndex][index] < 0 ) + { + index++; + continue; + } + } + textLen += spacing * scale; + } + } + return textLen; +} + +/* +================ +RB_DrawText + + oriented on the viewaxis + align can be 0-left, 1-center (default), 2-right +================ +*/ +static void RB_DrawText( const char* text, const idVec3& origin, float scale, const idVec4& color, const idMat3& viewAxis, const int align ) +{ + renderProgManager.BindShader_Color(); + + // RB begin + //GL_Color( color[0], color[1], color[2], 1 /*color[3]*/ ); + renderProgManager.CommitUniforms(); + // RB end + + int i, j, len, num, index, charIndex, line; + float textLen = 1.0f, spacing = 1.0f; + idVec3 org, p1, p2; + + if( text && *text ) + { + glBegin( GL_LINES ); + + if( text[0] == '\n' ) + { + line = 1; + } + else + { + line = 0; + } + + len = strlen( text ); + for( i = 0; i < len; i++ ) + { + + if( i == 0 || text[i] == '\n' ) + { + org = origin - viewAxis[2] * ( line * 36.0f * scale ); + if( align != 0 ) + { + for( j = 1; i + j <= len; j++ ) + { + if( i + j == len || text[i + j] == '\n' ) + { + textLen = RB_DrawTextLength( text + i, scale, j ); + break; + } + } + if( align == 2 ) + { + // right + org += viewAxis[1] * textLen; + } + else + { + // center + org += viewAxis[1] * ( textLen * 0.5f ); + } + } + line++; + } + + charIndex = text[i] - 32; + if( charIndex < 0 || charIndex > NUM_SIMPLEX_CHARS ) + { + continue; + } + num = simplex[charIndex][0] * 2; + spacing = simplex[charIndex][1]; + index = 2; + + while( index - 2 < num ) + { + if( simplex[charIndex][index] < 0 ) + { + index++; + continue; + } + p1 = org + scale * simplex[charIndex][index] * -viewAxis[1] + scale * simplex[charIndex][index + 1] * viewAxis[2]; + index += 2; + if( simplex[charIndex][index] < 0 ) + { + index++; + continue; + } + p2 = org + scale * simplex[charIndex][index] * -viewAxis[1] + scale * simplex[charIndex][index + 1] * viewAxis[2]; + + glVertex3fv( p1.ToFloatPtr() ); + glVertex3fv( p2.ToFloatPtr() ); + } + org -= viewAxis[1] * ( spacing * scale ); + } + + glEnd(); + } +} + +/* +================ +idRenderBackend::DBG_ShowDebugText +================ +*/ +void idRenderBackend::DBG_ShowDebugText() +{ + int i; + int width; + debugText_t* text; + + if( !rb_numDebugText ) + { + return; + } + + // all lines are expressed in world coordinates + DBG_SimpleWorldSetup(); + + width = r_debugLineWidth.GetInteger(); + if( width < 1 ) + { + width = 1; + } + else if( width > 10 ) + { + width = 10; + } + + // draw lines + glLineWidth( width ); + + + if( !r_debugLineDepthTest.GetBool() ) + { + GL_State( GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS ); + } + else + { + GL_State( GLS_POLYMODE_LINE ); + } + + text = rb_debugText; + for( i = 0; i < rb_numDebugText; i++, text++ ) + { + if( !text->depthTest ) + { + GL_Color( text->color.ToVec3() ); + RB_DrawText( text->text, text->origin, text->scale, text->color, text->viewAxis, text->align ); + } + } + + if( !r_debugLineDepthTest.GetBool() ) + { + GL_State( GLS_POLYMODE_LINE ); + } + + text = rb_debugText; + for( i = 0; i < rb_numDebugText; i++, text++ ) + { + if( text->depthTest ) + { + GL_Color( text->color.ToVec3() ); + RB_DrawText( text->text, text->origin, text->scale, text->color, text->viewAxis, text->align ); + } + } + + glLineWidth( 1 ); +} + +/* +================ +RB_ClearDebugLines +================ +*/ +void RB_ClearDebugLines( int time ) +{ + int i; + int num; + debugLine_t* line; + + rb_debugLineTime = time; + + if( !time ) + { + rb_numDebugLines = 0; + return; + } + + // copy any lines that still need to be drawn + num = 0; + line = rb_debugLines; + for( i = 0; i < rb_numDebugLines; i++, line++ ) + { + if( line->lifeTime > time ) + { + if( num != i ) + { + rb_debugLines[ num ] = *line; + } + num++; + } + } + rb_numDebugLines = num; +} + +/* +================ +RB_AddDebugLine +================ +*/ +void RB_AddDebugLine( const idVec4& color, const idVec3& start, const idVec3& end, const int lifeTime, const bool depthTest ) +{ + debugLine_t* line; + + if( rb_numDebugLines < MAX_DEBUG_LINES ) + { + line = &rb_debugLines[ rb_numDebugLines++ ]; + line->rgb = color; + line->start = start; + line->end = end; + line->depthTest = depthTest; + line->lifeTime = rb_debugLineTime + lifeTime; + } +} + +/* +================ +idRenderBackend::DBG_ShowDebugLines +================ +*/ +void idRenderBackend::DBG_ShowDebugLines() +{ + int i; + int width; + debugLine_t* line; + + if( !rb_numDebugLines ) + { + return; + } + + // all lines are expressed in world coordinates + DBG_SimpleWorldSetup(); + + // RB begin + renderProgManager.BindShader_VertexColor(); + renderProgManager.CommitUniforms(); + // RB end + + width = r_debugLineWidth.GetInteger(); + if( width < 1 ) + { + width = 1; + } + else if( width > 10 ) + { + width = 10; + } + + // draw lines + glLineWidth( width ); + + if( !r_debugLineDepthTest.GetBool() ) + { + GL_State( GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS ); + } + else + { + GL_State( GLS_POLYMODE_LINE ); + } + + glBegin( GL_LINES ); + + line = rb_debugLines; + for( i = 0; i < rb_numDebugLines; i++, line++ ) + { + if( !line->depthTest ) + { + glColor3fv( line->rgb.ToFloatPtr() ); + glVertex3fv( line->start.ToFloatPtr() ); + glVertex3fv( line->end.ToFloatPtr() ); + } + } + glEnd(); + + if( !r_debugLineDepthTest.GetBool() ) + { + GL_State( GLS_POLYMODE_LINE ); + } + + glBegin( GL_LINES ); + + line = rb_debugLines; + for( i = 0; i < rb_numDebugLines; i++, line++ ) + { + if( line->depthTest ) + { + glColor4fv( line->rgb.ToFloatPtr() ); + glVertex3fv( line->start.ToFloatPtr() ); + glVertex3fv( line->end.ToFloatPtr() ); + } + } + + glEnd(); + + glLineWidth( 1 ); + GL_State( GLS_DEFAULT ); +} + +/* +================ +RB_ClearDebugPolygons +================ +*/ +void RB_ClearDebugPolygons( int time ) +{ + int i; + int num; + debugPolygon_t* poly; + + rb_debugPolygonTime = time; + + if( !time ) + { + rb_numDebugPolygons = 0; + return; + } + + // copy any polygons that still need to be drawn + num = 0; + + poly = rb_debugPolygons; + for( i = 0; i < rb_numDebugPolygons; i++, poly++ ) + { + if( poly->lifeTime > time ) + { + if( num != i ) + { + rb_debugPolygons[ num ] = *poly; + } + num++; + } + } + rb_numDebugPolygons = num; +} + +/* +================ +RB_AddDebugPolygon +================ +*/ +void RB_AddDebugPolygon( const idVec4& color, const idWinding& winding, const int lifeTime, const bool depthTest ) +{ + debugPolygon_t* poly; + + if( rb_numDebugPolygons < MAX_DEBUG_POLYGONS ) + { + poly = &rb_debugPolygons[ rb_numDebugPolygons++ ]; + poly->rgb = color; + poly->winding = winding; + poly->depthTest = depthTest; + poly->lifeTime = rb_debugPolygonTime + lifeTime; + } +} + +/* +================ +idRenderBackend::DBG_ShowDebugPolygons +================ +*/ +void idRenderBackend::DBG_ShowDebugPolygons() +{ + int i, j; + debugPolygon_t* poly; + + if( !rb_numDebugPolygons ) + { + return; + } + + // all lines are expressed in world coordinates + DBG_SimpleWorldSetup(); + + // RB begin + renderProgManager.BindShader_VertexColor(); + renderProgManager.CommitUniforms(); + // RB end + + if( r_debugPolygonFilled.GetBool() ) + { + GL_State( GLS_POLYGON_OFFSET | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK ); + GL_PolygonOffset( -1, -2 ); + } + else + { + GL_State( GLS_POLYGON_OFFSET | GLS_POLYMODE_LINE ); + GL_PolygonOffset( -1, -2 ); + } + + poly = rb_debugPolygons; + for( i = 0; i < rb_numDebugPolygons; i++, poly++ ) + { +// if ( !poly->depthTest ) { + + glColor4fv( poly->rgb.ToFloatPtr() ); + + glBegin( GL_POLYGON ); + + for( j = 0; j < poly->winding.GetNumPoints(); j++ ) + { + glVertex3fv( poly->winding[j].ToFloatPtr() ); + } + + glEnd(); +// } + } + + GL_State( GLS_DEFAULT ); + + if( r_debugPolygonFilled.GetBool() ) + { + glDisable( GL_POLYGON_OFFSET_FILL ); + } + else + { + glDisable( GL_POLYGON_OFFSET_LINE ); + } + + GL_State( GLS_DEFAULT ); +} + +/* +================ +idRenderBackend::DBG_ShowCenterOfProjection +================ +*/ +void idRenderBackend::DBG_ShowCenterOfProjection() +{ + if( !r_showCenterOfProjection.GetBool() ) + { + return; + } + + const int w = viewDef->scissor.GetWidth(); + const int h = viewDef->scissor.GetHeight(); + glClearColor( 1, 0, 0, 1 ); + for( float f = 0.0f ; f <= 1.0f ; f += 0.125f ) + { + glScissor( w * f - 1 , 0, 3, h ); + glClear( GL_COLOR_BUFFER_BIT ); + glScissor( 0, h * f - 1 , w, 3 ); + glClear( GL_COLOR_BUFFER_BIT ); + } + glClearColor( 0, 1, 0, 1 ); + float f = 0.5f; + glScissor( w * f - 1 , 0, 3, h ); + glClear( GL_COLOR_BUFFER_BIT ); + glScissor( 0, h * f - 1 , w, 3 ); + glClear( GL_COLOR_BUFFER_BIT ); + + glScissor( 0, 0, w, h ); +} + +/* +================ +idRenderBackend::DBG_ShowLines + +Draw exact pixel lines to check pixel center sampling +================ +*/ +void idRenderBackend::DBG_ShowLines() +{ + if( !r_showLines.GetBool() ) + { + return; + } + + glEnable( GL_SCISSOR_TEST ); + if( viewDef->renderView.viewEyeBuffer == 0 ) + { + glClearColor( 1, 0, 0, 1 ); + } + else if( viewDef->renderView.viewEyeBuffer == 1 ) + { + glClearColor( 0, 1, 0, 1 ); + } + else + { + glClearColor( 0, 0, 1, 1 ); + } + + const int start = ( r_showLines.GetInteger() > 2 ); // 1,3 = horizontal, 2,4 = vertical + if( r_showLines.GetInteger() == 1 || r_showLines.GetInteger() == 3 ) + { + for( int i = start ; i < tr.GetHeight() ; i += 2 ) + { + glScissor( 0, i, tr.GetWidth(), 1 ); + glClear( GL_COLOR_BUFFER_BIT ); + } + } + else + { + for( int i = start ; i < tr.GetWidth() ; i += 2 ) + { + glScissor( i, 0, 1, tr.GetHeight() ); + glClear( GL_COLOR_BUFFER_BIT ); + } + } +} + + +/* +================ +idRenderBackend::DBG_TestGamma +================ +*/ +#define G_WIDTH 512 +#define G_HEIGHT 512 +#define BAR_HEIGHT 64 + +void idRenderBackend::DBG_TestGamma() +{ + byte image[G_HEIGHT][G_WIDTH][4]; + int i, j; + int c, comp; + int v, dither; + int mask, y; + + if( r_testGamma.GetInteger() <= 0 ) + { + return; + } + + v = r_testGamma.GetInteger(); + if( v <= 1 || v >= 196 ) + { + v = 128; + } + + memset( image, 0, sizeof( image ) ); + + for( mask = 0; mask < 8; mask++ ) + { + y = mask * BAR_HEIGHT; + for( c = 0; c < 4; c++ ) + { + v = c * 64 + 32; + // solid color + for( i = 0; i < BAR_HEIGHT / 2; i++ ) + { + for( j = 0; j < G_WIDTH / 4; j++ ) + { + for( comp = 0; comp < 3; comp++ ) + { + if( mask & ( 1 << comp ) ) + { + image[y + i][c * G_WIDTH / 4 + j][comp] = v; + } + } + } + // dithered color + for( j = 0; j < G_WIDTH / 4; j++ ) + { + if( ( i ^ j ) & 1 ) + { + dither = c * 64; + } + else + { + dither = c * 64 + 63; + } + for( comp = 0; comp < 3; comp++ ) + { + if( mask & ( 1 << comp ) ) + { + image[y + BAR_HEIGHT / 2 + i][c * G_WIDTH / 4 + j][comp] = dither; + } + } + } + } + } + } + + // draw geometrically increasing steps in the bottom row + y = 0 * BAR_HEIGHT; + float scale = 1; + for( c = 0; c < 4; c++ ) + { + v = ( int )( 64 * scale ); + if( v < 0 ) + { + v = 0; + } + else if( v > 255 ) + { + v = 255; + } + scale = scale * 1.5; + for( i = 0; i < BAR_HEIGHT; i++ ) + { + for( j = 0; j < G_WIDTH / 4; j++ ) + { + image[y + i][c * G_WIDTH / 4 + j][0] = v; + image[y + i][c * G_WIDTH / 4 + j][1] = v; + image[y + i][c * G_WIDTH / 4 + j][2] = v; + } + } + } + + glLoadIdentity(); + + glMatrixMode( GL_PROJECTION ); + GL_State( GLS_DEPTHFUNC_ALWAYS ); + GL_Color( 1, 1, 1 ); + glPushMatrix(); + glLoadIdentity(); + glDisable( GL_TEXTURE_2D ); + glOrtho( 0, 1, 0, 1, -1, 1 ); + glRasterPos2f( 0.01f, 0.01f ); + glDrawPixels( G_WIDTH, G_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, image ); + glPopMatrix(); + glEnable( GL_TEXTURE_2D ); + glMatrixMode( GL_MODELVIEW ); +} + + +/* +================== +idRenderBackend::DBG_TestGammaBias +================== +*/ +void idRenderBackend::DBG_TestGammaBias() +{ + byte image[G_HEIGHT][G_WIDTH][4]; + + if( r_testGammaBias.GetInteger() <= 0 ) + { + return; + } + + int y = 0; + for( int bias = -40; bias < 40; bias += 10, y += BAR_HEIGHT ) + { + float scale = 1; + for( int c = 0; c < 4; c++ ) + { + int v = ( int )( 64 * scale + bias ); + scale = scale * 1.5; + if( v < 0 ) + { + v = 0; + } + else if( v > 255 ) + { + v = 255; + } + for( int i = 0; i < BAR_HEIGHT; i++ ) + { + for( int j = 0; j < G_WIDTH / 4; j++ ) + { + image[y + i][c * G_WIDTH / 4 + j][0] = v; + image[y + i][c * G_WIDTH / 4 + j][1] = v; + image[y + i][c * G_WIDTH / 4 + j][2] = v; + } + } + } + } + + glLoadIdentity(); + glMatrixMode( GL_PROJECTION ); + GL_State( GLS_DEPTHFUNC_ALWAYS ); + GL_Color( 1, 1, 1 ); + glPushMatrix(); + glLoadIdentity(); + glDisable( GL_TEXTURE_2D ); + glOrtho( 0, 1, 0, 1, -1, 1 ); + glRasterPos2f( 0.01f, 0.01f ); + glDrawPixels( G_WIDTH, G_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, image ); + glPopMatrix(); + glEnable( GL_TEXTURE_2D ); + glMatrixMode( GL_MODELVIEW ); +} + +/* +================ +idRenderBackend::DBG_TestImage + +Display a single image over most of the screen +================ +*/ +void idRenderBackend::DBG_TestImage() +{ + idImage* image = NULL; + idImage* imageCr = NULL; + idImage* imageCb = NULL; + int max; + float w, h; + + image = tr.testImage; + if( !image ) + { + return; + } + + if( tr.testVideo ) + { + cinData_t cin; + + cin = tr.testVideo->ImageForTime( viewDef->renderView.time[1] - tr.testVideoStartTime ); + if( cin.imageY != NULL ) + { + image = cin.imageY; + imageCr = cin.imageCr; + imageCb = cin.imageCb; + } + else + { + tr.testImage = NULL; + return; + } + w = 0.25; + h = 0.25; + } + else + { + max = image->GetUploadWidth() > image->GetUploadHeight() ? image->GetUploadWidth() : image->GetUploadHeight(); + + w = 0.25 * image->GetUploadWidth() / max; + h = 0.25 * image->GetUploadHeight() / max; + + w *= ( float )renderSystem->GetHeight() / renderSystem->GetWidth(); + } + + // Set State + GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); + + // Set Parms + float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; + float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f }; + renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_S, texS ); + renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_T, texT ); + + float texGenEnabled[4] = { 0, 0, 0, 0 }; + renderProgManager.SetRenderParm( RENDERPARM_TEXGEN_0_ENABLED, texGenEnabled ); + + // not really necessary but just for clarity + const float screenWidth = 1.0f; + const float screenHeight = 1.0f; + const float halfScreenWidth = screenWidth * 0.5f; + const float halfScreenHeight = screenHeight * 0.5f; + + float scale[16] = { 0 }; + scale[0] = w; // scale + scale[5] = h; // scale + scale[12] = halfScreenWidth - ( halfScreenWidth * w ); // translate + scale[13] = halfScreenHeight - ( halfScreenHeight * h ); // translate + scale[10] = 1.0f; + scale[15] = 1.0f; + + float ortho[16] = { 0 }; + ortho[0] = 2.0f / screenWidth; + ortho[5] = -2.0f / screenHeight; + ortho[10] = -2.0f; + ortho[12] = -1.0f; + ortho[13] = 1.0f; + ortho[14] = -1.0f; + ortho[15] = 1.0f; + + float finalOrtho[16]; + R_MatrixMultiply( scale, ortho, finalOrtho ); + + float projMatrixTranspose[16]; + R_MatrixTranspose( finalOrtho, projMatrixTranspose ); + renderProgManager.SetRenderParms( RENDERPARM_MVPMATRIX_X, projMatrixTranspose, 4 ); + +// glMatrixMode( GL_PROJECTION ); +// glLoadMatrixf( finalOrtho ); +// glMatrixMode( GL_MODELVIEW ); +// glLoadIdentity(); + + // Set Color + GL_Color( 1, 1, 1, 1 ); + + // Bind the Texture + if( ( imageCr != NULL ) && ( imageCb != NULL ) ) + { + GL_SelectTexture( 0 ); + image->Bind(); + GL_SelectTexture( 1 ); + imageCr->Bind(); + GL_SelectTexture( 2 ); + imageCb->Bind(); + renderProgManager.BindShader_Bink(); + } + else + { + GL_SelectTexture( 0 ); + image->Bind(); + // Set Shader + renderProgManager.BindShader_Texture(); + } + + // Draw! + DrawElementsWithCounters( &testImageSurface ); +} + +// RB begin +void idRenderBackend::DBG_ShowShadowMaps() +{ + idImage* image = NULL; + int max; + float w, h; + + if( !r_showShadowMaps.GetBool() ) + return; + + image = globalImages->shadowImage[0]; + if( !image ) + { + return; + } + + // Set State + GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); + + // Set Parms + float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; + float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f }; + renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_S, texS ); + renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_T, texT ); + + float texGenEnabled[4] = { 0, 0, 0, 0 }; + renderProgManager.SetRenderParm( RENDERPARM_TEXGEN_0_ENABLED, texGenEnabled ); + + for( int i = 0; i < ( r_shadowMapSplits.GetInteger() + 1 ); i++ ) + { + max = image->GetUploadWidth() > image->GetUploadHeight() ? image->GetUploadWidth() : image->GetUploadHeight(); + + w = 0.25 * image->GetUploadWidth() / max; + h = 0.25 * image->GetUploadHeight() / max; + + w *= ( float )renderSystem->GetHeight() / renderSystem->GetWidth(); + + // not really necessary but just for clarity + const float screenWidth = 1.0f; + const float screenHeight = 1.0f; + const float halfScreenWidth = screenWidth * 0.5f; + const float halfScreenHeight = screenHeight * 0.5f; + + float scale[16] = { 0 }; + scale[0] = w; // scale + scale[5] = h; // scale + scale[12] = ( halfScreenWidth * w * 2.1f * i ); // translate + scale[13] = halfScreenHeight + ( halfScreenHeight * h ); // translate + scale[10] = 1.0f; + scale[15] = 1.0f; + + float ortho[16] = { 0 }; + ortho[0] = 2.0f / screenWidth; + ortho[5] = -2.0f / screenHeight; + ortho[10] = -2.0f; + ortho[12] = -1.0f; + ortho[13] = 1.0f; + ortho[14] = -1.0f; + ortho[15] = 1.0f; + + float finalOrtho[16]; + R_MatrixMultiply( scale, ortho, finalOrtho ); + + float projMatrixTranspose[16]; + R_MatrixTranspose( finalOrtho, projMatrixTranspose ); + renderProgManager.SetRenderParms( RENDERPARM_MVPMATRIX_X, projMatrixTranspose, 4 ); + + float screenCorrectionParm[4]; + screenCorrectionParm[0] = i; + screenCorrectionParm[1] = 0.0f; + screenCorrectionParm[2] = 0.0f; + screenCorrectionParm[3] = 1.0f; + renderProgManager.SetRenderParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor + + // glMatrixMode( GL_PROJECTION ); + // glLoadMatrixf( finalOrtho ); + // glMatrixMode( GL_MODELVIEW ); + // glLoadIdentity(); + + // Set Color + GL_Color( 1, 1, 1, 1 ); + + GL_SelectTexture( 0 ); + image->Bind(); + glTexParameteri( GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_NONE ); + + + renderProgManager.BindShader_DebugShadowMap(); + + DrawElementsWithCounters( &testImageSurface ); + } + + glTexParameteri( GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE ); +} +// RB end + +/* +================= +RB_DrawExpandedTriangles +================= +*/ +static void RB_DrawExpandedTriangles( const srfTriangles_t* tri, const float radius, const idVec3& vieworg ) +{ + int i, j, k; + idVec3 dir[6], normal, point; + + for( i = 0; i < tri->numIndexes; i += 3 ) + { + + idVec3 p[3] = { tri->verts[ tri->indexes[ i + 0 ] ].xyz, tri->verts[ tri->indexes[ i + 1 ] ].xyz, tri->verts[ tri->indexes[ i + 2 ] ].xyz }; + + dir[0] = p[0] - p[1]; + dir[1] = p[1] - p[2]; + dir[2] = p[2] - p[0]; + + normal = dir[0].Cross( dir[1] ); + + if( normal * p[0] < normal * vieworg ) + { + continue; + } + + dir[0] = normal.Cross( dir[0] ); + dir[1] = normal.Cross( dir[1] ); + dir[2] = normal.Cross( dir[2] ); + + dir[0].Normalize(); + dir[1].Normalize(); + dir[2].Normalize(); + + glBegin( GL_LINE_LOOP ); + + for( j = 0; j < 3; j++ ) + { + k = ( j + 1 ) % 3; + + dir[4] = ( dir[j] + dir[k] ) * 0.5f; + dir[4].Normalize(); + + dir[3] = ( dir[j] + dir[4] ) * 0.5f; + dir[3].Normalize(); + + dir[5] = ( dir[4] + dir[k] ) * 0.5f; + dir[5].Normalize(); + + point = p[k] + dir[j] * radius; + glVertex3f( point[0], point[1], point[2] ); + + point = p[k] + dir[3] * radius; + glVertex3f( point[0], point[1], point[2] ); + + point = p[k] + dir[4] * radius; + glVertex3f( point[0], point[1], point[2] ); + + point = p[k] + dir[5] * radius; + glVertex3f( point[0], point[1], point[2] ); + + point = p[k] + dir[k] * radius; + glVertex3f( point[0], point[1], point[2] ); + } + + glEnd(); + } +} + +/* +================ +idRenderBackend::DBG_ShowTrace + +Debug visualization + +FIXME: not thread safe! +================ +*/ +void idRenderBackend::DBG_ShowTrace( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + int i; + const srfTriangles_t* tri; + const drawSurf_t* surf; + idVec3 start, end; + idVec3 localStart, localEnd; + localTrace_t hit; + float radius; + + if( r_showTrace.GetInteger() == 0 ) + { + return; + } + + if( r_showTrace.GetInteger() == 2 ) + { + radius = 5.0f; + } + else + { + radius = 0.0f; + } + + // determine the points of the trace + start = viewDef->renderView.vieworg; + end = start + 4000 * viewDef->renderView.viewaxis[0]; + + // check and draw the surfaces + globalImages->whiteImage->Bind(); + + // find how many are ambient + for( i = 0; i < numDrawSurfs; i++ ) + { + surf = drawSurfs[i]; + tri = surf->frontEndGeo; + + if( tri == NULL || tri->verts == NULL ) + { + continue; + } + + // transform the points into local space + R_GlobalPointToLocal( surf->space->modelMatrix, start, localStart ); + R_GlobalPointToLocal( surf->space->modelMatrix, end, localEnd ); + + // check the bounding box + if( !tri->bounds.Expand( radius ).LineIntersection( localStart, localEnd ) ) + { + continue; + } + + glLoadMatrixf( surf->space->modelViewMatrix ); + + // highlight the surface + GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); + + GL_Color( 1, 0, 0, 0.25 ); + DrawElementsWithCounters( surf ); + + // draw the bounding box + GL_State( GLS_DEPTHFUNC_ALWAYS ); + + GL_Color( 1, 1, 1, 1 ); + RB_DrawBounds( tri->bounds ); + + if( radius != 0.0f ) + { + // draw the expanded triangles + GL_Color( 0.5f, 0.5f, 1.0f, 1.0f ); + RB_DrawExpandedTriangles( tri, radius, localStart ); + } + + // check the exact surfaces + hit = R_LocalTrace( localStart, localEnd, radius, tri ); + if( hit.fraction < 1.0 ) + { + GL_Color( 1, 1, 1, 1 ); + RB_DrawBounds( idBounds( hit.point ).Expand( 1 ) ); + } + } +} + +/* +================= +idRenderBackend::DBG_RenderDebugTools +================= +*/ +void idRenderBackend::DBG_RenderDebugTools( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + // don't do much if this was a 2D rendering + if( !viewDef->viewEntitys ) + { + DBG_TestImage(); + DBG_ShowLines(); + return; + } + + renderLog.OpenMainBlock( MRB_DRAW_DEBUG_TOOLS ); + RENDERLOG_PRINTF( "---------- RB_RenderDebugTools ----------\n" ); + + GL_State( GLS_DEFAULT ); + + GL_Scissor( viewDef->viewport.x1 + viewDef->scissor.x1, + viewDef->viewport.y1 + viewDef->scissor.y1, + viewDef->scissor.x2 + 1 - viewDef->scissor.x1, + viewDef->scissor.y2 + 1 - viewDef->scissor.y1 ); + + currentScissor = viewDef->scissor; + + DBG_ShowLightCount(); + DBG_ShowTexturePolarity( drawSurfs, numDrawSurfs ); + DBG_ShowTangentSpace( drawSurfs, numDrawSurfs ); + DBG_ShowVertexColor( drawSurfs, numDrawSurfs ); + DBG_ShowTris( drawSurfs, numDrawSurfs ); + DBG_ShowUnsmoothedTangents( drawSurfs, numDrawSurfs ); + DBG_ShowSurfaceInfo( drawSurfs, numDrawSurfs ); + DBG_ShowEdges( drawSurfs, numDrawSurfs ); + DBG_ShowNormals( drawSurfs, numDrawSurfs ); + DBG_ShowViewEntitys( viewDef->viewEntitys ); + DBG_ShowLights(); + // RB begin + DBG_ShowShadowMapLODs(); + DBG_ShowShadowMaps(); + // RB end + + DBG_ShowTextureVectors( drawSurfs, numDrawSurfs ); + DBG_ShowDominantTris( drawSurfs, numDrawSurfs ); + if( r_testGamma.GetInteger() > 0 ) // test here so stack check isn't so damn slow on debug builds + { + DBG_TestGamma(); + } + if( r_testGammaBias.GetInteger() > 0 ) + { + DBG_TestGammaBias(); + } + DBG_TestImage(); + DBG_ShowPortals(); + DBG_ShowSilhouette(); + DBG_ShowDepthBuffer(); + DBG_ShowIntensity(); + DBG_ShowCenterOfProjection(); + DBG_ShowLines(); + DBG_ShowDebugLines(); + DBG_ShowDebugText(); + DBG_ShowDebugPolygons(); + DBG_ShowTrace( drawSurfs, numDrawSurfs ); + + renderLog.CloseMainBlock(); +} + +/* +================= +RB_ShutdownDebugTools +================= +*/ +void RB_ShutdownDebugTools() +{ + for( int i = 0; i < MAX_DEBUG_POLYGONS; i++ ) + { + rb_debugPolygons[i].winding.Clear(); + } +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderBackend.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderBackend.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderBackend.cpp 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderBackend.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,5954 @@ +/* +=========================================================================== + +Doom 3 BFG Edition GPL Source Code +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2013-2015 Robert Beckebans +Copyright (C) 2014 Carl Kenner + +This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). + +Doom 3 BFG Edition Source Code 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. + +Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . + +In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#pragma hdrstop +#include "precompiled.h" + +#include "RenderCommon.h" +#include "Framebuffer.h" + +idCVar r_drawEyeColor( "r_drawEyeColor", "0", CVAR_RENDERER | CVAR_BOOL, "Draw a colored box, red = left eye, blue = right eye, grey = non-stereo" ); +idCVar r_motionBlur( "r_motionBlur", "0", CVAR_RENDERER | CVAR_INTEGER | CVAR_ARCHIVE, "1 - 5, log2 of the number of motion blur samples" ); +idCVar r_forceZPassStencilShadows( "r_forceZPassStencilShadows", "0", CVAR_RENDERER | CVAR_BOOL, "force Z-pass rendering for performance testing" ); +idCVar r_useStencilShadowPreload( "r_useStencilShadowPreload", "1", CVAR_RENDERER | CVAR_BOOL, "use stencil shadow preload algorithm instead of Z-fail" ); +idCVar r_skipShaderPasses( "r_skipShaderPasses", "0", CVAR_RENDERER | CVAR_BOOL, "" ); +idCVar r_skipInteractionFastPath( "r_skipInteractionFastPath", "1", CVAR_RENDERER | CVAR_BOOL, "" ); +idCVar r_useLightStencilSelect( "r_useLightStencilSelect", "0", CVAR_RENDERER | CVAR_BOOL, "use stencil select pass" ); + +extern idCVar stereoRender_swapEyes; + + +/* +================ +SetVertexParm +================ +*/ +static ID_INLINE void SetVertexParm( renderParm_t rp, const float* value ) +{ + renderProgManager.SetUniformValue( rp, value ); +} + +/* +================ +SetVertexParms +================ +*/ +static ID_INLINE void SetVertexParms( renderParm_t rp, const float* value, int num ) +{ + for( int i = 0; i < num; i++ ) + { + renderProgManager.SetUniformValue( ( renderParm_t )( rp + i ), value + ( i * 4 ) ); + } +} + +/* +================ +SetFragmentParm +================ +*/ +static ID_INLINE void SetFragmentParm( renderParm_t rp, const float* value ) +{ + renderProgManager.SetUniformValue( rp, value ); +} + +/* +==================== +PrintState +==================== +*/ +#if 0 +void PrintState( uint64 stateBits, uint64* stencilBits ) +{ + if( renderLog.Active() == 0 ) + { + return; + } + + renderLog.OpenBlock( "GL_State" ); + + // culling + renderLog.Printf( "Culling: " ); + switch( stateBits & GLS_CULL_BITS ) + { + case GLS_CULL_FRONTSIDED: + renderLog.Printf_NoIndent( "FRONTSIDED -> BACK" ); + break; + case GLS_CULL_BACKSIDED: + renderLog.Printf_NoIndent( "BACKSIDED -> FRONT" ); + break; + case GLS_CULL_TWOSIDED: + renderLog.Printf_NoIndent( "TWOSIDED" ); + break; + default: + renderLog.Printf_NoIndent( "NA" ); + break; + } + renderLog.Printf_NoIndent( "\n" ); + + // polygon mode + renderLog.Printf( "PolygonMode: %s\n", ( stateBits & GLS_POLYMODE_LINE ) ? "LINE" : "FILL" ); + + // color mask + renderLog.Printf( "ColorMask: " ); + renderLog.Printf_NoIndent( ( stateBits & GLS_REDMASK ) ? "_" : "R" ); + renderLog.Printf_NoIndent( ( stateBits & GLS_GREENMASK ) ? "_" : "G" ); + renderLog.Printf_NoIndent( ( stateBits & GLS_BLUEMASK ) ? "_" : "B" ); + renderLog.Printf_NoIndent( ( stateBits & GLS_ALPHAMASK ) ? "_" : "A" ); + renderLog.Printf_NoIndent( "\n" ); + + // blend + renderLog.Printf( "Blend: src=" ); + switch( stateBits & GLS_SRCBLEND_BITS ) + { + case GLS_SRCBLEND_ZERO: + renderLog.Printf_NoIndent( "ZERO" ); + break; + case GLS_SRCBLEND_ONE: + renderLog.Printf_NoIndent( "ONE" ); + break; + case GLS_SRCBLEND_DST_COLOR: + renderLog.Printf_NoIndent( "DST_COLOR" ); + break; + case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: + renderLog.Printf_NoIndent( "ONE_MINUS_DST_COLOR" ); + break; + case GLS_SRCBLEND_SRC_ALPHA: + renderLog.Printf_NoIndent( "SRC_ALPHA" ); + break; + case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: + renderLog.Printf_NoIndent( "ONE_MINUS_SRC_ALPHA" ); + break; + case GLS_SRCBLEND_DST_ALPHA: + renderLog.Printf_NoIndent( "DST_ALPHA" ); + break; + case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: + renderLog.Printf_NoIndent( "ONE_MINUS_DST_ALPHA" ); + break; + default: + renderLog.Printf_NoIndent( "NA" ); + break; + } + renderLog.Printf_NoIndent( ", dst=" ); + switch( stateBits & GLS_DSTBLEND_BITS ) + { + case GLS_DSTBLEND_ZERO: + renderLog.Printf_NoIndent( "ZERO" ); + break; + case GLS_DSTBLEND_ONE: + renderLog.Printf_NoIndent( "ONE" ); + break; + case GLS_DSTBLEND_SRC_COLOR: + renderLog.Printf_NoIndent( "SRC_COLOR" ); + break; + case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: + renderLog.Printf_NoIndent( "ONE_MINUS_SRC_COLOR" ); + break; + case GLS_DSTBLEND_SRC_ALPHA: + renderLog.Printf_NoIndent( "SRC_ALPHA" ); + break; + case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: + renderLog.Printf_NoIndent( "ONE_MINUS_SRC_ALPHA" ); + break; + case GLS_DSTBLEND_DST_ALPHA: + renderLog.Printf_NoIndent( "DST_ALPHA" ); + break; + case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: + renderLog.Printf_NoIndent( "ONE_MINUS_DST_ALPHA" ); + break; + default: + renderLog.Printf_NoIndent( "NA" ); + } + renderLog.Printf_NoIndent( "\n" ); + + // depth func + renderLog.Printf( "DepthFunc: " ); + switch( stateBits & GLS_DEPTHFUNC_BITS ) + { + case GLS_DEPTHFUNC_EQUAL: + renderLog.Printf_NoIndent( "EQUAL" ); + break; + case GLS_DEPTHFUNC_ALWAYS: + renderLog.Printf_NoIndent( "ALWAYS" ); + break; + case GLS_DEPTHFUNC_LESS: + renderLog.Printf_NoIndent( "LEQUAL" ); + break; + case GLS_DEPTHFUNC_GREATER: + renderLog.Printf_NoIndent( "GEQUAL" ); + break; + default: + renderLog.Printf_NoIndent( "NA" ); + break; + } + renderLog.Printf_NoIndent( "\n" ); + + // depth mask + renderLog.Printf( "DepthWrite: %s\n", ( stateBits & GLS_DEPTHMASK ) ? "FALSE" : "TRUE" ); + + renderLog.Printf( "DepthBounds: %s\n", ( stateBits & GLS_DEPTH_TEST_MASK ) ? "TRUE" : "FALSE" ); + + // depth bias + renderLog.Printf( "DepthBias: %s\n", ( stateBits & GLS_POLYGON_OFFSET ) ? "TRUE" : "FALSE" ); + + // stencil + auto printStencil = [&]( stencilFace_t face, uint64 bits, uint64 mask, uint64 ref ) + { + renderLog.Printf( "Stencil: %s, ", ( bits & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS ) ) ? "ON" : "OFF" ); + renderLog.Printf_NoIndent( "Face=" ); + switch( face ) + { + case STENCIL_FACE_FRONT: + renderLog.Printf_NoIndent( "FRONT" ); + break; + case STENCIL_FACE_BACK: + renderLog.Printf_NoIndent( "BACK" ); + break; + default: + renderLog.Printf_NoIndent( "BOTH" ); + break; + } + renderLog.Printf_NoIndent( ", Func=" ); + switch( bits & GLS_STENCIL_FUNC_BITS ) + { + case GLS_STENCIL_FUNC_NEVER: + renderLog.Printf_NoIndent( "NEVER" ); + break; + case GLS_STENCIL_FUNC_LESS: + renderLog.Printf_NoIndent( "LESS" ); + break; + case GLS_STENCIL_FUNC_EQUAL: + renderLog.Printf_NoIndent( "EQUAL" ); + break; + case GLS_STENCIL_FUNC_LEQUAL: + renderLog.Printf_NoIndent( "LEQUAL" ); + break; + case GLS_STENCIL_FUNC_GREATER: + renderLog.Printf_NoIndent( "GREATER" ); + break; + case GLS_STENCIL_FUNC_NOTEQUAL: + renderLog.Printf_NoIndent( "NOTEQUAL" ); + break; + case GLS_STENCIL_FUNC_GEQUAL: + renderLog.Printf_NoIndent( "GEQUAL" ); + break; + case GLS_STENCIL_FUNC_ALWAYS: + renderLog.Printf_NoIndent( "ALWAYS" ); + break; + default: + renderLog.Printf_NoIndent( "NA" ); + break; + } + renderLog.Printf_NoIndent( ", OpFail=" ); + switch( bits & GLS_STENCIL_OP_FAIL_BITS ) + { + case GLS_STENCIL_OP_FAIL_KEEP: + renderLog.Printf_NoIndent( "KEEP" ); + break; + case GLS_STENCIL_OP_FAIL_ZERO: + renderLog.Printf_NoIndent( "ZERO" ); + break; + case GLS_STENCIL_OP_FAIL_REPLACE: + renderLog.Printf_NoIndent( "REPLACE" ); + break; + case GLS_STENCIL_OP_FAIL_INCR: + renderLog.Printf_NoIndent( "INCR" ); + break; + case GLS_STENCIL_OP_FAIL_DECR: + renderLog.Printf_NoIndent( "DECR" ); + break; + case GLS_STENCIL_OP_FAIL_INVERT: + renderLog.Printf_NoIndent( "INVERT" ); + break; + case GLS_STENCIL_OP_FAIL_INCR_WRAP: + renderLog.Printf_NoIndent( "INCR_WRAP" ); + break; + case GLS_STENCIL_OP_FAIL_DECR_WRAP: + renderLog.Printf_NoIndent( "DECR_WRAP" ); + break; + default: + renderLog.Printf_NoIndent( "NA" ); + break; + } + renderLog.Printf_NoIndent( ", ZFail=" ); + switch( bits & GLS_STENCIL_OP_ZFAIL_BITS ) + { + case GLS_STENCIL_OP_ZFAIL_KEEP: + renderLog.Printf_NoIndent( "KEEP" ); + break; + case GLS_STENCIL_OP_ZFAIL_ZERO: + renderLog.Printf_NoIndent( "ZERO" ); + break; + case GLS_STENCIL_OP_ZFAIL_REPLACE: + renderLog.Printf_NoIndent( "REPLACE" ); + break; + case GLS_STENCIL_OP_ZFAIL_INCR: + renderLog.Printf_NoIndent( "INCR" ); + break; + case GLS_STENCIL_OP_ZFAIL_DECR: + renderLog.Printf_NoIndent( "DECR" ); + break; + case GLS_STENCIL_OP_ZFAIL_INVERT: + renderLog.Printf_NoIndent( "INVERT" ); + break; + case GLS_STENCIL_OP_ZFAIL_INCR_WRAP: + renderLog.Printf_NoIndent( "INCR_WRAP" ); + break; + case GLS_STENCIL_OP_ZFAIL_DECR_WRAP: + renderLog.Printf_NoIndent( "DECR_WRAP" ); + break; + default: + renderLog.Printf_NoIndent( "NA" ); + break; + } + renderLog.Printf_NoIndent( ", OpPass=" ); + switch( bits & GLS_STENCIL_OP_PASS_BITS ) + { + case GLS_STENCIL_OP_PASS_KEEP: + renderLog.Printf_NoIndent( "KEEP" ); + break; + case GLS_STENCIL_OP_PASS_ZERO: + renderLog.Printf_NoIndent( "ZERO" ); + break; + case GLS_STENCIL_OP_PASS_REPLACE: + renderLog.Printf_NoIndent( "REPLACE" ); + break; + case GLS_STENCIL_OP_PASS_INCR: + renderLog.Printf_NoIndent( "INCR" ); + break; + case GLS_STENCIL_OP_PASS_DECR: + renderLog.Printf_NoIndent( "DECR" ); + break; + case GLS_STENCIL_OP_PASS_INVERT: + renderLog.Printf_NoIndent( "INVERT" ); + break; + case GLS_STENCIL_OP_PASS_INCR_WRAP: + renderLog.Printf_NoIndent( "INCR_WRAP" ); + break; + case GLS_STENCIL_OP_PASS_DECR_WRAP: + renderLog.Printf_NoIndent( "DECR_WRAP" ); + break; + default: + renderLog.Printf_NoIndent( "NA" ); + break; + } + renderLog.Printf_NoIndent( ", mask=%llu, ref=%llu\n", mask, ref ); + }; + + uint32 mask = uint32( ( stateBits & GLS_STENCIL_FUNC_MASK_BITS ) >> GLS_STENCIL_FUNC_MASK_SHIFT ); + uint32 ref = uint32( ( stateBits & GLS_STENCIL_FUNC_REF_BITS ) >> GLS_STENCIL_FUNC_REF_SHIFT ); + if( stateBits & GLS_SEPARATE_STENCIL ) + { + printStencil( STENCIL_FACE_FRONT, stencilBits[ 0 ], mask, ref ); + printStencil( STENCIL_FACE_BACK, stencilBits[ 1 ], mask, ref ); + } + else + { + printStencil( STENCIL_FACE_NUM, stateBits, mask, ref ); + } + + renderLog.CloseBlock(); +} +#endif + +/* +================ +RB_SetMVP +================ +*/ +void RB_SetMVP( const idRenderMatrix& mvp ) +{ + SetVertexParms( RENDERPARM_MVPMATRIX_X, mvp[0], 4 ); +} + +/* +================ +RB_SetMVPWithStereoOffset +================ +*/ +static void RB_SetMVPWithStereoOffset( const idRenderMatrix& mvp, const float stereoOffset ) +{ + idRenderMatrix offset = mvp; + offset[0][3] += stereoOffset; + + SetVertexParms( RENDERPARM_MVPMATRIX_X, offset[0], 4 ); +} + +static const float zero[4] = { 0, 0, 0, 0 }; +static const float one[4] = { 1, 1, 1, 1 }; +static const float negOne[4] = { -1, -1, -1, -1 }; + +/* +================ +RB_SetVertexColorParms +================ +*/ +void RB_SetVertexColorParms( stageVertexColor_t svc ) +{ + switch( svc ) + { + case SVC_IGNORE: + SetVertexParm( RENDERPARM_VERTEXCOLOR_MODULATE, zero ); + SetVertexParm( RENDERPARM_VERTEXCOLOR_ADD, one ); + break; + case SVC_MODULATE: + SetVertexParm( RENDERPARM_VERTEXCOLOR_MODULATE, one ); + SetVertexParm( RENDERPARM_VERTEXCOLOR_ADD, zero ); + break; + case SVC_INVERSE_MODULATE: + SetVertexParm( RENDERPARM_VERTEXCOLOR_MODULATE, negOne ); + SetVertexParm( RENDERPARM_VERTEXCOLOR_ADD, one ); + break; + } +} + + + +/* +====================== +RB_GetShaderTextureMatrix +====================== +*/ +void RB_GetShaderTextureMatrix( const float* shaderRegisters, const textureStage_t* texture, float matrix[16] ) +{ + matrix[0 * 4 + 0] = shaderRegisters[ texture->matrix[0][0] ]; + matrix[1 * 4 + 0] = shaderRegisters[ texture->matrix[0][1] ]; + matrix[2 * 4 + 0] = 0.0f; + matrix[3 * 4 + 0] = shaderRegisters[ texture->matrix[0][2] ]; + + matrix[0 * 4 + 1] = shaderRegisters[ texture->matrix[1][0] ]; + matrix[1 * 4 + 1] = shaderRegisters[ texture->matrix[1][1] ]; + matrix[2 * 4 + 1] = 0.0f; + matrix[3 * 4 + 1] = shaderRegisters[ texture->matrix[1][2] ]; + + // we attempt to keep scrolls from generating incredibly large texture values, but + // center rotations and center scales can still generate offsets that need to be > 1 + if( matrix[3 * 4 + 0] < -40.0f || matrix[12] > 40.0f ) + { + matrix[3 * 4 + 0] -= ( int )matrix[3 * 4 + 0]; + } + if( matrix[13] < -40.0f || matrix[13] > 40.0f ) + { + matrix[13] -= ( int )matrix[13]; + } + + matrix[0 * 4 + 2] = 0.0f; + matrix[1 * 4 + 2] = 0.0f; + matrix[2 * 4 + 2] = 1.0f; + matrix[3 * 4 + 2] = 0.0f; + + matrix[0 * 4 + 3] = 0.0f; + matrix[1 * 4 + 3] = 0.0f; + matrix[2 * 4 + 3] = 0.0f; + matrix[3 * 4 + 3] = 1.0f; +} + +/* +====================== +RB_LoadShaderTextureMatrix +====================== +*/ +void RB_LoadShaderTextureMatrix( const float* shaderRegisters, const textureStage_t* texture ) +{ + float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; + float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f }; + + if( texture->hasMatrix ) + { + float matrix[16]; + RB_GetShaderTextureMatrix( shaderRegisters, texture, matrix ); + texS[0] = matrix[0 * 4 + 0]; + texS[1] = matrix[1 * 4 + 0]; + texS[2] = matrix[2 * 4 + 0]; + texS[3] = matrix[3 * 4 + 0]; + + texT[0] = matrix[0 * 4 + 1]; + texT[1] = matrix[1 * 4 + 1]; + texT[2] = matrix[2 * 4 + 1]; + texT[3] = matrix[3 * 4 + 1]; + + RENDERLOG_PRINTF( "Setting Texture Matrix\n" ); + renderLog.Indent(); + RENDERLOG_PRINTF( "Texture Matrix S : %4.3f, %4.3f, %4.3f, %4.3f\n", texS[0], texS[1], texS[2], texS[3] ); + RENDERLOG_PRINTF( "Texture Matrix T : %4.3f, %4.3f, %4.3f, %4.3f\n", texT[0], texT[1], texT[2], texT[3] ); + renderLog.Outdent(); + } + + SetVertexParm( RENDERPARM_TEXTUREMATRIX_S, texS ); + SetVertexParm( RENDERPARM_TEXTUREMATRIX_T, texT ); +} + +/* +===================== +RB_BakeTextureMatrixIntoTexgen +===================== +*/ +void RB_BakeTextureMatrixIntoTexgen( idPlane lightProject[3], const float* textureMatrix ) +{ + float genMatrix[16]; + float final[16]; + + genMatrix[0 * 4 + 0] = lightProject[0][0]; + genMatrix[1 * 4 + 0] = lightProject[0][1]; + genMatrix[2 * 4 + 0] = lightProject[0][2]; + genMatrix[3 * 4 + 0] = lightProject[0][3]; + + genMatrix[0 * 4 + 1] = lightProject[1][0]; + genMatrix[1 * 4 + 1] = lightProject[1][1]; + genMatrix[2 * 4 + 1] = lightProject[1][2]; + genMatrix[3 * 4 + 1] = lightProject[1][3]; + + genMatrix[0 * 4 + 2] = 0.0f; + genMatrix[1 * 4 + 2] = 0.0f; + genMatrix[2 * 4 + 2] = 0.0f; + genMatrix[3 * 4 + 2] = 0.0f; + + genMatrix[0 * 4 + 3] = lightProject[2][0]; + genMatrix[1 * 4 + 3] = lightProject[2][1]; + genMatrix[2 * 4 + 3] = lightProject[2][2]; + genMatrix[3 * 4 + 3] = lightProject[2][3]; + + R_MatrixMultiply( genMatrix, textureMatrix, final ); + + lightProject[0][0] = final[0 * 4 + 0]; + lightProject[0][1] = final[1 * 4 + 0]; + lightProject[0][2] = final[2 * 4 + 0]; + lightProject[0][3] = final[3 * 4 + 0]; + + lightProject[1][0] = final[0 * 4 + 1]; + lightProject[1][1] = final[1 * 4 + 1]; + lightProject[1][2] = final[2 * 4 + 1]; + lightProject[1][3] = final[3 * 4 + 1]; +} + +/* +====================== +idRenderBackend::BindVariableStageImage + +Handles generating a cinematic frame if needed +====================== +*/ +void idRenderBackend::BindVariableStageImage( const textureStage_t* texture, const float* shaderRegisters ) +{ + if( texture->cinematic ) + { + cinData_t cin; + + if( r_skipDynamicTextures.GetBool() ) + { + globalImages->defaultImage->Bind(); + return; + } + + // offset time by shaderParm[7] (FIXME: make the time offset a parameter of the shader?) + // We make no attempt to optimize for multiple identical cinematics being in view, or + // for cinematics going at a lower framerate than the renderer. + cin = texture->cinematic->ImageForTime( viewDef->renderView.time[0] + idMath::Ftoi( 1000.0f * viewDef->renderView.shaderParms[11] ) ); + if( cin.imageY != NULL ) + { + GL_SelectTexture( 0 ); + cin.imageY->Bind(); + GL_SelectTexture( 1 ); + cin.imageCr->Bind(); + GL_SelectTexture( 2 ); + cin.imageCb->Bind(); + // DG: imageY is only used for bink videos (with libbinkdec), so the bink shader must be used + renderProgManager.BindShader_Bink(); + } + else if( cin.image != NULL ) + { + // Carl: A single RGB image works better with the FFMPEG BINK codec. + GL_SelectTexture( 0 ); + cin.image->Bind(); + + /* + if( backEnd.viewDef->is2Dgui ) + { + renderProgManager.BindShader_TextureVertexColor_sRGB(); + } + else + { + renderProgManager.BindShader_TextureVertexColor(); + } + */ + } + else + { + globalImages->blackImage->Bind(); + // because the shaders may have already been set - we need to make sure we are not using a bink shader which would + // display incorrectly. We may want to get rid of RB_BindVariableStageImage and inline the code so that the + // SWF GUI case is handled better, too + renderProgManager.BindShader_TextureVertexColor(); + } + } + else + { + // FIXME: see why image is invalid + if( texture->image != NULL ) + { + texture->image->Bind(); + } + } +} + +/* +================ +idRenderBackend::PrepareStageTexturing +================ +*/ +void idRenderBackend::PrepareStageTexturing( const shaderStage_t* pStage, const drawSurf_t* surf ) +{ + float useTexGenParm[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + // set the texture matrix if needed + RB_LoadShaderTextureMatrix( surf->shaderRegisters, &pStage->texture ); + + // texgens + if( pStage->texture.texgen == TG_REFLECT_CUBE ) + { + + // see if there is also a bump map specified + const shaderStage_t* bumpStage = surf->material->GetBumpStage(); + if( bumpStage != NULL ) + { + // per-pixel reflection mapping with bump mapping + GL_SelectTexture( 1 ); + bumpStage->texture.image->Bind(); + GL_SelectTexture( 0 ); + + RENDERLOG_PRINTF( "TexGen: TG_REFLECT_CUBE: Bumpy Environment\n" ); + if( surf->jointCache ) + { + renderProgManager.BindShader_BumpyEnvironmentSkinned(); + } + else + { + renderProgManager.BindShader_BumpyEnvironment(); + } + } + else + { + RENDERLOG_PRINTF( "TexGen: TG_REFLECT_CUBE: Environment\n" ); + if( surf->jointCache ) + { + renderProgManager.BindShader_EnvironmentSkinned(); + } + else + { + renderProgManager.BindShader_Environment(); + } + } + + } + else if( pStage->texture.texgen == TG_SKYBOX_CUBE ) + { + + renderProgManager.BindShader_SkyBox(); + + } + else if( pStage->texture.texgen == TG_WOBBLESKY_CUBE ) + { + + const int* parms = surf->material->GetTexGenRegisters(); + + float wobbleDegrees = surf->shaderRegisters[ parms[0] ] * ( idMath::PI / 180.0f ); + float wobbleSpeed = surf->shaderRegisters[ parms[1] ] * ( 2.0f * idMath::PI / 60.0f ); + float rotateSpeed = surf->shaderRegisters[ parms[2] ] * ( 2.0f * idMath::PI / 60.0f ); + + idVec3 axis[3]; + { + // very ad-hoc "wobble" transform + float s, c; + idMath::SinCos( wobbleSpeed * viewDef->renderView.time[0] * 0.001f, s, c ); + + float ws, wc; + idMath::SinCos( wobbleDegrees, ws, wc ); + + axis[2][0] = ws * c; + axis[2][1] = ws * s; + axis[2][2] = wc; + + axis[1][0] = -s * s * ws; + axis[1][2] = -s * ws * ws; + axis[1][1] = idMath::Sqrt( idMath::Fabs( 1.0f - ( axis[1][0] * axis[1][0] + axis[1][2] * axis[1][2] ) ) ); + + // make the second vector exactly perpendicular to the first + axis[1] -= ( axis[2] * axis[1] ) * axis[2]; + axis[1].Normalize(); + + // construct the third with a cross + axis[0].Cross( axis[1], axis[2] ); + } + + // add the rotate + float rs, rc; + idMath::SinCos( rotateSpeed * viewDef->renderView.time[0] * 0.001f, rs, rc ); + + float transform[12]; + transform[0 * 4 + 0] = axis[0][0] * rc + axis[1][0] * rs; + transform[0 * 4 + 1] = axis[0][1] * rc + axis[1][1] * rs; + transform[0 * 4 + 2] = axis[0][2] * rc + axis[1][2] * rs; + transform[0 * 4 + 3] = 0.0f; + + transform[1 * 4 + 0] = axis[1][0] * rc - axis[0][0] * rs; + transform[1 * 4 + 1] = axis[1][1] * rc - axis[0][1] * rs; + transform[1 * 4 + 2] = axis[1][2] * rc - axis[0][2] * rs; + transform[1 * 4 + 3] = 0.0f; + + transform[2 * 4 + 0] = axis[2][0]; + transform[2 * 4 + 1] = axis[2][1]; + transform[2 * 4 + 2] = axis[2][2]; + transform[2 * 4 + 3] = 0.0f; + + SetVertexParms( RENDERPARM_WOBBLESKY_X, transform, 3 ); + renderProgManager.BindShader_WobbleSky(); + + } + else if( ( pStage->texture.texgen == TG_SCREEN ) || ( pStage->texture.texgen == TG_SCREEN2 ) ) + { + + useTexGenParm[0] = 1.0f; + useTexGenParm[1] = 1.0f; + useTexGenParm[2] = 1.0f; + useTexGenParm[3] = 1.0f; + + float mat[16]; + R_MatrixMultiply( surf->space->modelViewMatrix, viewDef->projectionMatrix, mat ); + + RENDERLOG_PRINTF( "TexGen : %s\n", ( pStage->texture.texgen == TG_SCREEN ) ? "TG_SCREEN" : "TG_SCREEN2" ); + renderLog.Indent(); + + float plane[4]; + plane[0] = mat[0 * 4 + 0]; + plane[1] = mat[1 * 4 + 0]; + plane[2] = mat[2 * 4 + 0]; + plane[3] = mat[3 * 4 + 0]; + SetVertexParm( RENDERPARM_TEXGEN_0_S, plane ); + RENDERLOG_PRINTF( "TEXGEN_S = %4.3f, %4.3f, %4.3f, %4.3f\n", plane[0], plane[1], plane[2], plane[3] ); + + plane[0] = mat[0 * 4 + 1]; + plane[1] = mat[1 * 4 + 1]; + plane[2] = mat[2 * 4 + 1]; + plane[3] = mat[3 * 4 + 1]; + SetVertexParm( RENDERPARM_TEXGEN_0_T, plane ); + RENDERLOG_PRINTF( "TEXGEN_T = %4.3f, %4.3f, %4.3f, %4.3f\n", plane[0], plane[1], plane[2], plane[3] ); + + plane[0] = mat[0 * 4 + 3]; + plane[1] = mat[1 * 4 + 3]; + plane[2] = mat[2 * 4 + 3]; + plane[3] = mat[3 * 4 + 3]; + SetVertexParm( RENDERPARM_TEXGEN_0_Q, plane ); + RENDERLOG_PRINTF( "TEXGEN_Q = %4.3f, %4.3f, %4.3f, %4.3f\n", plane[0], plane[1], plane[2], plane[3] ); + + renderLog.Outdent(); + + } + else if( pStage->texture.texgen == TG_DIFFUSE_CUBE ) + { + + // As far as I can tell, this is never used + idLib::Warning( "Using Diffuse Cube! Please contact Brian!" ); + + } + else if( pStage->texture.texgen == TG_GLASSWARP ) + { + + // As far as I can tell, this is never used + idLib::Warning( "Using GlassWarp! Please contact Brian!" ); + } + + SetVertexParm( RENDERPARM_TEXGEN_0_ENABLED, useTexGenParm ); +} + +/* +================ +idRenderBackend::FinishStageTexturing +================ +*/ +void idRenderBackend::FinishStageTexturing( const shaderStage_t* pStage, const drawSurf_t* surf ) +{ + if( pStage->texture.cinematic ) + { + // unbind the extra bink textures + GL_SelectTexture( 0 ); + } + + if( pStage->texture.texgen == TG_REFLECT_CUBE ) + { + // see if there is also a bump map specified + const shaderStage_t* bumpStage = surf->material->GetBumpStage(); + if( bumpStage != NULL ) + { + // per-pixel reflection mapping with bump mapping + GL_SelectTexture( 0 ); + } + else + { + // per-pixel reflection mapping without bump mapping + } + renderProgManager.Unbind(); + } +} + +// RB: moved this up because we need to call this several times for shadow mapping +void idRenderBackend::ResetViewportAndScissorToDefaultCamera( const viewDef_t* _viewDef ) +{ + // set the window clipping + GL_Viewport( _viewDef->viewport.x1, + _viewDef->viewport.y1, + _viewDef->viewport.x2 + 1 - _viewDef->viewport.x1, + _viewDef->viewport.y2 + 1 - _viewDef->viewport.y1 ); + + // the scissor may be smaller than the viewport for subviews + GL_Scissor( viewDef->viewport.x1 + _viewDef->scissor.x1, + viewDef->viewport.y1 + _viewDef->scissor.y1, + _viewDef->scissor.x2 + 1 - _viewDef->scissor.x1, + _viewDef->scissor.y2 + 1 - _viewDef->scissor.y1 ); + + currentScissor = viewDef->scissor; +} +// RB end + +/* +========================================================================================= + +DEPTH BUFFER RENDERING + +========================================================================================= +*/ + +/* +================== +idRenderBackend::FillDepthBufferGeneric +================== +*/ +void idRenderBackend::FillDepthBufferGeneric( const drawSurf_t* const* drawSurfs, int numDrawSurfs ) +{ + for( int i = 0; i < numDrawSurfs; i++ ) + { + const drawSurf_t* drawSurf = drawSurfs[i]; + const idMaterial* shader = drawSurf->material; + + // translucent surfaces don't put anything in the depth buffer and don't + // test against it, which makes them fail the mirror clip plane operation + if( shader->Coverage() == MC_TRANSLUCENT ) + { + continue; + } + + // get the expressions for conditionals / color / texcoords + const float* regs = drawSurf->shaderRegisters; + + // if all stages of a material have been conditioned off, don't do anything + int stage = 0; + for( ; stage < shader->GetNumStages(); stage++ ) + { + const shaderStage_t* pStage = shader->GetStage( stage ); + // check the stage enable condition + if( regs[ pStage->conditionRegister ] != 0 ) + { + break; + } + } + if( stage == shader->GetNumStages() ) + { + continue; + } + + // change the matrix if needed + if( drawSurf->space != currentSpace ) + { + RB_SetMVP( drawSurf->space->mvp ); + + currentSpace = drawSurf->space; + } + + uint64 surfGLState = 0; + + // set polygon offset if necessary + if( shader->TestMaterialFlag( MF_POLYGONOFFSET ) ) + { + surfGLState |= GLS_POLYGON_OFFSET; + GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); + } + + // subviews will just down-modulate the color buffer + idVec4 color; + if( shader->GetSort() == SS_SUBVIEW ) + { + surfGLState |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHFUNC_LESS; + color[0] = 1.0f; + color[1] = 1.0f; + color[2] = 1.0f; + color[3] = 1.0f; + } + else + { + // others just draw black + color[0] = 0.0f; + color[1] = 0.0f; + color[2] = 0.0f; + color[3] = 1.0f; + } + + renderLog.OpenBlock( shader->GetName() ); + + bool drawSolid = false; + if( shader->Coverage() == MC_OPAQUE ) + { + drawSolid = true; + } + else if( shader->Coverage() == MC_PERFORATED ) + { + // we may have multiple alpha tested stages + // if the only alpha tested stages are condition register omitted, + // draw a normal opaque surface + bool didDraw = false; + + // perforated surfaces may have multiple alpha tested stages + for( stage = 0; stage < shader->GetNumStages(); stage++ ) + { + const shaderStage_t* pStage = shader->GetStage( stage ); + + if( !pStage->hasAlphaTest ) + { + continue; + } + + // check the stage enable condition + if( regs[ pStage->conditionRegister ] == 0 ) + { + continue; + } + + // if we at least tried to draw an alpha tested stage, + // we won't draw the opaque surface + didDraw = true; + + // set the alpha modulate + color[3] = regs[ pStage->color.registers[3] ]; + + // skip the entire stage if alpha would be black + if( color[3] <= 0.0f ) + { + continue; + } + + uint64 stageGLState = surfGLState; + + // set privatePolygonOffset if necessary + if( pStage->privatePolygonOffset ) + { + GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * pStage->privatePolygonOffset ); + stageGLState |= GLS_POLYGON_OFFSET; + } + + GL_Color( color ); + +#ifdef USE_CORE_PROFILE + GL_State( stageGLState ); + idVec4 alphaTestValue( regs[ pStage->alphaTestRegister ] ); + SetFragmentParm( RENDERPARM_ALPHA_TEST, alphaTestValue.ToFloatPtr() ); +#else + GL_State( stageGLState | GLS_ALPHATEST_FUNC_GREATER | GLS_ALPHATEST_MAKE_REF( idMath::Ftob( 255.0f * regs[ pStage->alphaTestRegister ] ) ) ); +#endif + + if( drawSurf->jointCache ) + { + renderProgManager.BindShader_TextureVertexColorSkinned(); + } + else + { + renderProgManager.BindShader_TextureVertexColor(); + } + + RB_SetVertexColorParms( SVC_IGNORE ); + + // bind the texture + GL_SelectTexture( 0 ); + pStage->texture.image->Bind(); + + // set texture matrix and texGens + PrepareStageTexturing( pStage, drawSurf ); + + // must render with less-equal for Z-Cull to work properly + assert( ( GL_GetCurrentState() & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS ); + + // draw it + DrawElementsWithCounters( drawSurf ); + + // clean up + FinishStageTexturing( pStage, drawSurf ); + + // unset privatePolygonOffset if necessary + if( pStage->privatePolygonOffset ) + { + GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); + } + } + + if( !didDraw ) + { + drawSolid = true; + } + } + + // draw the entire surface solid + if( drawSolid ) + { + if( shader->GetSort() == SS_SUBVIEW ) + { + renderProgManager.BindShader_Color(); + GL_Color( color ); + GL_State( surfGLState ); + } + else + { + if( drawSurf->jointCache ) + { + renderProgManager.BindShader_DepthSkinned(); + } + else + { + renderProgManager.BindShader_Depth(); + } + GL_State( surfGLState | GLS_ALPHAMASK ); + } + + // must render with less-equal for Z-Cull to work properly + assert( ( GL_GetCurrentState() & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS ); + + // draw it + DrawElementsWithCounters( drawSurf ); + } + + renderLog.CloseBlock(); + } + +#ifdef USE_CORE_PROFILE + SetFragmentParm( RENDERPARM_ALPHA_TEST, vec4_zero.ToFloatPtr() ); +#endif +} + +/* +===================== +idRenderBackend::FillDepthBufferFast + +Optimized fast path code. + +If there are subview surfaces, they must be guarded in the depth buffer to allow +the mirror / subview to show through underneath the current view rendering. + +Surfaces with perforated shaders need the full shader setup done, but should be +drawn after the opaque surfaces. + +The bulk of the surfaces should be simple opaque geometry that can be drawn very rapidly. + +If there are no subview surfaces, we could clear to black and use fast-Z rendering +on the 360. +===================== +*/ +void idRenderBackend::FillDepthBufferFast( drawSurf_t** drawSurfs, int numDrawSurfs ) +{ + if( numDrawSurfs == 0 ) + { + return; + } + + // if we are just doing 2D rendering, no need to fill the depth buffer + if( viewDef->viewEntitys == NULL ) + { + return; + } + + renderLog.OpenMainBlock( MRB_FILL_DEPTH_BUFFER ); + renderLog.OpenBlock( "RB_FillDepthBufferFast" ); + + // force MVP change on first surface + currentSpace = NULL; + + // draw all the subview surfaces, which will already be at the start of the sorted list, + // with the general purpose path + GL_State( GLS_DEFAULT ); + + int surfNum; + for( surfNum = 0; surfNum < numDrawSurfs; surfNum++ ) + { + if( drawSurfs[surfNum]->material->GetSort() != SS_SUBVIEW ) + { + break; + } + + FillDepthBufferGeneric( &drawSurfs[surfNum], 1 ); + } + + const drawSurf_t** perforatedSurfaces = ( const drawSurf_t** )_alloca( numDrawSurfs * sizeof( drawSurf_t* ) ); + int numPerforatedSurfaces = 0; + + // draw all the opaque surfaces and build up a list of perforated surfaces that + // we will defer drawing until all opaque surfaces are done + GL_State( GLS_DEFAULT ); + + // continue checking past the subview surfaces + for( ; surfNum < numDrawSurfs; surfNum++ ) + { + const drawSurf_t* surf = drawSurfs[ surfNum ]; + const idMaterial* shader = surf->material; + + // translucent surfaces don't put anything in the depth buffer + if( shader->Coverage() == MC_TRANSLUCENT ) + { + continue; + } + if( shader->Coverage() == MC_PERFORATED ) + { + // save for later drawing + perforatedSurfaces[ numPerforatedSurfaces ] = surf; + numPerforatedSurfaces++; + continue; + } + + // set polygon offset? + + // set mvp matrix + if( surf->space != currentSpace ) + { + RB_SetMVP( surf->space->mvp ); + currentSpace = surf->space; + } + + renderLog.OpenBlock( shader->GetName() ); + + if( surf->jointCache ) + { + renderProgManager.BindShader_DepthSkinned(); + } + else + { + renderProgManager.BindShader_Depth(); + } + + // must render with less-equal for Z-Cull to work properly + assert( ( GL_GetCurrentState() & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS ); + + // draw it solid + DrawElementsWithCounters( surf ); + + renderLog.CloseBlock(); + } + + // draw all perforated surfaces with the general code path + if( numPerforatedSurfaces > 0 ) + { + FillDepthBufferGeneric( perforatedSurfaces, numPerforatedSurfaces ); + } + + renderLog.CloseBlock(); + renderLog.CloseMainBlock(); +} + +/* +========================================================================================= + +GENERAL INTERACTION RENDERING + +========================================================================================= +*/ + +const int INTERACTION_TEXUNIT_BUMP = 0; +const int INTERACTION_TEXUNIT_FALLOFF = 1; +const int INTERACTION_TEXUNIT_PROJECTION = 2; +const int INTERACTION_TEXUNIT_DIFFUSE = 3; +const int INTERACTION_TEXUNIT_SPECULAR = 4; +const int INTERACTION_TEXUNIT_SHADOWMAPS = 5; +const int INTERACTION_TEXUNIT_JITTER = 6; + +/* +================== +idRenderBackend::SetupInteractionStage +================== +*/ +void idRenderBackend::SetupInteractionStage( const shaderStage_t* surfaceStage, const float* surfaceRegs, const float lightColor[4], + idVec4 matrix[2], float color[4] ) +{ + + if( surfaceStage->texture.hasMatrix ) + { + matrix[0][0] = surfaceRegs[surfaceStage->texture.matrix[0][0]]; + matrix[0][1] = surfaceRegs[surfaceStage->texture.matrix[0][1]]; + matrix[0][2] = 0.0f; + matrix[0][3] = surfaceRegs[surfaceStage->texture.matrix[0][2]]; + + matrix[1][0] = surfaceRegs[surfaceStage->texture.matrix[1][0]]; + matrix[1][1] = surfaceRegs[surfaceStage->texture.matrix[1][1]]; + matrix[1][2] = 0.0f; + matrix[1][3] = surfaceRegs[surfaceStage->texture.matrix[1][2]]; + + // we attempt to keep scrolls from generating incredibly large texture values, but + // center rotations and center scales can still generate offsets that need to be > 1 + if( matrix[0][3] < -40.0f || matrix[0][3] > 40.0f ) + { + matrix[0][3] -= idMath::Ftoi( matrix[0][3] ); + } + if( matrix[1][3] < -40.0f || matrix[1][3] > 40.0f ) + { + matrix[1][3] -= idMath::Ftoi( matrix[1][3] ); + } + } + else + { + matrix[0][0] = 1.0f; + matrix[0][1] = 0.0f; + matrix[0][2] = 0.0f; + matrix[0][3] = 0.0f; + + matrix[1][0] = 0.0f; + matrix[1][1] = 1.0f; + matrix[1][2] = 0.0f; + matrix[1][3] = 0.0f; + } + + if( color != NULL ) + { + for( int i = 0; i < 4; i++ ) + { + // clamp here, so cards with a greater range don't look different. + // we could perform overbrighting like we do for lights, but + // it doesn't currently look worth it. + color[i] = idMath::ClampFloat( 0.0f, 1.0f, surfaceRegs[surfaceStage->color.registers[i]] ) * lightColor[i]; + } + } +} + +/* +================= +idRenderBackend::DrawSingleInteraction +================= +*/ +void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din ) +{ + if( din->bumpImage == NULL ) + { + // stage wasn't actually an interaction + return; + } + + if( din->diffuseImage == NULL || r_skipDiffuse.GetBool() ) + { + // this isn't a YCoCg black, but it doesn't matter, because + // the diffuseColor will also be 0 + din->diffuseImage = globalImages->blackImage; + } + if( din->specularImage == NULL || r_skipSpecular.GetBool() || din->ambientLight ) + { + din->specularImage = globalImages->blackImage; + } + if( r_skipBump.GetBool() ) + { + din->bumpImage = globalImages->flatNormalMap; + } + + // if we wouldn't draw anything, don't call the Draw function + const bool diffuseIsBlack = ( din->diffuseImage == globalImages->blackImage ) + || ( ( din->diffuseColor[0] <= 0 ) && ( din->diffuseColor[1] <= 0 ) && ( din->diffuseColor[2] <= 0 ) ); + const bool specularIsBlack = ( din->specularImage == globalImages->blackImage ) + || ( ( din->specularColor[0] <= 0 ) && ( din->specularColor[1] <= 0 ) && ( din->specularColor[2] <= 0 ) ); + if( diffuseIsBlack && specularIsBlack ) + { + return; + } + + // bump matrix + SetVertexParm( RENDERPARM_BUMPMATRIX_S, din->bumpMatrix[0].ToFloatPtr() ); + SetVertexParm( RENDERPARM_BUMPMATRIX_T, din->bumpMatrix[1].ToFloatPtr() ); + + // diffuse matrix + SetVertexParm( RENDERPARM_DIFFUSEMATRIX_S, din->diffuseMatrix[0].ToFloatPtr() ); + SetVertexParm( RENDERPARM_DIFFUSEMATRIX_T, din->diffuseMatrix[1].ToFloatPtr() ); + + // specular matrix + SetVertexParm( RENDERPARM_SPECULARMATRIX_S, din->specularMatrix[0].ToFloatPtr() ); + SetVertexParm( RENDERPARM_SPECULARMATRIX_T, din->specularMatrix[1].ToFloatPtr() ); + + RB_SetVertexColorParms( din->vertexColor ); + + SetFragmentParm( RENDERPARM_DIFFUSEMODIFIER, din->diffuseColor.ToFloatPtr() ); + SetFragmentParm( RENDERPARM_SPECULARMODIFIER, din->specularColor.ToFloatPtr() ); + + // texture 0 will be the per-surface bump map + GL_SelectTexture( INTERACTION_TEXUNIT_BUMP ); + din->bumpImage->Bind(); + + // texture 3 is the per-surface diffuse map + GL_SelectTexture( INTERACTION_TEXUNIT_DIFFUSE ); + din->diffuseImage->Bind(); + + // texture 4 is the per-surface specular map + GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR ); + din->specularImage->Bind(); + + DrawElementsWithCounters( din->surf ); +} + +/* +================= +RB_SetupForFastPathInteractions + +These are common for all fast path surfaces +================= +*/ +static void RB_SetupForFastPathInteractions( const idVec4& diffuseColor, const idVec4& specularColor ) +{ + const idVec4 sMatrix( 1, 0, 0, 0 ); + const idVec4 tMatrix( 0, 1, 0, 0 ); + + // bump matrix + SetVertexParm( RENDERPARM_BUMPMATRIX_S, sMatrix.ToFloatPtr() ); + SetVertexParm( RENDERPARM_BUMPMATRIX_T, tMatrix.ToFloatPtr() ); + + // diffuse matrix + SetVertexParm( RENDERPARM_DIFFUSEMATRIX_S, sMatrix.ToFloatPtr() ); + SetVertexParm( RENDERPARM_DIFFUSEMATRIX_T, tMatrix.ToFloatPtr() ); + + // specular matrix + SetVertexParm( RENDERPARM_SPECULARMATRIX_S, sMatrix.ToFloatPtr() ); + SetVertexParm( RENDERPARM_SPECULARMATRIX_T, tMatrix.ToFloatPtr() ); + + RB_SetVertexColorParms( SVC_IGNORE ); + + SetFragmentParm( RENDERPARM_DIFFUSEMODIFIER, diffuseColor.ToFloatPtr() ); + SetFragmentParm( RENDERPARM_SPECULARMODIFIER, specularColor.ToFloatPtr() ); +} + +/* +============= +idRenderBackend::RenderInteractions + +With added sorting and trivial path work. +============= +*/ +void idRenderBackend::RenderInteractions( const drawSurf_t* surfList, const viewLight_t* vLight, int depthFunc, bool performStencilTest, bool useLightDepthBounds ) +{ + if( surfList == NULL ) + { + return; + } + + // change the scissor if needed, it will be constant across all the surfaces lit by the light + if( !currentScissor.Equals( vLight->scissorRect ) && r_useScissor.GetBool() ) + { + GL_Scissor( viewDef->viewport.x1 + vLight->scissorRect.x1, + viewDef->viewport.y1 + vLight->scissorRect.y1, + vLight->scissorRect.x2 + 1 - vLight->scissorRect.x1, + vLight->scissorRect.y2 + 1 - vLight->scissorRect.y1 ); + + currentScissor = vLight->scissorRect; + } + + // perform setup here that will be constant for all interactions + if( performStencilTest ) + { + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | depthFunc | GLS_STENCIL_FUNC_EQUAL | GLS_STENCIL_MAKE_REF( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK( STENCIL_SHADOW_MASK_VALUE ) ); + + } + else + { + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | depthFunc | GLS_STENCIL_FUNC_ALWAYS ); + } + + // some rare lights have multiple animating stages, loop over them outside the surface list + const idMaterial* lightShader = vLight->lightShader; + const float* lightRegs = vLight->shaderRegisters; + + drawInteraction_t inter = {}; + inter.ambientLight = lightShader->IsAmbientLight(); + + //--------------------------------- + // Split out the complex surfaces from the fast-path surfaces + // so we can do the fast path ones all in a row. + // The surfaces should already be sorted by space because they + // are added single-threaded, and there is only a negligable amount + // of benefit to trying to sort by materials. + //--------------------------------- + static const int MAX_INTERACTIONS_PER_LIGHT = 1024; + static const int MAX_COMPLEX_INTERACTIONS_PER_LIGHT = 256; + idStaticList< const drawSurf_t*, MAX_INTERACTIONS_PER_LIGHT > allSurfaces; + idStaticList< const drawSurf_t*, MAX_COMPLEX_INTERACTIONS_PER_LIGHT > complexSurfaces; + for( const drawSurf_t* walk = surfList; walk != NULL; walk = walk->nextOnLight ) + { + + // make sure the triangle culling is done + if( walk->shadowVolumeState != SHADOWVOLUME_DONE ) + { + assert( walk->shadowVolumeState == SHADOWVOLUME_UNFINISHED || walk->shadowVolumeState == SHADOWVOLUME_DONE ); + + uint64 start = Sys_Microseconds(); + while( walk->shadowVolumeState == SHADOWVOLUME_UNFINISHED ) + { + Sys_Yield(); + } + uint64 end = Sys_Microseconds(); + + pc.shadowMicroSec += end - start; + } + + const idMaterial* surfaceShader = walk->material; + if( surfaceShader->GetFastPathBumpImage() ) + { + allSurfaces.Append( walk ); + } + else + { + complexSurfaces.Append( walk ); + } + } + for( int i = 0; i < complexSurfaces.Num(); i++ ) + { + allSurfaces.Append( complexSurfaces[i] ); + } + + bool lightDepthBoundsDisabled = false; + + // RB begin + if( r_useShadowMapping.GetBool() ) + { + const static int JITTER_SIZE = 128; + + // default high quality + float jitterSampleScale = 1.0f; + float shadowMapSamples = r_shadowMapSamples.GetInteger(); + + // screen power of two correction factor + float screenCorrectionParm[4]; + screenCorrectionParm[0] = 1.0f / ( JITTER_SIZE * shadowMapSamples ) ; + screenCorrectionParm[1] = 1.0f / JITTER_SIZE; + screenCorrectionParm[2] = 1.0f / shadowMapResolutions[vLight->shadowLOD]; + screenCorrectionParm[3] = vLight->parallel ? r_shadowMapSunDepthBiasScale.GetFloat() : r_shadowMapRegularDepthBiasScale.GetFloat(); + SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor + + float jitterTexScale[4]; + jitterTexScale[0] = r_shadowMapJitterScale.GetFloat() * jitterSampleScale; // TODO shadow buffer size fraction shadowMapSize / maxShadowMapSize + jitterTexScale[1] = r_shadowMapJitterScale.GetFloat() * jitterSampleScale; + jitterTexScale[2] = -r_shadowMapBiasScale.GetFloat(); + jitterTexScale[3] = 0.0f; + SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale + + float jitterTexOffset[4]; + if( r_shadowMapRandomizeJitter.GetBool() ) + { + jitterTexOffset[0] = ( rand() & 255 ) / 255.0; + jitterTexOffset[1] = ( rand() & 255 ) / 255.0; + } + else + { + jitterTexOffset[0] = 0; + jitterTexOffset[1] = 0; + } + jitterTexOffset[2] = 0.0f; + jitterTexOffset[3] = 0.0f; + SetFragmentParm( RENDERPARM_JITTERTEXOFFSET, jitterTexOffset ); // rpJitterTexOffset + + if( vLight->parallel ) + { + float cascadeDistances[4]; + cascadeDistances[0] = viewDef->frustumSplitDistances[0]; + cascadeDistances[1] = viewDef->frustumSplitDistances[1]; + cascadeDistances[2] = viewDef->frustumSplitDistances[2]; + cascadeDistances[3] = viewDef->frustumSplitDistances[3]; + SetFragmentParm( RENDERPARM_CASCADEDISTANCES, cascadeDistances ); // rpCascadeDistances + } + + } + // RB end + + float lightScale = r_useHDR.GetBool() ? 3.0f : r_lightScale.GetFloat(); + + for( int lightStageNum = 0; lightStageNum < lightShader->GetNumStages(); lightStageNum++ ) + { + const shaderStage_t* lightStage = lightShader->GetStage( lightStageNum ); + + // ignore stages that fail the condition + if( !lightRegs[ lightStage->conditionRegister ] ) + { + continue; + } + + const idVec4 lightColor( + lightScale * lightRegs[ lightStage->color.registers[0] ], + lightScale * lightRegs[ lightStage->color.registers[1] ], + lightScale * lightRegs[ lightStage->color.registers[2] ], + lightRegs[ lightStage->color.registers[3] ] ); + // apply the world-global overbright and the 2x factor for specular + const idVec4 diffuseColor = lightColor; + const idVec4 specularColor = lightColor * 2.0f; + + float lightTextureMatrix[16]; + if( lightStage->texture.hasMatrix ) + { + RB_GetShaderTextureMatrix( lightRegs, &lightStage->texture, lightTextureMatrix ); + } + + // texture 1 will be the light falloff texture + GL_SelectTexture( INTERACTION_TEXUNIT_FALLOFF ); + vLight->falloffImage->Bind(); + + // texture 2 will be the light projection texture + GL_SelectTexture( INTERACTION_TEXUNIT_PROJECTION ); + lightStage->texture.image->Bind(); + + if( r_useShadowMapping.GetBool() ) + { + // texture 5 will be the shadow maps array + GL_SelectTexture( INTERACTION_TEXUNIT_SHADOWMAPS ); + globalImages->shadowImage[vLight->shadowLOD]->Bind(); + + // texture 6 will be the jitter texture for soft shadowing + GL_SelectTexture( INTERACTION_TEXUNIT_JITTER ); + if( r_shadowMapSamples.GetInteger() == 16 ) + { + globalImages->jitterImage16->Bind(); + } + else if( r_shadowMapSamples.GetInteger() == 4 ) + { + globalImages->jitterImage4->Bind(); + } + else + { + globalImages->jitterImage1->Bind(); + } + } + + // force the light textures to not use anisotropic filtering, which is wasted on them + // all of the texture sampler parms should be constant for all interactions, only + // the actual texture image bindings will change + + //---------------------------------- + // For all surfaces on this light list, generate an interaction for this light stage + //---------------------------------- + + // setup renderparms assuming we will be drawing trivial surfaces first + RB_SetupForFastPathInteractions( diffuseColor, specularColor ); + + // even if the space does not change between light stages, each light stage may need a different lightTextureMatrix baked in + currentSpace = NULL; + + for( int sortedSurfNum = 0; sortedSurfNum < allSurfaces.Num(); sortedSurfNum++ ) + { + const drawSurf_t* const surf = allSurfaces[ sortedSurfNum ]; + + // select the render prog + if( lightShader->IsAmbientLight() ) + { + if( surf->jointCache ) + { + renderProgManager.BindShader_InteractionAmbientSkinned(); + } + else + { + renderProgManager.BindShader_InteractionAmbient(); + } + } + else + { + if( r_useShadowMapping.GetBool() && vLight->globalShadows ) + { + // RB: we have shadow mapping enabled and shadow maps so do a shadow compare + + if( vLight->parallel ) + { + if( surf->jointCache ) + { + renderProgManager.BindShader_Interaction_ShadowMapping_Parallel_Skinned(); + } + else + { + renderProgManager.BindShader_Interaction_ShadowMapping_Parallel(); + } + } + else if( vLight->pointLight ) + { + if( surf->jointCache ) + { + renderProgManager.BindShader_Interaction_ShadowMapping_Point_Skinned(); + } + else + { + renderProgManager.BindShader_Interaction_ShadowMapping_Point(); + } + } + else + { + if( surf->jointCache ) + { + renderProgManager.BindShader_Interaction_ShadowMapping_Spot_Skinned(); + } + else + { + renderProgManager.BindShader_Interaction_ShadowMapping_Spot(); + } + } + } + else + { + if( surf->jointCache ) + { + renderProgManager.BindShader_InteractionSkinned(); + } + else + { + renderProgManager.BindShader_Interaction(); + } + } + } + + const idMaterial* surfaceShader = surf->material; + const float* surfaceRegs = surf->shaderRegisters; + + inter.surf = surf; + + // change the MVP matrix, view/light origin and light projection vectors if needed + if( surf->space != currentSpace ) + { + currentSpace = surf->space; + + // turn off the light depth bounds test if this model is rendered with a depth hack + if( useLightDepthBounds ) + { + if( !surf->space->weaponDepthHack && surf->space->modelDepthHack == 0.0f ) + { + if( lightDepthBoundsDisabled ) + { + GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax ); + lightDepthBoundsDisabled = false; + } + } + else + { + if( !lightDepthBoundsDisabled ) + { + GL_DepthBoundsTest( 0.0f, 0.0f ); + lightDepthBoundsDisabled = true; + } + } + } + + // model-view-projection + RB_SetMVP( surf->space->mvp ); + + // RB begin + idRenderMatrix modelMatrix; + idRenderMatrix::Transpose( *( idRenderMatrix* )surf->space->modelMatrix, modelMatrix ); + + SetVertexParms( RENDERPARM_MODELMATRIX_X, modelMatrix[0], 4 ); + + // for determining the shadow mapping cascades + idRenderMatrix modelViewMatrix, tmp; + idRenderMatrix::Transpose( *( idRenderMatrix* )surf->space->modelViewMatrix, modelViewMatrix ); + SetVertexParms( RENDERPARM_MODELVIEWMATRIX_X, modelViewMatrix[0], 4 ); + + idVec4 globalLightOrigin( vLight->globalLightOrigin.x, vLight->globalLightOrigin.y, vLight->globalLightOrigin.z, 1.0f ); + SetVertexParm( RENDERPARM_GLOBALLIGHTORIGIN, globalLightOrigin.ToFloatPtr() ); + // RB end + + // tranform the light/view origin into model local space + idVec4 localLightOrigin( 0.0f ); + idVec4 localViewOrigin( 1.0f ); + R_GlobalPointToLocal( surf->space->modelMatrix, vLight->globalLightOrigin, localLightOrigin.ToVec3() ); + R_GlobalPointToLocal( surf->space->modelMatrix, viewDef->renderView.vieworg, localViewOrigin.ToVec3() ); + + // set the local light/view origin + SetVertexParm( RENDERPARM_LOCALLIGHTORIGIN, localLightOrigin.ToFloatPtr() ); + SetVertexParm( RENDERPARM_LOCALVIEWORIGIN, localViewOrigin.ToFloatPtr() ); + + // transform the light project into model local space + idPlane lightProjection[4]; + for( int i = 0; i < 4; i++ ) + { + R_GlobalPlaneToLocal( surf->space->modelMatrix, vLight->lightProject[i], lightProjection[i] ); + } + + // optionally multiply the local light projection by the light texture matrix + if( lightStage->texture.hasMatrix ) + { + RB_BakeTextureMatrixIntoTexgen( lightProjection, lightTextureMatrix ); + } + + // set the light projection + SetVertexParm( RENDERPARM_LIGHTPROJECTION_S, lightProjection[0].ToFloatPtr() ); + SetVertexParm( RENDERPARM_LIGHTPROJECTION_T, lightProjection[1].ToFloatPtr() ); + SetVertexParm( RENDERPARM_LIGHTPROJECTION_Q, lightProjection[2].ToFloatPtr() ); + SetVertexParm( RENDERPARM_LIGHTFALLOFF_S, lightProjection[3].ToFloatPtr() ); + + // RB begin + if( r_useShadowMapping.GetBool() ) + { + if( vLight->parallel ) + { + for( int i = 0; i < ( r_shadowMapSplits.GetInteger() + 1 ); i++ ) + { + idRenderMatrix modelToShadowMatrix; + idRenderMatrix::Multiply( shadowV[i], modelMatrix, modelToShadowMatrix ); + + idRenderMatrix shadowClipMVP; + idRenderMatrix::Multiply( shadowP[i], modelToShadowMatrix, shadowClipMVP ); + + idRenderMatrix shadowWindowMVP; + idRenderMatrix::Multiply( renderMatrix_clipSpaceToWindowSpace, shadowClipMVP, shadowWindowMVP ); + + SetVertexParms( ( renderParm_t )( RENDERPARM_SHADOW_MATRIX_0_X + i * 4 ), shadowWindowMVP[0], 4 ); + } + } + else if( vLight->pointLight ) + { + for( int i = 0; i < 6; i++ ) + { + idRenderMatrix modelToShadowMatrix; + idRenderMatrix::Multiply( shadowV[i], modelMatrix, modelToShadowMatrix ); + + idRenderMatrix shadowClipMVP; + idRenderMatrix::Multiply( shadowP[i], modelToShadowMatrix, shadowClipMVP ); + + idRenderMatrix shadowWindowMVP; + idRenderMatrix::Multiply( renderMatrix_clipSpaceToWindowSpace, shadowClipMVP, shadowWindowMVP ); + + SetVertexParms( ( renderParm_t )( RENDERPARM_SHADOW_MATRIX_0_X + i * 4 ), shadowWindowMVP[0], 4 ); + } + } + else + { + // spot light + + idRenderMatrix modelToShadowMatrix; + idRenderMatrix::Multiply( shadowV[0], modelMatrix, modelToShadowMatrix ); + + idRenderMatrix shadowClipMVP; + idRenderMatrix::Multiply( shadowP[0], modelToShadowMatrix, shadowClipMVP ); + + SetVertexParms( ( renderParm_t )( RENDERPARM_SHADOW_MATRIX_0_X ), shadowClipMVP[0], 4 ); + + } + } + // RB end + } + + // check for the fast path + if( surfaceShader->GetFastPathBumpImage() && !r_skipInteractionFastPath.GetBool() ) + { + renderLog.OpenBlock( surf->material->GetName() ); + + // texture 0 will be the per-surface bump map + GL_SelectTexture( INTERACTION_TEXUNIT_BUMP ); + surfaceShader->GetFastPathBumpImage()->Bind(); + + // texture 3 is the per-surface diffuse map + GL_SelectTexture( INTERACTION_TEXUNIT_DIFFUSE ); + surfaceShader->GetFastPathDiffuseImage()->Bind(); + + // texture 4 is the per-surface specular map + GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR ); + surfaceShader->GetFastPathSpecularImage()->Bind(); + + DrawElementsWithCounters( surf ); + + renderLog.CloseBlock(); + continue; + } + + renderLog.OpenBlock( surf->material->GetName() ); + + inter.bumpImage = NULL; + inter.specularImage = NULL; + inter.diffuseImage = NULL; + inter.diffuseColor[0] = inter.diffuseColor[1] = inter.diffuseColor[2] = inter.diffuseColor[3] = 0; + inter.specularColor[0] = inter.specularColor[1] = inter.specularColor[2] = inter.specularColor[3] = 0; + + // go through the individual surface stages + // + // This is somewhat arcane because of the old support for video cards that had to render + // interactions in multiple passes. + // + // We also have the very rare case of some materials that have conditional interactions + // for the "hell writing" that can be shined on them. + for( int surfaceStageNum = 0; surfaceStageNum < surfaceShader->GetNumStages(); surfaceStageNum++ ) + { + const shaderStage_t* surfaceStage = surfaceShader->GetStage( surfaceStageNum ); + + switch( surfaceStage->lighting ) + { + case SL_COVERAGE: + { + // ignore any coverage stages since they should only be used for the depth fill pass + // for diffuse stages that use alpha test. + break; + } + case SL_AMBIENT: + { + // ignore ambient stages while drawing interactions + break; + } + case SL_BUMP: + { + // ignore stage that fails the condition + if( !surfaceRegs[ surfaceStage->conditionRegister ] ) + { + break; + } + // draw any previous interaction + if( inter.bumpImage != NULL ) + { + DrawSingleInteraction( &inter ); + } + inter.bumpImage = surfaceStage->texture.image; + inter.diffuseImage = NULL; + inter.specularImage = NULL; + SetupInteractionStage( surfaceStage, surfaceRegs, NULL, inter.bumpMatrix, NULL ); + break; + } + case SL_DIFFUSE: + { + // ignore stage that fails the condition + if( !surfaceRegs[ surfaceStage->conditionRegister ] ) + { + break; + } + // draw any previous interaction + if( inter.diffuseImage != NULL ) + { + DrawSingleInteraction( &inter ); + } + inter.diffuseImage = surfaceStage->texture.image; + inter.vertexColor = surfaceStage->vertexColor; + SetupInteractionStage( surfaceStage, surfaceRegs, diffuseColor.ToFloatPtr(), + inter.diffuseMatrix, inter.diffuseColor.ToFloatPtr() ); + break; + } + case SL_SPECULAR: + { + // ignore stage that fails the condition + if( !surfaceRegs[ surfaceStage->conditionRegister ] ) + { + break; + } + // draw any previous interaction + if( inter.specularImage != NULL ) + { + DrawSingleInteraction( &inter ); + } + inter.specularImage = surfaceStage->texture.image; + inter.vertexColor = surfaceStage->vertexColor; + SetupInteractionStage( surfaceStage, surfaceRegs, specularColor.ToFloatPtr(), + inter.specularMatrix, inter.specularColor.ToFloatPtr() ); + break; + } + } + } + + // draw the final interaction + DrawSingleInteraction( &inter ); + + renderLog.CloseBlock(); + } + } + + if( useLightDepthBounds && lightDepthBoundsDisabled ) + { + GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax ); + } + + renderProgManager.Unbind(); +} + +// RB begin + +/* +========================================================================================= + +AMBIENT PASS RENDERING + +========================================================================================= +*/ + +/* +================== +idRenderBackend::AmbientPass +================== +*/ +void idRenderBackend::AmbientPass( const drawSurf_t* const* drawSurfs, int numDrawSurfs, bool fillGbuffer ) +{ + if( fillGbuffer ) + { + if( !r_useSSGI.GetBool() && !r_useSSAO.GetBool() ) + { + return; + } + } + else + { + if( r_forceAmbient.GetFloat() <= 0 || r_skipAmbient.GetBool() ) + { + return; + } + } + + if( numDrawSurfs == 0 ) + { + return; + } + + // if we are just doing 2D rendering, no need to fill the depth buffer + if( viewDef->viewEntitys == NULL ) + { + return; + } + + const bool hdrIsActive = ( r_useHDR.GetBool() && globalFramebuffers.hdrFBO != NULL && globalFramebuffers.hdrFBO->IsBound() ); + + /* + if( fillGbuffer ) + { + globalFramebuffers.geometryBufferFBO->Bind(); + + glClearColor( 0, 0, 0, 0 ); + glClear( GL_COLOR_BUFFER_BIT ); + } + */ + + renderLog.OpenMainBlock( MRB_AMBIENT_PASS ); + renderLog.OpenBlock( "RB_AmbientPass" ); + + // RB: not needed + // GL_StartDepthPass( backEnd.viewDef->scissor ); + + // force MVP change on first surface + currentSpace = NULL; + + // draw all the subview surfaces, which will already be at the start of the sorted list, + // with the general purpose path + //GL_State( GLS_DEFAULT ); + + //if( fillGbuffer ) + { + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL ); + } + //else + //{ + // GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL ); + //} + + GL_Color( colorWhite ); + + const float lightScale = 1.0f; //r_lightScale.GetFloat(); + const idVec4 lightColor = colorWhite * lightScale; + // apply the world-global overbright and the 2x factor for specular + const idVec4 diffuseColor = lightColor; + const idVec4 specularColor = lightColor * 2.0f; + + idVec4 ambientColor; + float ambientBoost = 1.0f; + ambientBoost += r_useSSAO.GetBool() ? 0.2f : 0.0f; + ambientBoost *= r_useHDR.GetBool() ? 1.1f : 1.0f; + ambientColor.x = r_forceAmbient.GetFloat() * ambientBoost; + ambientColor.y = r_forceAmbient.GetFloat() * ambientBoost; + ambientColor.z = r_forceAmbient.GetFloat() * ambientBoost; + ambientColor.w = 1; + + renderProgManager.SetRenderParm( RENDERPARM_AMBIENT_COLOR, ambientColor.ToFloatPtr() ); + + // setup renderparms assuming we will be drawing trivial surfaces first + RB_SetupForFastPathInteractions( diffuseColor, specularColor ); + + for( int i = 0; i < numDrawSurfs; i++ ) + { + const drawSurf_t* drawSurf = drawSurfs[i]; + const idMaterial* surfaceMaterial = drawSurf->material; + + // translucent surfaces don't put anything in the depth buffer and don't + // test against it, which makes them fail the mirror clip plane operation + if( surfaceMaterial->Coverage() == MC_TRANSLUCENT ) + { + continue; + } + + // get the expressions for conditionals / color / texcoords + const float* surfaceRegs = drawSurf->shaderRegisters; + + // if all stages of a material have been conditioned off, don't do anything + int stage = 0; + for( ; stage < surfaceMaterial->GetNumStages(); stage++ ) + { + const shaderStage_t* pStage = surfaceMaterial->GetStage( stage ); + // check the stage enable condition + if( surfaceRegs[ pStage->conditionRegister ] != 0 ) + { + break; + } + } + if( stage == surfaceMaterial->GetNumStages() ) + { + continue; + } + + //bool isWorldModel = ( drawSurf->space->entityDef->parms.origin == vec3_origin ); + + //if( isWorldModel ) + //{ + // renderProgManager.BindShader_VertexLighting(); + //} + //else + { +#if 1 + if( fillGbuffer ) + { + // fill geometry buffer with normal/roughness information + if( drawSurf->jointCache ) + { + renderProgManager.BindShader_SmallGeometryBufferSkinned(); + } + else + { + renderProgManager.BindShader_SmallGeometryBuffer(); + } + } + else +#endif + { + // draw Quake 4 style ambient + if( drawSurf->jointCache ) + { + renderProgManager.BindShader_AmbientLightingSkinned(); + } + else + { + renderProgManager.BindShader_AmbientLighting(); + } + } + } + + // change the matrix if needed + if( drawSurf->space != currentSpace ) + { + currentSpace = drawSurf->space; + + RB_SetMVP( drawSurf->space->mvp ); + + // tranform the view origin into model local space + idVec4 localViewOrigin( 1.0f ); + R_GlobalPointToLocal( drawSurf->space->modelMatrix, viewDef->renderView.vieworg, localViewOrigin.ToVec3() ); + SetVertexParm( RENDERPARM_LOCALVIEWORIGIN, localViewOrigin.ToFloatPtr() ); + + //if( !isWorldModel ) + //{ + // // tranform the light direction into model local space + // idVec3 globalLightDirection( 0.0f, 0.0f, -1.0f ); // HACK + // idVec4 localLightDirection( 0.0f ); + // R_GlobalVectorToLocal( drawSurf->space->modelMatrix, globalLightDirection, localLightDirection.ToVec3() ); + // + // SetVertexParm( RENDERPARM_LOCALLIGHTORIGIN, localLightDirection.ToFloatPtr() ); + //} + + // RB: if we want to store the normals in world space so we need the model -> world matrix + idRenderMatrix modelMatrix; + idRenderMatrix::Transpose( *( idRenderMatrix* )drawSurf->space->modelMatrix, modelMatrix ); + + SetVertexParms( RENDERPARM_MODELMATRIX_X, modelMatrix[0], 4 ); + + // RB: if we want to store the normals in camera space so we need the model -> camera matrix + float modelViewMatrixTranspose[16]; + R_MatrixTranspose( drawSurf->space->modelViewMatrix, modelViewMatrixTranspose ); + SetVertexParms( RENDERPARM_MODELVIEWMATRIX_X, modelViewMatrixTranspose, 4 ); + } + +#if 0 + if( !isWorldModel ) + { + idVec4 directedColor; + directedColor.x = drawSurf->space->gridDirectedLight.x; + directedColor.y = drawSurf->space->gridDirectedLight.y; + directedColor.z = drawSurf->space->gridDirectedLight.z; + directedColor.w = 1; + + idVec4 ambientColor; + ambientColor.x = drawSurf->space->gridAmbientLight.x; + ambientColor.y = drawSurf->space->gridAmbientLight.y; + ambientColor.z = drawSurf->space->gridAmbientLight.z; + ambientColor.w = 1; + + renderProgManager.SetRenderParm( RENDERPARM_COLOR, directedColor.ToFloatPtr() ); + renderProgManager.SetRenderParm( RENDERPARM_AMBIENT_COLOR, ambientColor.ToFloatPtr() ); + } +#endif + + /* + uint64 surfGLState = 0; + + // set polygon offset if necessary + if( surfaceMaterial->TestMaterialFlag( MF_POLYGONOFFSET ) ) + { + surfGLState |= GLS_POLYGON_OFFSET; + GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * surfaceMaterial->GetPolygonOffset() ); + } + + // subviews will just down-modulate the color buffer + idVec4 color; + if( surfaceMaterial->GetSort() == SS_SUBVIEW ) + { + surfGLState |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHFUNC_LESS; + color[0] = 1.0f; + color[1] = 1.0f; + color[2] = 1.0f; + color[3] = 1.0f; + } + else + { + // others just draw black + #if 0 + color[0] = 0.0f; + color[1] = 0.0f; + color[2] = 0.0f; + color[3] = 1.0f; + #else + color = colorWhite; + #endif + } + */ + + // check for the fast path + if( surfaceMaterial->GetFastPathBumpImage() && !r_skipInteractionFastPath.GetBool() ) + { + renderLog.OpenBlock( surfaceMaterial->GetName() ); + + // texture 0 will be the per-surface bump map + GL_SelectTexture( INTERACTION_TEXUNIT_BUMP ); + surfaceMaterial->GetFastPathBumpImage()->Bind(); + + // texture 3 is the per-surface diffuse map + GL_SelectTexture( INTERACTION_TEXUNIT_DIFFUSE ); + surfaceMaterial->GetFastPathDiffuseImage()->Bind(); + + // texture 4 is the per-surface specular map + GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR ); + surfaceMaterial->GetFastPathSpecularImage()->Bind(); + + DrawElementsWithCounters( drawSurf ); + + renderLog.CloseBlock(); + continue; + } + + renderLog.OpenBlock( surfaceMaterial->GetName() ); + + //bool drawSolid = false; + + + // we may have multiple alpha tested stages + // if the only alpha tested stages are condition register omitted, + // draw a normal opaque surface + bool didDraw = false; + + drawInteraction_t inter = {}; + inter.surf = drawSurf; + inter.bumpImage = NULL; + inter.specularImage = NULL; + inter.diffuseImage = NULL; + + inter.diffuseColor[0] = inter.diffuseColor[1] = inter.diffuseColor[2] = inter.diffuseColor[3] = 1; + inter.specularColor[0] = inter.specularColor[1] = inter.specularColor[2] = inter.specularColor[3] = 0; + + // perforated surfaces may have multiple alpha tested stages + for( stage = 0; stage < surfaceMaterial->GetNumStages(); stage++ ) + { + const shaderStage_t* surfaceStage = surfaceMaterial->GetStage( stage ); + + switch( surfaceStage->lighting ) + { + case SL_COVERAGE: + { + // ignore any coverage stages since they should only be used for the depth fill pass + // for diffuse stages that use alpha test. + break; + } + + case SL_AMBIENT: + { + // ignore ambient stages while drawing interactions + break; + } + + case SL_BUMP: + { + // ignore stage that fails the condition + if( !surfaceRegs[ surfaceStage->conditionRegister ] ) + { + break; + } + // draw any previous interaction + if( inter.bumpImage != NULL ) + { + DrawSingleInteraction( &inter ); + } + inter.bumpImage = surfaceStage->texture.image; + inter.diffuseImage = NULL; + inter.specularImage = NULL; + SetupInteractionStage( surfaceStage, surfaceRegs, NULL, + inter.bumpMatrix, NULL ); + break; + } + + case SL_DIFFUSE: + { + // ignore stage that fails the condition + if( !surfaceRegs[ surfaceStage->conditionRegister ] ) + { + break; + } + + // draw any previous interaction + if( inter.diffuseImage != NULL ) + { + DrawSingleInteraction( &inter ); + } + + inter.diffuseImage = surfaceStage->texture.image; + inter.vertexColor = surfaceStage->vertexColor; + SetupInteractionStage( surfaceStage, surfaceRegs, diffuseColor.ToFloatPtr(), + inter.diffuseMatrix, inter.diffuseColor.ToFloatPtr() ); + break; + } + + case SL_SPECULAR: + { + // ignore stage that fails the condition + if( !surfaceRegs[ surfaceStage->conditionRegister ] ) + { + break; + } + // draw any previous interaction + if( inter.specularImage != NULL ) + { + DrawSingleInteraction( &inter ); + } + inter.specularImage = surfaceStage->texture.image; + inter.vertexColor = surfaceStage->vertexColor; + SetupInteractionStage( surfaceStage, surfaceRegs, specularColor.ToFloatPtr(), + inter.specularMatrix, inter.specularColor.ToFloatPtr() ); + break; + } + } + } + + // draw the final interaction + DrawSingleInteraction( &inter ); + + renderLog.CloseBlock(); + } + +#ifdef USE_CORE_PROFILE + SetFragmentParm( RENDERPARM_ALPHA_TEST, vec4_zero.ToFloatPtr() ); +#endif + + renderLog.CloseBlock(); + renderLog.CloseMainBlock(); + + GL_SelectTexture( 0 ); + + if( fillGbuffer ) + { + // FIXME: this copies RGBA16F into _currentNormals if HDR is enabled + const idScreenRect& viewport = viewDef->viewport; + globalImages->currentNormalsImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); + + //GL_Clear( true, false, false, STENCIL_SHADOW_TEST_VALUE, 0.0f, 0.0f, 0.0f, 1.0f, false ); + + + /* + if( hdrIsActive ) + { + globalFramebuffers.hdrFBO->Bind(); + } + else + { + Framebuffer::Unbind(); + } + */ + } + + renderProgManager.Unbind(); +} + +// RB end + +/* +============================================================================================== + +STENCIL SHADOW RENDERING + +============================================================================================== +*/ + +/* +===================== +idRenderBackend::StencilShadowPass + +The stencil buffer should have been set to 128 on any surfaces that might receive shadows. +===================== +*/ +void idRenderBackend::StencilShadowPass( const drawSurf_t* drawSurfs, const viewLight_t* vLight ) +{ + if( r_skipShadows.GetBool() ) + { + return; + } + + if( drawSurfs == NULL ) + { + return; + } + + RENDERLOG_PRINTF( "---------- RB_StencilShadowPass ----------\n" ); + + renderProgManager.BindShader_Shadow(); + + GL_SelectTexture( 0 ); + + uint64 glState = 0; + + // for visualizing the shadows + if( r_showShadows.GetInteger() ) + { + // set the debug shadow color + SetFragmentParm( RENDERPARM_COLOR, colorMagenta.ToFloatPtr() ); + if( r_showShadows.GetInteger() == 2 ) + { + // draw filled in + glState = GLS_DEPTHMASK | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_LESS; + } + else + { + // draw as lines, filling the depth buffer + glState = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS; + } + } + else + { + // don't write to the color or depth buffer, just the stencil buffer + glState = GLS_DEPTHMASK | GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHFUNC_LESS; + } + + GL_PolygonOffset( r_shadowPolygonFactor.GetFloat(), -r_shadowPolygonOffset.GetFloat() ); + + // the actual stencil func will be set in the draw code, but we need to make sure it isn't + // disabled here, and that the value will get reset for the interactions without looking + // like a no-change-required + GL_State( glState | GLS_STENCIL_OP_FAIL_KEEP | GLS_STENCIL_OP_ZFAIL_KEEP | GLS_STENCIL_OP_PASS_INCR | + GLS_STENCIL_MAKE_REF( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK( STENCIL_SHADOW_MASK_VALUE ) | GLS_POLYGON_OFFSET ); + + // Two Sided Stencil reduces two draw calls to one for slightly faster shadows + GL_Cull( CT_TWO_SIDED ); + + + // process the chain of shadows with the current rendering state + currentSpace = NULL; + + for( const drawSurf_t* drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight ) + { + if( drawSurf->scissorRect.IsEmpty() ) + { + continue; // !@# FIXME: find out why this is sometimes being hit! + // temporarily jump over the scissor and draw so the gl error callback doesn't get hit + } + + // make sure the shadow volume is done + if( drawSurf->shadowVolumeState != SHADOWVOLUME_DONE ) + { + assert( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED || drawSurf->shadowVolumeState == SHADOWVOLUME_DONE ); + + uint64 start = Sys_Microseconds(); + while( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED ) + { + Sys_Yield(); + } + uint64 end = Sys_Microseconds(); + + pc.shadowMicroSec += end - start; + } + + if( drawSurf->numIndexes == 0 ) + { + continue; // a job may have created an empty shadow volume + } + + if( !currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) + { + // change the scissor + GL_Scissor( viewDef->viewport.x1 + drawSurf->scissorRect.x1, + viewDef->viewport.y1 + drawSurf->scissorRect.y1, + drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1, + drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 ); + + currentScissor = drawSurf->scissorRect; + } + + if( drawSurf->space != currentSpace ) + { + // change the matrix + RB_SetMVP( drawSurf->space->mvp ); + + // set the local light position to allow the vertex program to project the shadow volume end cap to infinity + idVec4 localLight( 0.0f ); + R_GlobalPointToLocal( drawSurf->space->modelMatrix, vLight->globalLightOrigin, localLight.ToVec3() ); + SetVertexParm( RENDERPARM_LOCALLIGHTORIGIN, localLight.ToFloatPtr() ); + + currentSpace = drawSurf->space; + } + + if( r_showShadows.GetInteger() == 0 ) + { + if( drawSurf->jointCache ) + { + renderProgManager.BindShader_ShadowSkinned(); + } + else + { + renderProgManager.BindShader_Shadow(); + } + } + else + { + if( drawSurf->jointCache ) + { + renderProgManager.BindShader_ShadowDebugSkinned(); + } + else + { + renderProgManager.BindShader_ShadowDebug(); + } + } + + // set depth bounds per shadow + if( r_useShadowDepthBounds.GetBool() ) + { + GL_DepthBoundsTest( drawSurf->scissorRect.zmin, drawSurf->scissorRect.zmax ); + } + + // Determine whether or not the shadow volume needs to be rendered with Z-pass or + // Z-fail. It is worthwhile to spend significant resources to reduce the number of + // cases where shadow volumes need to be rendered with Z-fail because Z-fail + // rendering can be significantly slower even on today's hardware. For instance, + // on NVIDIA hardware Z-fail rendering causes the Z-Cull to be used in reverse: + // Z-near becomes Z-far (trivial accept becomes trivial reject). Using the Z-Cull + // in reverse is far less efficient because the Z-Cull only stores Z-near per 16x16 + // pixels while the Z-far is stored per 4x2 pixels. (The Z-near coallesce buffer + // which has 4x4 granularity is only used when updating the depth which is not the + // case for shadow volumes.) Note that it is also important to NOT use a Z-Cull + // reconstruct because that would clear the Z-near of the Z-Cull which results in + // no trivial rejection for Z-fail stencil shadow rendering. + + const bool renderZPass = ( drawSurf->renderZFail == 0 ) || r_forceZPassStencilShadows.GetBool(); + + + if( renderZPass ) + { + // Z-pass + glStencilOpSeparate( GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR ); + glStencilOpSeparate( GL_BACK, GL_KEEP, GL_KEEP, GL_DECR ); + } + else if( r_useStencilShadowPreload.GetBool() ) + { + // preload + Z-pass + glStencilOpSeparate( GL_FRONT, GL_KEEP, GL_DECR, GL_DECR ); + glStencilOpSeparate( GL_BACK, GL_KEEP, GL_INCR, GL_INCR ); + } + else + { + // Z-fail + } + + + // get vertex buffer + const vertCacheHandle_t vbHandle = drawSurf->shadowCache; + idVertexBuffer* vertexBuffer; + if( vertexCache.CacheIsStatic( vbHandle ) ) + { + vertexBuffer = &vertexCache.staticData.vertexBuffer; + } + else + { + const uint64 frameNum = ( int )( vbHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK; + if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) + { + idLib::Warning( "RB_DrawElementsWithCounters, vertexBuffer == NULL" ); + continue; + } + vertexBuffer = &vertexCache.frameData[vertexCache.drawListNum].vertexBuffer; + } + const int vertOffset = ( int )( vbHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK; + + // get index buffer + const vertCacheHandle_t ibHandle = drawSurf->indexCache; + idIndexBuffer* indexBuffer; + if( vertexCache.CacheIsStatic( ibHandle ) ) + { + indexBuffer = &vertexCache.staticData.indexBuffer; + } + else + { + const uint64 frameNum = ( int )( ibHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK; + if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) + { + idLib::Warning( "RB_DrawElementsWithCounters, indexBuffer == NULL" ); + continue; + } + indexBuffer = &vertexCache.frameData[vertexCache.drawListNum].indexBuffer; + } + const uint64 indexOffset = ( int )( ibHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK; + + RENDERLOG_PRINTF( "Binding Buffers: %p %p\n", vertexBuffer, indexBuffer ); + + // RB: 64 bit fixes, changed GLuint to GLintptr + if( currentIndexBuffer != ( GLintptr )indexBuffer->GetAPIObject() || !r_useStateCaching.GetBool() ) + { + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ( GLintptr )indexBuffer->GetAPIObject() ); + currentIndexBuffer = ( GLintptr )indexBuffer->GetAPIObject(); + } + + if( drawSurf->jointCache ) + { + assert( renderProgManager.ShaderUsesJoints() ); + + idJointBuffer jointBuffer; + if( !vertexCache.GetJointBuffer( drawSurf->jointCache, &jointBuffer ) ) + { + idLib::Warning( "RB_DrawElementsWithCounters, jointBuffer == NULL" ); + continue; + } + assert( ( jointBuffer.GetOffset() & ( glConfig.uniformBufferOffsetAlignment - 1 ) ) == 0 ); + + const GLintptr ubo = reinterpret_cast< GLintptr >( jointBuffer.GetAPIObject() ); + glBindBufferRange( GL_UNIFORM_BUFFER, 0, ubo, jointBuffer.GetOffset(), jointBuffer.GetNumJoints() * sizeof( idJointMat ) ); + + if( ( vertexLayout != LAYOUT_DRAW_SHADOW_VERT_SKINNED ) || ( currentVertexBuffer != ( GLintptr )vertexBuffer->GetAPIObject() ) || !r_useStateCaching.GetBool() ) + { + glBindBuffer( GL_ARRAY_BUFFER, ( GLintptr )vertexBuffer->GetAPIObject() ); + currentVertexBuffer = ( GLintptr )vertexBuffer->GetAPIObject(); + + glEnableVertexAttribArray( PC_ATTRIB_INDEX_VERTEX ); + glDisableVertexAttribArray( PC_ATTRIB_INDEX_NORMAL ); + glEnableVertexAttribArray( PC_ATTRIB_INDEX_COLOR ); + glEnableVertexAttribArray( PC_ATTRIB_INDEX_COLOR2 ); + glDisableVertexAttribArray( PC_ATTRIB_INDEX_ST ); + glDisableVertexAttribArray( PC_ATTRIB_INDEX_TANGENT ); + +#if defined(USE_GLES2) || defined(USE_GLES3) + glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 4, GL_FLOAT, GL_FALSE, sizeof( idShadowVertSkinned ), ( void* )( vertOffset + SHADOWVERTSKINNED_XYZW_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), ( void* )( vertOffset + SHADOWVERTSKINNED_COLOR_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), ( void* )( vertOffset + SHADOWVERTSKINNED_COLOR2_OFFSET ) ); +#else + glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 4, GL_FLOAT, GL_FALSE, sizeof( idShadowVertSkinned ), ( void* )( SHADOWVERTSKINNED_XYZW_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), ( void* )( SHADOWVERTSKINNED_COLOR_OFFSET ) ); + glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), ( void* )( SHADOWVERTSKINNED_COLOR2_OFFSET ) ); +#endif + + vertexLayout = LAYOUT_DRAW_SHADOW_VERT_SKINNED; + } + + } + else + { + if( ( vertexLayout != LAYOUT_DRAW_SHADOW_VERT ) || ( currentVertexBuffer != ( GLintptr )vertexBuffer->GetAPIObject() ) || !r_useStateCaching.GetBool() ) + { + glBindBuffer( GL_ARRAY_BUFFER, ( GLintptr )vertexBuffer->GetAPIObject() ); + currentVertexBuffer = ( GLintptr )vertexBuffer->GetAPIObject(); + + glEnableVertexAttribArray( PC_ATTRIB_INDEX_VERTEX ); + glDisableVertexAttribArray( PC_ATTRIB_INDEX_NORMAL ); + glDisableVertexAttribArray( PC_ATTRIB_INDEX_COLOR ); + glDisableVertexAttribArray( PC_ATTRIB_INDEX_COLOR2 ); + glDisableVertexAttribArray( PC_ATTRIB_INDEX_ST ); + glDisableVertexAttribArray( PC_ATTRIB_INDEX_TANGENT ); + +#if defined(USE_GLES2) || defined(USE_GLES3) + glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 4, GL_FLOAT, GL_FALSE, sizeof( idShadowVert ), ( void* )( vertOffset + SHADOWVERT_XYZW_OFFSET ) ); +#else + glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 4, GL_FLOAT, GL_FALSE, sizeof( idShadowVert ), ( void* )( SHADOWVERT_XYZW_OFFSET ) ); +#endif + + vertexLayout = LAYOUT_DRAW_SHADOW_VERT; + } + } + // RB end + + renderProgManager.CommitUniforms(); + + if( drawSurf->jointCache ) + { +#if defined(USE_GLES3) //defined(USE_GLES2) + glDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset ); +#else + glDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset, vertOffset / sizeof( idShadowVertSkinned ) ); +#endif + } + else + { +#if defined(USE_GLES3) + glDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset ); +#else + glDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset, vertOffset / sizeof( idShadowVert ) ); +#endif + } + + // RB: added stats + pc.c_shadowElements++; + pc.c_shadowIndexes += drawSurf->numIndexes; + // RB end + + if( !renderZPass && r_useStencilShadowPreload.GetBool() ) + { + // render again with Z-pass + glStencilOpSeparate( GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR ); + glStencilOpSeparate( GL_BACK, GL_KEEP, GL_KEEP, GL_DECR ); + + if( drawSurf->jointCache ) + { +#if defined(USE_GLES3) + glDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset ); +#else + glDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset, vertOffset / sizeof( idShadowVertSkinned ) ); +#endif + } + else + { +#if defined(USE_GLES3) + glDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset ); +#else + glDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset, vertOffset / sizeof( idShadowVert ) ); +#endif + } + + // RB: added stats + pc.c_shadowElements++; + pc.c_shadowIndexes += drawSurf->numIndexes; + // RB end + } + } + + // cleanup the shadow specific rendering state + + GL_Cull( CT_FRONT_SIDED ); + + // reset depth bounds + if( r_useShadowDepthBounds.GetBool() ) + { + if( r_useLightDepthBounds.GetBool() ) + { + GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax ); + } + else + { + GL_DepthBoundsTest( 0.0f, 0.0f ); + } + } +} + +/* +================== +idRenderBackend::StencilSelectLight + +Deform the zeroOneCubeModel to exactly cover the light volume. Render the deformed cube model to the stencil buffer in +such a way that only fragments that are directly visible and contained within the volume will be written creating a +mask to be used by the following stencil shadow and draw interaction passes. +================== +*/ +void idRenderBackend::StencilSelectLight( const viewLight_t* vLight ) +{ + renderLog.OpenBlock( "Stencil Select" ); + + // enable the light scissor + if( !currentScissor.Equals( vLight->scissorRect ) && r_useScissor.GetBool() ) + { + GL_Scissor( viewDef->viewport.x1 + vLight->scissorRect.x1, + viewDef->viewport.y1 + vLight->scissorRect.y1, + vLight->scissorRect.x2 + 1 - vLight->scissorRect.x1, + vLight->scissorRect.y2 + 1 - vLight->scissorRect.y1 ); + + currentScissor = vLight->scissorRect; + } + + // clear stencil buffer to 0 (not drawable) + uint64 glStateMinusStencil = GL_GetCurrentStateMinusStencil(); + GL_State( glStateMinusStencil | GLS_STENCIL_FUNC_ALWAYS | GLS_STENCIL_MAKE_REF( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK( STENCIL_SHADOW_MASK_VALUE ) ); // make sure stencil mask passes for the clear + GL_Clear( false, false, true, 0, 0.0f, 0.0f, 0.0f, 0.0f, false ); // clear to 0 for stencil select + + // set the depthbounds + GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax ); + + + GL_State( GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS | GLS_STENCIL_FUNC_ALWAYS | GLS_STENCIL_MAKE_REF( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK( STENCIL_SHADOW_MASK_VALUE ) ); + GL_Cull( CT_TWO_SIDED ); + + renderProgManager.BindShader_Depth(); + + // set the matrix for deforming the 'zeroOneCubeModel' into the frustum to exactly cover the light volume + idRenderMatrix invProjectMVPMatrix; + idRenderMatrix::Multiply( viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix ); + RB_SetMVP( invProjectMVPMatrix ); + + // two-sided stencil test + glStencilOpSeparate( GL_FRONT, GL_KEEP, GL_REPLACE, GL_ZERO ); + glStencilOpSeparate( GL_BACK, GL_KEEP, GL_ZERO, GL_REPLACE ); + + DrawElementsWithCounters( &zeroOneCubeSurface ); + + // reset stencil state + + GL_Cull( CT_FRONT_SIDED ); + + renderProgManager.Unbind(); + + + // unset the depthbounds + GL_DepthBoundsTest( 0.0f, 0.0f ); + + renderLog.CloseBlock(); +} + +/* +============================================================================================== + +SHADOW MAPS RENDERING + +============================================================================================== +*/ + +/* +same as D3DXMatrixOrthoOffCenterRH + +http://msdn.microsoft.com/en-us/library/bb205348(VS.85).aspx +*/ +static void MatrixOrthogonalProjectionRH( float m[16], float left, float right, float bottom, float top, float zNear, float zFar ) +{ + m[0] = 2 / ( right - left ); + m[4] = 0; + m[8] = 0; + m[12] = ( left + right ) / ( left - right ); + m[1] = 0; + m[5] = 2 / ( top - bottom ); + m[9] = 0; + m[13] = ( top + bottom ) / ( bottom - top ); + m[2] = 0; + m[6] = 0; + m[10] = 1 / ( zNear - zFar ); + m[14] = zNear / ( zNear - zFar ); + m[3] = 0; + m[7] = 0; + m[11] = 0; + m[15] = 1; +} + +void MatrixCrop( float m[16], const idVec3 mins, const idVec3 maxs ) +{ + float scaleX, scaleY, scaleZ; + float offsetX, offsetY, offsetZ; + + scaleX = 2.0f / ( maxs[0] - mins[0] ); + scaleY = 2.0f / ( maxs[1] - mins[1] ); + + offsetX = -0.5f * ( maxs[0] + mins[0] ) * scaleX; + offsetY = -0.5f * ( maxs[1] + mins[1] ) * scaleY; + + scaleZ = 1.0f / ( maxs[2] - mins[2] ); + offsetZ = -mins[2] * scaleZ; + + m[ 0] = scaleX; + m[ 4] = 0; + m[ 8] = 0; + m[12] = offsetX; + m[ 1] = 0; + m[ 5] = scaleY; + m[ 9] = 0; + m[13] = offsetY; + m[ 2] = 0; + m[ 6] = 0; + m[10] = scaleZ; + m[14] = offsetZ; + m[ 3] = 0; + m[ 7] = 0; + m[11] = 0; + m[15] = 1; +} + +void MatrixLookAtRH( float m[16], const idVec3& eye, const idVec3& dir, const idVec3& up ) +{ + idVec3 dirN; + idVec3 upN; + idVec3 sideN; + + sideN = dir.Cross( up ); + sideN.Normalize(); + + upN = sideN.Cross( dir ); + upN.Normalize(); + + dirN = dir; + dirN.Normalize(); + + m[ 0] = sideN[0]; + m[ 4] = sideN[1]; + m[ 8] = sideN[2]; + m[12] = -( sideN * eye ); + m[ 1] = upN[0]; + m[ 5] = upN[1]; + m[ 9] = upN[2]; + m[13] = -( upN * eye ); + m[ 2] = -dirN[0]; + m[ 6] = -dirN[1]; + m[10] = -dirN[2]; + m[14] = ( dirN * eye ); + m[ 3] = 0; + m[ 7] = 0; + m[11] = 0; + m[15] = 1; +} + +/* +===================== +idRenderBackend::ShadowMapPass +===================== +*/ +void idRenderBackend::ShadowMapPass( const drawSurf_t* drawSurfs, const viewLight_t* vLight, int side ) +{ + if( r_skipShadows.GetBool() ) + { + return; + } + + if( drawSurfs == NULL ) + { + return; + } + + RENDERLOG_PRINTF( "---------- RB_ShadowMapPass( side = %i ) ----------\n", side ); + + renderProgManager.BindShader_Depth(); + + GL_SelectTexture( 0 ); + + uint64 glState = 0; + + // the actual stencil func will be set in the draw code, but we need to make sure it isn't + // disabled here, and that the value will get reset for the interactions without looking + // like a no-change-required + GL_State( glState | GLS_POLYGON_OFFSET ); + + switch( r_shadowMapOccluderFacing.GetInteger() ) + { + case 0: + GL_Cull( CT_FRONT_SIDED ); + GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat(), r_shadowMapPolygonOffset.GetFloat() ); + break; + + case 1: + GL_Cull( CT_BACK_SIDED ); + GL_PolygonOffset( -r_shadowMapPolygonFactor.GetFloat(), -r_shadowMapPolygonOffset.GetFloat() ); + break; + + default: + GL_Cull( CT_TWO_SIDED ); + GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat(), r_shadowMapPolygonOffset.GetFloat() ); + break; + } + + idRenderMatrix lightProjectionRenderMatrix; + idRenderMatrix lightViewRenderMatrix; + + + if( vLight->parallel && side >= 0 ) + { + assert( side >= 0 && side < 6 ); + + // original light direction is from surface to light origin + idVec3 lightDir = -vLight->lightCenter; + if( lightDir.Normalize() == 0.0f ) + { + lightDir[2] = -1.0f; + } + + idMat3 rotation = lightDir.ToMat3(); + //idAngles angles = lightDir.ToAngles(); + //idMat3 rotation = angles.ToMat3(); + + const idVec3 viewDir = viewDef->renderView.viewaxis[0]; + const idVec3 viewPos = viewDef->renderView.vieworg; + +#if 1 + idRenderMatrix::CreateViewMatrix( viewDef->renderView.vieworg, rotation, lightViewRenderMatrix ); +#else + float lightViewMatrix[16]; + MatrixLookAtRH( lightViewMatrix, viewPos, lightDir, viewDir ); + idRenderMatrix::Transpose( *( idRenderMatrix* )lightViewMatrix, lightViewRenderMatrix ); +#endif + + idBounds lightBounds; + lightBounds.Clear(); + + ALIGNTYPE16 frustumCorners_t corners; + idRenderMatrix::GetFrustumCorners( corners, vLight->inverseBaseLightProject, bounds_zeroOneCube ); + + idVec4 point, transf; + for( int j = 0; j < 8; j++ ) + { + point[0] = corners.x[j]; + point[1] = corners.y[j]; + point[2] = corners.z[j]; + point[3] = 1; + + lightViewRenderMatrix.TransformPoint( point, transf ); + transf[0] /= transf[3]; + transf[1] /= transf[3]; + transf[2] /= transf[3]; + + lightBounds.AddPoint( transf.ToVec3() ); + } + + float lightProjectionMatrix[16]; + MatrixOrthogonalProjectionRH( lightProjectionMatrix, lightBounds[0][0], lightBounds[1][0], lightBounds[0][1], lightBounds[1][1], -lightBounds[1][2], -lightBounds[0][2] ); + idRenderMatrix::Transpose( *( idRenderMatrix* )lightProjectionMatrix, lightProjectionRenderMatrix ); + + + // 'frustumMVP' goes from global space -> camera local space -> camera projective space + // invert the MVP projection so we can deform zero-to-one cubes into the frustum pyramid shape and calculate global bounds + + idRenderMatrix splitFrustumInverse; + if( !idRenderMatrix::Inverse( viewDef->frustumMVPs[FRUSTUM_CASCADE1 + side], splitFrustumInverse ) ) + { + idLib::Warning( "splitFrustumMVP invert failed" ); + } + + // splitFrustumCorners in global space + ALIGNTYPE16 frustumCorners_t splitFrustumCorners; + idRenderMatrix::GetFrustumCorners( splitFrustumCorners, splitFrustumInverse, bounds_unitCube ); + +#if 0 + idBounds splitFrustumBounds; + splitFrustumBounds.Clear(); + for( int j = 0; j < 8; j++ ) + { + point[0] = splitFrustumCorners.x[j]; + point[1] = splitFrustumCorners.y[j]; + point[2] = splitFrustumCorners.z[j]; + + splitFrustumBounds.AddPoint( point.ToVec3() ); + } + + idVec3 center = splitFrustumBounds.GetCenter(); + float radius = splitFrustumBounds.GetRadius( center ); + + //ALIGNTYPE16 frustumCorners_t splitFrustumCorners; + splitFrustumBounds[0] = idVec3( -radius, -radius, -radius ); + splitFrustumBounds[1] = idVec3( radius, radius, radius ); + splitFrustumBounds.TranslateSelf( viewPos ); + idVec3 splitFrustumCorners2[8]; + splitFrustumBounds.ToPoints( splitFrustumCorners2 ); + + for( int j = 0; j < 8; j++ ) + { + splitFrustumCorners.x[j] = splitFrustumCorners2[j].x; + splitFrustumCorners.y[j] = splitFrustumCorners2[j].y; + splitFrustumCorners.z[j] = splitFrustumCorners2[j].z; + } +#endif + + + idRenderMatrix lightViewProjectionRenderMatrix; + idRenderMatrix::Multiply( lightProjectionRenderMatrix, lightViewRenderMatrix, lightViewProjectionRenderMatrix ); + + // find the bounding box of the current split in the light's clip space + idBounds cropBounds; + cropBounds.Clear(); + for( int j = 0; j < 8; j++ ) + { + point[0] = splitFrustumCorners.x[j]; + point[1] = splitFrustumCorners.y[j]; + point[2] = splitFrustumCorners.z[j]; + point[3] = 1; + + lightViewRenderMatrix.TransformPoint( point, transf ); + transf[0] /= transf[3]; + transf[1] /= transf[3]; + transf[2] /= transf[3]; + + cropBounds.AddPoint( transf.ToVec3() ); + } + + // don't let the frustum AABB be bigger than the light AABB + if( cropBounds[0][0] < lightBounds[0][0] ) + { + cropBounds[0][0] = lightBounds[0][0]; + } + + if( cropBounds[0][1] < lightBounds[0][1] ) + { + cropBounds[0][1] = lightBounds[0][1]; + } + + if( cropBounds[1][0] > lightBounds[1][0] ) + { + cropBounds[1][0] = lightBounds[1][0]; + } + + if( cropBounds[1][1] > lightBounds[1][1] ) + { + cropBounds[1][1] = lightBounds[1][1]; + } + + cropBounds[0][2] = lightBounds[0][2]; + cropBounds[1][2] = lightBounds[1][2]; + + //float cropMatrix[16]; + //MatrixCrop(cropMatrix, cropBounds[0], cropBounds[1]); + + //idRenderMatrix cropRenderMatrix; + //idRenderMatrix::Transpose( *( idRenderMatrix* )cropMatrix, cropRenderMatrix ); + + //idRenderMatrix tmp = lightProjectionRenderMatrix; + //idRenderMatrix::Multiply( cropRenderMatrix, tmp, lightProjectionRenderMatrix ); + + MatrixOrthogonalProjectionRH( lightProjectionMatrix, cropBounds[0][0], cropBounds[1][0], cropBounds[0][1], cropBounds[1][1], -cropBounds[1][2], -cropBounds[0][2] ); + idRenderMatrix::Transpose( *( idRenderMatrix* )lightProjectionMatrix, lightProjectionRenderMatrix ); + + shadowV[side] = lightViewRenderMatrix; + shadowP[side] = lightProjectionRenderMatrix; + } + else if( vLight->pointLight && side >= 0 ) + { + assert( side >= 0 && side < 6 ); + + // FIXME OPTIMIZE no memset + + float viewMatrix[16]; + + idVec3 vec; + idVec3 origin = vLight->globalLightOrigin; + + // side of a point light + memset( viewMatrix, 0, sizeof( viewMatrix ) ); + switch( side ) + { + case 0: + viewMatrix[0] = 1; + viewMatrix[9] = 1; + viewMatrix[6] = -1; + break; + case 1: + viewMatrix[0] = -1; + viewMatrix[9] = -1; + viewMatrix[6] = -1; + break; + case 2: + viewMatrix[4] = 1; + viewMatrix[1] = -1; + viewMatrix[10] = 1; + break; + case 3: + viewMatrix[4] = -1; + viewMatrix[1] = -1; + viewMatrix[10] = -1; + break; + case 4: + viewMatrix[8] = 1; + viewMatrix[1] = -1; + viewMatrix[6] = -1; + break; + case 5: + viewMatrix[8] = -1; + viewMatrix[1] = 1; + viewMatrix[6] = -1; + break; + } + + viewMatrix[12] = -origin[0] * viewMatrix[0] + -origin[1] * viewMatrix[4] + -origin[2] * viewMatrix[8]; + viewMatrix[13] = -origin[0] * viewMatrix[1] + -origin[1] * viewMatrix[5] + -origin[2] * viewMatrix[9]; + viewMatrix[14] = -origin[0] * viewMatrix[2] + -origin[1] * viewMatrix[6] + -origin[2] * viewMatrix[10]; + + viewMatrix[3] = 0; + viewMatrix[7] = 0; + viewMatrix[11] = 0; + viewMatrix[15] = 1; + + // from world space to light origin, looking down the X axis + float unflippedLightViewMatrix[16]; + + // from world space to OpenGL view space, looking down the negative Z axis + float lightViewMatrix[16]; + + static float s_flipMatrix[16] = + { + // convert from our coordinate system (looking down X) + // to OpenGL's coordinate system (looking down -Z) + 0, 0, -1, 0, + -1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 1 + }; + + memcpy( unflippedLightViewMatrix, viewMatrix, sizeof( unflippedLightViewMatrix ) ); + R_MatrixMultiply( viewMatrix, s_flipMatrix, lightViewMatrix ); + + idRenderMatrix::Transpose( *( idRenderMatrix* )lightViewMatrix, lightViewRenderMatrix ); + + // set up 90 degree projection matrix + const float zNear = 4; + const float fov = r_shadowMapFrustumFOV.GetFloat(); + + float ymax = zNear * tan( fov * idMath::PI / 360.0f ); + float ymin = -ymax; + + float xmax = zNear * tan( fov * idMath::PI / 360.0f ); + float xmin = -xmax; + + const float width = xmax - xmin; + const float height = ymax - ymin; + + // from OpenGL view space to OpenGL NDC ( -1 : 1 in XYZ ) + float lightProjectionMatrix[16]; + + lightProjectionMatrix[0 * 4 + 0] = 2.0f * zNear / width; + lightProjectionMatrix[1 * 4 + 0] = 0.0f; + lightProjectionMatrix[2 * 4 + 0] = ( xmax + xmin ) / width; // normally 0 + lightProjectionMatrix[3 * 4 + 0] = 0.0f; + + lightProjectionMatrix[0 * 4 + 1] = 0.0f; + lightProjectionMatrix[1 * 4 + 1] = 2.0f * zNear / height; + lightProjectionMatrix[2 * 4 + 1] = ( ymax + ymin ) / height; // normally 0 + lightProjectionMatrix[3 * 4 + 1] = 0.0f; + + // this is the far-plane-at-infinity formulation, and + // crunches the Z range slightly so w=0 vertexes do not + // rasterize right at the wraparound point + lightProjectionMatrix[0 * 4 + 2] = 0.0f; + lightProjectionMatrix[1 * 4 + 2] = 0.0f; + lightProjectionMatrix[2 * 4 + 2] = -0.999f; // adjust value to prevent imprecision issues + lightProjectionMatrix[3 * 4 + 2] = -2.0f * zNear; + + lightProjectionMatrix[0 * 4 + 3] = 0.0f; + lightProjectionMatrix[1 * 4 + 3] = 0.0f; + lightProjectionMatrix[2 * 4 + 3] = -1.0f; + lightProjectionMatrix[3 * 4 + 3] = 0.0f; + + idRenderMatrix::Transpose( *( idRenderMatrix* )lightProjectionMatrix, lightProjectionRenderMatrix ); + + shadowV[side] = lightViewRenderMatrix; + shadowP[side] = lightProjectionRenderMatrix; + } + else + { + lightViewRenderMatrix.Identity(); + lightProjectionRenderMatrix = vLight->baseLightProject; + + shadowV[0] = lightViewRenderMatrix; + shadowP[0] = lightProjectionRenderMatrix; + } + + globalFramebuffers.shadowFBO[vLight->shadowLOD]->Bind(); + + if( side < 0 ) + { + globalFramebuffers.shadowFBO[vLight->shadowLOD]->AttachImageDepthLayer( globalImages->shadowImage[vLight->shadowLOD], 0 ); + } + else + { + globalFramebuffers.shadowFBO[vLight->shadowLOD]->AttachImageDepthLayer( globalImages->shadowImage[vLight->shadowLOD], side ); + } + + globalFramebuffers.shadowFBO[vLight->shadowLOD]->Check(); + + GL_ViewportAndScissor( 0, 0, shadowMapResolutions[vLight->shadowLOD], shadowMapResolutions[vLight->shadowLOD] ); + + glClear( GL_DEPTH_BUFFER_BIT ); + + // process the chain of shadows with the current rendering state + currentSpace = NULL; + + for( const drawSurf_t* drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight ) + { + +#if 1 + // make sure the shadow occluder geometry is done + if( drawSurf->shadowVolumeState != SHADOWVOLUME_DONE ) + { + assert( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED || drawSurf->shadowVolumeState == SHADOWVOLUME_DONE ); + + uint64 start = Sys_Microseconds(); + while( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED ) + { + Sys_Yield(); + } + uint64 end = Sys_Microseconds(); + + pc.shadowMicroSec += end - start; + } +#endif + + if( drawSurf->numIndexes == 0 ) + { + continue; // a job may have created an empty shadow geometry + } + + if( drawSurf->space != currentSpace ) + { + idRenderMatrix modelRenderMatrix; + idRenderMatrix::Transpose( *( idRenderMatrix* )drawSurf->space->modelMatrix, modelRenderMatrix ); + + idRenderMatrix modelToLightRenderMatrix; + idRenderMatrix::Multiply( lightViewRenderMatrix, modelRenderMatrix, modelToLightRenderMatrix ); + + idRenderMatrix clipMVP; + idRenderMatrix::Multiply( lightProjectionRenderMatrix, modelToLightRenderMatrix, clipMVP ); + + if( vLight->parallel ) + { + idRenderMatrix MVP; + idRenderMatrix::Multiply( renderMatrix_clipSpaceToWindowSpace, clipMVP, MVP ); + + RB_SetMVP( clipMVP ); + } + else if( side < 0 ) + { + // from OpenGL view space to OpenGL NDC ( -1 : 1 in XYZ ) + idRenderMatrix MVP; + idRenderMatrix::Multiply( renderMatrix_windowSpaceToClipSpace, clipMVP, MVP ); + + RB_SetMVP( MVP ); + } + else + { + RB_SetMVP( clipMVP ); + } + + // set the local light position to allow the vertex program to project the shadow volume end cap to infinity + /* + idVec4 localLight( 0.0f ); + R_GlobalPointToLocal( drawSurf->space->modelMatrix, vLight->globalLightOrigin, localLight.ToVec3() ); + SetVertexParm( RENDERPARM_LOCALLIGHTORIGIN, localLight.ToFloatPtr() ); + */ + + currentSpace = drawSurf->space; + } + + bool didDraw = false; + + const idMaterial* shader = drawSurf->material; + + // get the expressions for conditionals / color / texcoords + const float* regs = drawSurf->shaderRegisters; + idVec4 color( 0, 0, 0, 1 ); + + uint64 surfGLState = 0; + + // set polygon offset if necessary + if( shader && shader->TestMaterialFlag( MF_POLYGONOFFSET ) ) + { + surfGLState |= GLS_POLYGON_OFFSET; + GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); + } + +#if 1 + if( shader && shader->Coverage() == MC_PERFORATED ) + { + // perforated surfaces may have multiple alpha tested stages + for( int stage = 0; stage < shader->GetNumStages(); stage++ ) + { + const shaderStage_t* pStage = shader->GetStage( stage ); + + if( !pStage->hasAlphaTest ) + { + continue; + } + + // check the stage enable condition + if( regs[ pStage->conditionRegister ] == 0 ) + { + continue; + } + + // if we at least tried to draw an alpha tested stage, + // we won't draw the opaque surface + didDraw = true; + + // set the alpha modulate + color[3] = regs[ pStage->color.registers[3] ]; + + // skip the entire stage if alpha would be black + if( color[3] <= 0.0f ) + { + continue; + } + + uint64 stageGLState = surfGLState; + + // set privatePolygonOffset if necessary + if( pStage->privatePolygonOffset ) + { + GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * pStage->privatePolygonOffset ); + stageGLState |= GLS_POLYGON_OFFSET; + } + + GL_Color( color ); + +#ifdef USE_CORE_PROFILE + GL_State( stageGLState ); + idVec4 alphaTestValue( regs[ pStage->alphaTestRegister ] ); + SetFragmentParm( RENDERPARM_ALPHA_TEST, alphaTestValue.ToFloatPtr() ); +#else + GL_State( stageGLState | GLS_ALPHATEST_FUNC_GREATER | GLS_ALPHATEST_MAKE_REF( idMath::Ftob( 255.0f * regs[ pStage->alphaTestRegister ] ) ) ); +#endif + + if( drawSurf->jointCache ) + { + renderProgManager.BindShader_TextureVertexColorSkinned(); + } + else + { + renderProgManager.BindShader_TextureVertexColor(); + } + + RB_SetVertexColorParms( SVC_IGNORE ); + + // bind the texture + GL_SelectTexture( 0 ); + pStage->texture.image->Bind(); + + // set texture matrix and texGens + PrepareStageTexturing( pStage, drawSurf ); + + // must render with less-equal for Z-Cull to work properly + assert( ( GL_GetCurrentState() & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS ); + + // draw it + DrawElementsWithCounters( drawSurf ); + + // clean up + FinishStageTexturing( pStage, drawSurf ); + + // unset privatePolygonOffset if necessary + if( pStage->privatePolygonOffset ) + { + GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); + } + } + } +#endif + + if( !didDraw ) + { + if( drawSurf->jointCache ) + { + renderProgManager.BindShader_DepthSkinned(); + } + else + { + renderProgManager.BindShader_Depth(); + } + + DrawElementsWithCounters( drawSurf ); + } + } + + // cleanup the shadow specific rendering state + if( r_useHDR.GetBool() ) //&& !backEnd.viewDef->is2Dgui ) + { + globalFramebuffers.hdrFBO->Bind(); + } + else + { + Framebuffer::Unbind(); + } + renderProgManager.Unbind(); + + GL_State( GLS_DEFAULT ); + GL_Cull( CT_FRONT_SIDED ); + +#ifdef USE_CORE_PROFILE + SetFragmentParm( RENDERPARM_ALPHA_TEST, vec4_zero.ToFloatPtr() ); +#endif +} + +/* +============================================================================================== + +DRAW INTERACTIONS + +============================================================================================== +*/ +/* +================== +idRenderBackend::DrawInteractions +================== +*/ +void idRenderBackend::DrawInteractions( const viewDef_t* _viewDef ) +{ + if( r_skipInteractions.GetBool() ) + { + return; + } + + renderLog.OpenMainBlock( MRB_DRAW_INTERACTIONS ); + renderLog.OpenBlock( "RB_DrawInteractions" ); + + GL_SelectTexture( 0 ); + + + const bool useLightDepthBounds = r_useLightDepthBounds.GetBool() && !r_useShadowMapping.GetBool(); + + // + // for each light, perform shadowing and adding + // + for( const viewLight_t* vLight = viewDef->viewLights; vLight != NULL; vLight = vLight->next ) + { + // do fogging later + if( vLight->lightShader->IsFogLight() ) + { + continue; + } + if( vLight->lightShader->IsBlendLight() ) + { + continue; + } + + if( vLight->localInteractions == NULL && vLight->globalInteractions == NULL && vLight->translucentInteractions == NULL ) + { + continue; + } + + const idMaterial* lightShader = vLight->lightShader; + renderLog.OpenBlock( lightShader->GetName() ); + + // set the depth bounds for the whole light + if( useLightDepthBounds ) + { + GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax ); + } + + // RB: shadow mapping + if( r_useShadowMapping.GetBool() ) + { + int side, sideStop; + + if( vLight->parallel ) + { + side = 0; + sideStop = r_shadowMapSplits.GetInteger() + 1; + } + else if( vLight->pointLight ) + { + if( r_shadowMapSingleSide.GetInteger() != -1 ) + { + side = r_shadowMapSingleSide.GetInteger(); + sideStop = side + 1; + } + else + { + side = 0; + sideStop = 6; + } + } + else + { + side = -1; + sideStop = 0; + } + + for( ; side < sideStop ; side++ ) + { + ShadowMapPass( vLight->globalShadows, vLight, side ); + } + + // go back from light view to default camera view + ResetViewportAndScissorToDefaultCamera( _viewDef ); + + if( vLight->localInteractions != NULL ) + { + renderLog.OpenBlock( "Local Light Interactions" ); + RenderInteractions( vLight->localInteractions, vLight, GLS_DEPTHFUNC_EQUAL, false, useLightDepthBounds ); + renderLog.CloseBlock(); + } + + if( vLight->globalInteractions != NULL ) + { + renderLog.OpenBlock( "Global Light Interactions" ); + RenderInteractions( vLight->globalInteractions, vLight, GLS_DEPTHFUNC_EQUAL, false, useLightDepthBounds ); + renderLog.CloseBlock(); + } + } + else + { + // only need to clear the stencil buffer and perform stencil testing if there are shadows + const bool performStencilTest = ( vLight->globalShadows != NULL || vLight->localShadows != NULL ) && !r_useShadowMapping.GetBool(); + + // mirror flips the sense of the stencil select, and I don't want to risk accidentally breaking it + // in the normal case, so simply disable the stencil select in the mirror case + const bool useLightStencilSelect = ( r_useLightStencilSelect.GetBool() && viewDef->isMirror == false ); + + if( performStencilTest ) + { + if( useLightStencilSelect ) + { + // write a stencil mask for the visible light bounds to hi-stencil + StencilSelectLight( vLight ); + } + else + { + // always clear whole S-Cull tiles + idScreenRect rect; + rect.x1 = ( vLight->scissorRect.x1 + 0 ) & ~15; + rect.y1 = ( vLight->scissorRect.y1 + 0 ) & ~15; + rect.x2 = ( vLight->scissorRect.x2 + 15 ) & ~15; + rect.y2 = ( vLight->scissorRect.y2 + 15 ) & ~15; + + if( !currentScissor.Equals( rect ) && r_useScissor.GetBool() ) + { + GL_Scissor( viewDef->viewport.x1 + rect.x1, + viewDef->viewport.y1 + rect.y1, + rect.x2 + 1 - rect.x1, + rect.y2 + 1 - rect.y1 ); + + currentScissor = rect; + } + GL_State( GLS_DEFAULT ); // make sure stencil mask passes for the clear + GL_Clear( false, false, true, STENCIL_SHADOW_TEST_VALUE, 0.0f, 0.0f, 0.0f, 0.0f, false ); + } + } + + if( vLight->globalShadows != NULL ) + { + renderLog.OpenBlock( "Global Light Shadows" ); + StencilShadowPass( vLight->globalShadows, vLight ); + renderLog.CloseBlock(); + } + + if( vLight->localInteractions != NULL ) + { + renderLog.OpenBlock( "Local Light Interactions" ); + RenderInteractions( vLight->localInteractions, vLight, GLS_DEPTHFUNC_EQUAL, performStencilTest, useLightDepthBounds ); + renderLog.CloseBlock(); + } + + if( vLight->localShadows != NULL ) + { + renderLog.OpenBlock( "Local Light Shadows" ); + StencilShadowPass( vLight->localShadows, vLight ); + renderLog.CloseBlock(); + } + + if( vLight->globalInteractions != NULL ) + { + renderLog.OpenBlock( "Global Light Interactions" ); + RenderInteractions( vLight->globalInteractions, vLight, GLS_DEPTHFUNC_EQUAL, performStencilTest, useLightDepthBounds ); + renderLog.CloseBlock(); + } + } + // RB end + + if( vLight->translucentInteractions != NULL && !r_skipTranslucent.GetBool() ) + { + renderLog.OpenBlock( "Translucent Interactions" ); + + // Disable the depth bounds test because translucent surfaces don't work with + // the depth bounds tests since they did not write depth during the depth pass. + if( useLightDepthBounds ) + { + GL_DepthBoundsTest( 0.0f, 0.0f ); + } + + // The depth buffer wasn't filled in for translucent surfaces, so they + // can never be constrained to perforated surfaces with the depthfunc equal. + + // Translucent surfaces do not receive shadows. This is a case where a + // shadow buffer solution would work but stencil shadows do not because + // stencil shadows only affect surfaces that contribute to the view depth + // buffer and translucent surfaces do not contribute to the view depth buffer. + + RenderInteractions( vLight->translucentInteractions, vLight, GLS_DEPTHFUNC_LESS, false, false ); + + renderLog.CloseBlock(); + } + + renderLog.CloseBlock(); + } + + // disable stencil shadow test + GL_State( GLS_DEFAULT ); + + // unbind texture units + GL_SelectTexture( 0 ); + + // reset depth bounds + if( useLightDepthBounds ) + { + GL_DepthBoundsTest( 0.0f, 0.0f ); + } + + renderLog.CloseBlock(); + renderLog.CloseMainBlock(); +} + +/* +============================================================================================= + +NON-INTERACTION SHADER PASSES + +============================================================================================= +*/ + +/* +===================== +idRenderBackend::DrawShaderPasses + +Draw non-light dependent passes + +If we are rendering Guis, the drawSurf_t::sort value is a depth offset that can +be multiplied by guiEye for polarity and screenSeparation for scale. +===================== +*/ +int idRenderBackend::DrawShaderPasses( const drawSurf_t* const* const drawSurfs, const int numDrawSurfs, + const float guiStereoScreenOffset, const int stereoEye ) +{ + // only obey skipAmbient if we are rendering a view + if( viewDef->viewEntitys && r_skipAmbient.GetBool() ) + { + return numDrawSurfs; + } + + renderLog.OpenBlock( "RB_DrawShaderPasses" ); + + GL_SelectTexture( 0 ); + + currentSpace = ( const viewEntity_t* )1; // using NULL makes /analyze think surf->space needs to be checked... + float currentGuiStereoOffset = 0.0f; + + int i = 0; + for( ; i < numDrawSurfs; i++ ) + { + const drawSurf_t* surf = drawSurfs[i]; + const idMaterial* shader = surf->material; + + if( !shader->HasAmbient() ) + { + continue; + } + + if( shader->IsPortalSky() ) + { + continue; + } + + // some deforms may disable themselves by setting numIndexes = 0 + if( surf->numIndexes == 0 ) + { + continue; + } + + if( shader->SuppressInSubview() ) + { + continue; + } + + if( viewDef->isXraySubview && surf->space->entityDef ) + { + if( surf->space->entityDef->parms.xrayIndex != 2 ) + { + continue; + } + } + + // we need to draw the post process shaders after we have drawn the fog lights + if( shader->GetSort() >= SS_POST_PROCESS && !currentRenderCopied ) + { + break; + } + + // if we are rendering a 3D view and the surface's eye index doesn't match + // the current view's eye index then we skip the surface + // if the stereoEye value of a surface is 0 then we need to draw it for both eyes. + const int shaderStereoEye = shader->GetStereoEye(); + const bool isEyeValid = stereoRender_swapEyes.GetBool() ? ( shaderStereoEye == stereoEye ) : ( shaderStereoEye != stereoEye ); + if( ( stereoEye != 0 ) && ( shaderStereoEye != 0 ) && ( isEyeValid ) ) + { + continue; + } + + renderLog.OpenBlock( shader->GetName() ); + + // determine the stereoDepth offset + // guiStereoScreenOffset will always be zero for 3D views, so the != + // check will never force an update due to the current sort value. + const float thisGuiStereoOffset = guiStereoScreenOffset * surf->sort; + + // change the matrix and other space related vars if needed + if( surf->space != currentSpace || thisGuiStereoOffset != currentGuiStereoOffset ) + { + currentSpace = surf->space; + currentGuiStereoOffset = thisGuiStereoOffset; + + const viewEntity_t* space = currentSpace; + + if( guiStereoScreenOffset != 0.0f ) + { + RB_SetMVPWithStereoOffset( space->mvp, currentGuiStereoOffset ); + } + else + { + RB_SetMVP( space->mvp ); + } + + // set eye position in local space + idVec4 localViewOrigin( 1.0f ); + R_GlobalPointToLocal( space->modelMatrix, viewDef->renderView.vieworg, localViewOrigin.ToVec3() ); + SetVertexParm( RENDERPARM_LOCALVIEWORIGIN, localViewOrigin.ToFloatPtr() ); + + // set model Matrix + float modelMatrixTranspose[16]; + R_MatrixTranspose( space->modelMatrix, modelMatrixTranspose ); + SetVertexParms( RENDERPARM_MODELMATRIX_X, modelMatrixTranspose, 4 ); + + // Set ModelView Matrix + float modelViewMatrixTranspose[16]; + R_MatrixTranspose( space->modelViewMatrix, modelViewMatrixTranspose ); + SetVertexParms( RENDERPARM_MODELVIEWMATRIX_X, modelViewMatrixTranspose, 4 ); + } + + // change the scissor if needed + if( !currentScissor.Equals( surf->scissorRect ) && r_useScissor.GetBool() ) + { + GL_Scissor( viewDef->viewport.x1 + surf->scissorRect.x1, + viewDef->viewport.y1 + surf->scissorRect.y1, + surf->scissorRect.x2 + 1 - surf->scissorRect.x1, + surf->scissorRect.y2 + 1 - surf->scissorRect.y1 ); + + currentScissor = surf->scissorRect; + } + + // get the expressions for conditionals / color / texcoords + const float* regs = surf->shaderRegisters; + + // set face culling appropriately + if( surf->space->isGuiSurface ) + { + GL_Cull( CT_TWO_SIDED ); + } + else + { + GL_Cull( shader->GetCullType() ); + } + + uint64 surfGLState = surf->extraGLState; + + // set polygon offset if necessary + if( shader->TestMaterialFlag( MF_POLYGONOFFSET ) ) + { + GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); + surfGLState = GLS_POLYGON_OFFSET; + } + + for( int stage = 0; stage < shader->GetNumStages(); stage++ ) + { + const shaderStage_t* pStage = shader->GetStage( stage ); + + // check the enable condition + if( regs[ pStage->conditionRegister ] == 0 ) + { + continue; + } + + // skip the stages involved in lighting + if( pStage->lighting != SL_AMBIENT ) + { + continue; + } + + uint64 stageGLState = surfGLState; + if( ( surfGLState & GLS_OVERRIDE ) == 0 ) + { + stageGLState |= pStage->drawStateBits; + } + + // skip if the stage is ( GL_ZERO, GL_ONE ), which is used for some alpha masks + if( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE ) ) + { + continue; + } + + + // see if we are a new-style stage + newShaderStage_t* newStage = pStage->newStage; + if( newStage != NULL ) + { + //-------------------------- + // + // new style stages + // + //-------------------------- + if( r_skipNewAmbient.GetBool() ) + { + continue; + } + renderLog.OpenBlock( "New Shader Stage" ); + + GL_State( stageGLState ); + + // RB: CRITICAL BUGFIX: changed newStage->glslProgram to vertexProgram and fragmentProgram + // otherwise it will result in an out of bounds crash in RB_DrawElementsWithCounters + renderProgManager.BindShader( newStage->glslProgram, newStage->vertexProgram, newStage->fragmentProgram, false ); + // RB end + + for( int j = 0; j < newStage->numVertexParms; j++ ) + { + float parm[4]; + parm[0] = regs[ newStage->vertexParms[j][0] ]; + parm[1] = regs[ newStage->vertexParms[j][1] ]; + parm[2] = regs[ newStage->vertexParms[j][2] ]; + parm[3] = regs[ newStage->vertexParms[j][3] ]; + SetVertexParm( ( renderParm_t )( RENDERPARM_USER + j ), parm ); + } + + // set rpEnableSkinning if the shader has optional support for skinning + if( surf->jointCache && renderProgManager.ShaderHasOptionalSkinning() ) + { + const idVec4 skinningParm( 1.0f ); + SetVertexParm( RENDERPARM_ENABLE_SKINNING, skinningParm.ToFloatPtr() ); + } + + // bind texture units + for( int j = 0; j < newStage->numFragmentProgramImages; j++ ) + { + idImage* image = newStage->fragmentProgramImages[j]; + if( image != NULL ) + { + GL_SelectTexture( j ); + image->Bind(); + } + } + + // draw it + DrawElementsWithCounters( surf ); + + // clear rpEnableSkinning if it was set + if( surf->jointCache && renderProgManager.ShaderHasOptionalSkinning() ) + { + const idVec4 skinningParm( 0.0f ); + SetVertexParm( RENDERPARM_ENABLE_SKINNING, skinningParm.ToFloatPtr() ); + } + + GL_SelectTexture( 0 ); + renderProgManager.Unbind(); + + renderLog.CloseBlock(); + continue; + } + + //-------------------------- + // + // old style stages + // + //-------------------------- + + // set the color + idVec4 color; + color[0] = regs[ pStage->color.registers[0] ]; + color[1] = regs[ pStage->color.registers[1] ]; + color[2] = regs[ pStage->color.registers[2] ]; + color[3] = regs[ pStage->color.registers[3] ]; + + // skip the entire stage if an add would be black + if( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ) + && color[0] <= 0 && color[1] <= 0 && color[2] <= 0 ) + { + continue; + } + + // skip the entire stage if a blend would be completely transparent + if( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) + && color[3] <= 0 ) + { + continue; + } + + stageVertexColor_t svc = pStage->vertexColor; + + renderLog.OpenBlock( "Old Shader Stage" ); + GL_Color( color ); + + if( surf->space->isGuiSurface ) + { + // Force gui surfaces to always be SVC_MODULATE + svc = SVC_MODULATE; + + // use special shaders for bink cinematics + if( pStage->texture.cinematic ) + { + if( ( stageGLState & GLS_OVERRIDE ) != 0 ) + { + // This is a hack... Only SWF Guis set GLS_OVERRIDE + // Old style guis do not, and we don't want them to use the new GUI renederProg + renderProgManager.BindShader_TextureVertexColor_sRGB(); + } + else + { + renderProgManager.BindShader_TextureVertexColor(); + } + } + else + { + if( ( stageGLState & GLS_OVERRIDE ) != 0 ) + { + // This is a hack... Only SWF Guis set GLS_OVERRIDE + // Old style guis do not, and we don't want them to use the new GUI renderProg + renderProgManager.BindShader_GUI(); + } + else + { + if( surf->jointCache ) + { + renderProgManager.BindShader_TextureVertexColorSkinned(); + } + else + { + if( viewDef->is2Dgui ) + { + // RB: 2D fullscreen drawing like warp or damage blend effects + renderProgManager.BindShader_TextureVertexColor_sRGB(); + } + else + { + renderProgManager.BindShader_TextureVertexColor(); + } + } + } + } + } + else if( ( pStage->texture.texgen == TG_SCREEN ) || ( pStage->texture.texgen == TG_SCREEN2 ) ) + { + renderProgManager.BindShader_TextureTexGenVertexColor(); + } + else if( pStage->texture.cinematic ) + { + renderProgManager.BindShader_Bink(); + } + else + { + if( surf->jointCache ) + { + renderProgManager.BindShader_TextureVertexColorSkinned(); + } + else + { + renderProgManager.BindShader_TextureVertexColor(); + } + } + + RB_SetVertexColorParms( svc ); + + // bind the texture + BindVariableStageImage( &pStage->texture, regs ); + + // set privatePolygonOffset if necessary + if( pStage->privatePolygonOffset ) + { + GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * pStage->privatePolygonOffset ); + stageGLState |= GLS_POLYGON_OFFSET; + } + + // set the state + GL_State( stageGLState ); + + PrepareStageTexturing( pStage, surf ); + + // draw it + DrawElementsWithCounters( surf ); + + FinishStageTexturing( pStage, surf ); + + // unset privatePolygonOffset if necessary + if( pStage->privatePolygonOffset ) + { + GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); + } + renderLog.CloseBlock(); + } + + renderLog.CloseBlock(); + } + + GL_Cull( CT_FRONT_SIDED ); + GL_Color( 1.0f, 1.0f, 1.0f ); + + // disable stencil shadow test + GL_State( GLS_DEFAULT ); + + GL_SelectTexture( 0 ); + + renderLog.CloseBlock(); + return i; +} + +/* +============================================================================================= + +BLEND LIGHT PROJECTION + +============================================================================================= +*/ + +/* +===================== +idRenderBackend::T_BlendLight +===================== +*/ +void idRenderBackend::T_BlendLight( const drawSurf_t* drawSurfs, const viewLight_t* vLight ) +{ + currentSpace = NULL; + + for( const drawSurf_t* drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight ) + { + if( drawSurf->scissorRect.IsEmpty() ) + { + continue; // !@# FIXME: find out why this is sometimes being hit! + // temporarily jump over the scissor and draw so the gl error callback doesn't get hit + } + + if( !currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) + { + // change the scissor + GL_Scissor( viewDef->viewport.x1 + drawSurf->scissorRect.x1, + viewDef->viewport.y1 + drawSurf->scissorRect.y1, + drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1, + drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 ); + + currentScissor = drawSurf->scissorRect; + } + + if( drawSurf->space != currentSpace ) + { + // change the matrix + RB_SetMVP( drawSurf->space->mvp ); + + // change the light projection matrix + idPlane lightProjectInCurrentSpace[4]; + for( int i = 0; i < 4; i++ ) + { + R_GlobalPlaneToLocal( drawSurf->space->modelMatrix, vLight->lightProject[i], lightProjectInCurrentSpace[i] ); + } + + SetVertexParm( RENDERPARM_TEXGEN_0_S, lightProjectInCurrentSpace[0].ToFloatPtr() ); + SetVertexParm( RENDERPARM_TEXGEN_0_T, lightProjectInCurrentSpace[1].ToFloatPtr() ); + SetVertexParm( RENDERPARM_TEXGEN_0_Q, lightProjectInCurrentSpace[2].ToFloatPtr() ); + SetVertexParm( RENDERPARM_TEXGEN_1_S, lightProjectInCurrentSpace[3].ToFloatPtr() ); // falloff + + currentSpace = drawSurf->space; + } + + DrawElementsWithCounters( drawSurf ); + } +} + +/* +===================== +idRenderBackend::BlendLight + +Dual texture together the falloff and projection texture with a blend +mode to the framebuffer, instead of interacting with the surface texture +===================== +*/ +void idRenderBackend::BlendLight( const drawSurf_t* drawSurfs, const drawSurf_t* drawSurfs2, const viewLight_t* vLight ) +{ + if( drawSurfs == NULL ) + { + return; + } + if( r_skipBlendLights.GetBool() ) + { + return; + } + renderLog.OpenBlock( vLight->lightShader->GetName() ); + + const idMaterial* lightShader = vLight->lightShader; + const float* regs = vLight->shaderRegisters; + + // texture 1 will get the falloff texture + GL_SelectTexture( 1 ); + vLight->falloffImage->Bind(); + + // texture 0 will get the projected texture + GL_SelectTexture( 0 ); + + renderProgManager.BindShader_BlendLight(); + + for( int i = 0; i < lightShader->GetNumStages(); i++ ) + { + const shaderStage_t* stage = lightShader->GetStage( i ); + + if( !regs[ stage->conditionRegister ] ) + { + continue; + } + + GL_State( GLS_DEPTHMASK | stage->drawStateBits | GLS_DEPTHFUNC_EQUAL ); + + GL_SelectTexture( 0 ); + stage->texture.image->Bind(); + + if( stage->texture.hasMatrix ) + { + RB_LoadShaderTextureMatrix( regs, &stage->texture ); + } + + // get the modulate values from the light, including alpha, unlike normal lights + idVec4 lightColor; + lightColor[0] = regs[ stage->color.registers[0] ]; + lightColor[1] = regs[ stage->color.registers[1] ]; + lightColor[2] = regs[ stage->color.registers[2] ]; + lightColor[3] = regs[ stage->color.registers[3] ]; + GL_Color( lightColor ); + + T_BlendLight( drawSurfs, vLight ); + T_BlendLight( drawSurfs2, vLight ); + } + + GL_SelectTexture( 0 ); + + renderProgManager.Unbind(); + renderLog.CloseBlock(); +} + +/* +========================================================================================================= + +FOG LIGHTS + +========================================================================================================= +*/ + +/* +===================== +idRenderBackend::T_BasicFog +===================== +*/ +void idRenderBackend::T_BasicFog( const drawSurf_t* drawSurfs, const idPlane fogPlanes[4], const idRenderMatrix* inverseBaseLightProject ) +{ + currentSpace = NULL; + + for( const drawSurf_t* drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight ) + { + if( drawSurf->scissorRect.IsEmpty() ) + { + continue; // !@# FIXME: find out why this is sometimes being hit! + // temporarily jump over the scissor and draw so the gl error callback doesn't get hit + } + + if( !currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) + { + // change the scissor + GL_Scissor( viewDef->viewport.x1 + drawSurf->scissorRect.x1, + viewDef->viewport.y1 + drawSurf->scissorRect.y1, + drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1, + drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 ); + + currentScissor = drawSurf->scissorRect; + } + + if( drawSurf->space != currentSpace ) + { + idPlane localFogPlanes[4]; + if( inverseBaseLightProject == NULL ) + { + RB_SetMVP( drawSurf->space->mvp ); + for( int i = 0; i < 4; i++ ) + { + R_GlobalPlaneToLocal( drawSurf->space->modelMatrix, fogPlanes[i], localFogPlanes[i] ); + } + } + else + { + idRenderMatrix invProjectMVPMatrix; + idRenderMatrix::Multiply( viewDef->worldSpace.mvp, *inverseBaseLightProject, invProjectMVPMatrix ); + RB_SetMVP( invProjectMVPMatrix ); + for( int i = 0; i < 4; i++ ) + { + inverseBaseLightProject->InverseTransformPlane( fogPlanes[i], localFogPlanes[i], false ); + } + } + + SetVertexParm( RENDERPARM_TEXGEN_0_S, localFogPlanes[0].ToFloatPtr() ); + SetVertexParm( RENDERPARM_TEXGEN_0_T, localFogPlanes[1].ToFloatPtr() ); + SetVertexParm( RENDERPARM_TEXGEN_1_T, localFogPlanes[2].ToFloatPtr() ); + SetVertexParm( RENDERPARM_TEXGEN_1_S, localFogPlanes[3].ToFloatPtr() ); + + currentSpace = ( inverseBaseLightProject == NULL ) ? drawSurf->space : NULL; + } + + if( drawSurf->jointCache ) + { + renderProgManager.BindShader_FogSkinned(); + } + else + { + renderProgManager.BindShader_Fog(); + } + + DrawElementsWithCounters( drawSurf ); + } +} + +/* +================== +idRenderBackend::FogPass +================== +*/ +void idRenderBackend::FogPass( const drawSurf_t* drawSurfs, const drawSurf_t* drawSurfs2, const viewLight_t* vLight ) +{ + renderLog.OpenBlock( vLight->lightShader->GetName() ); + + // find the current color and density of the fog + const idMaterial* lightShader = vLight->lightShader; + const float* regs = vLight->shaderRegisters; + // assume fog shaders have only a single stage + const shaderStage_t* stage = lightShader->GetStage( 0 ); + + idVec4 lightColor; + lightColor[0] = regs[ stage->color.registers[0] ]; + lightColor[1] = regs[ stage->color.registers[1] ]; + lightColor[2] = regs[ stage->color.registers[2] ]; + lightColor[3] = regs[ stage->color.registers[3] ]; + + GL_Color( lightColor ); + + // calculate the falloff planes + float a; + + // if they left the default value on, set a fog distance of 500 + if( lightColor[3] <= 1.0f ) + { + a = -0.5f / DEFAULT_FOG_DISTANCE; + } + else + { + // otherwise, distance = alpha color + a = -0.5f / lightColor[3]; + } + + // texture 0 is the falloff image + GL_SelectTexture( 0 ); + globalImages->fogImage->Bind(); + + // texture 1 is the entering plane fade correction + GL_SelectTexture( 1 ); + globalImages->fogEnterImage->Bind(); + + // S is based on the view origin + const float s = vLight->fogPlane.Distance( viewDef->renderView.vieworg ); + + const float FOG_SCALE = 0.001f; + + idPlane fogPlanes[4]; + + // S-0 + fogPlanes[0][0] = a * viewDef->worldSpace.modelViewMatrix[0 * 4 + 2]; + fogPlanes[0][1] = a * viewDef->worldSpace.modelViewMatrix[1 * 4 + 2]; + fogPlanes[0][2] = a * viewDef->worldSpace.modelViewMatrix[2 * 4 + 2]; + fogPlanes[0][3] = a * viewDef->worldSpace.modelViewMatrix[3 * 4 + 2] + 0.5f; + + // T-0 + fogPlanes[1][0] = 0.0f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[0*4+0]; + fogPlanes[1][1] = 0.0f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[1*4+0]; + fogPlanes[1][2] = 0.0f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[2*4+0]; + fogPlanes[1][3] = 0.5f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[3*4+0] + 0.5f; + + // T-1 will get a texgen for the fade plane, which is always the "top" plane on unrotated lights + fogPlanes[2][0] = FOG_SCALE * vLight->fogPlane[0]; + fogPlanes[2][1] = FOG_SCALE * vLight->fogPlane[1]; + fogPlanes[2][2] = FOG_SCALE * vLight->fogPlane[2]; + fogPlanes[2][3] = FOG_SCALE * vLight->fogPlane[3] + FOG_ENTER; + + // S-1 + fogPlanes[3][0] = 0.0f; + fogPlanes[3][1] = 0.0f; + fogPlanes[3][2] = 0.0f; + fogPlanes[3][3] = FOG_SCALE * s + FOG_ENTER; + + // draw it + GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); + T_BasicFog( drawSurfs, fogPlanes, NULL ); + T_BasicFog( drawSurfs2, fogPlanes, NULL ); + + // the light frustum bounding planes aren't in the depth buffer, so use depthfunc_less instead + // of depthfunc_equal + GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_LESS ); + GL_Cull( CT_BACK_SIDED ); + + zeroOneCubeSurface.space = &viewDef->worldSpace; + zeroOneCubeSurface.scissorRect = viewDef->scissor; + T_BasicFog( &zeroOneCubeSurface, fogPlanes, &vLight->inverseBaseLightProject ); + + GL_Cull( CT_FRONT_SIDED ); + + GL_SelectTexture( 0 ); + + renderProgManager.Unbind(); + + renderLog.CloseBlock(); +} + +/* +================== +idRenderBackend::FogAllLights +================== +*/ +void idRenderBackend::FogAllLights() +{ + if( r_skipFogLights.GetBool() || r_showOverDraw.GetInteger() != 0 + || viewDef->isXraySubview /* don't fog in xray mode*/ ) + { + return; + } + renderLog.OpenMainBlock( MRB_FOG_ALL_LIGHTS ); + renderLog.OpenBlock( "RB_FogAllLights" ); + + // force fog plane to recalculate + currentSpace = NULL; + + for( viewLight_t* vLight = viewDef->viewLights; vLight != NULL; vLight = vLight->next ) + { + if( vLight->lightShader->IsFogLight() ) + { + FogPass( vLight->globalInteractions, vLight->localInteractions, vLight ); + } + else if( vLight->lightShader->IsBlendLight() ) + { + BlendLight( vLight->globalInteractions, vLight->localInteractions, vLight ); + } + } + + renderLog.CloseBlock(); + renderLog.CloseMainBlock(); +} + +// RB begin +void idRenderBackend::CalculateAutomaticExposure() +{ + int i; + static float image[64 * 64 * 4]; + float curTime; + float deltaTime; + float luminance; + float avgLuminance; + float maxLuminance; + double sum; + const idVec3 LUMINANCE_SRGB( 0.2125f, 0.7154f, 0.0721f ); // be careful wether this should be linear RGB or sRGB + idVec4 color; + float newAdaptation; + float newMaximum; + + if( !r_hdrAutoExposure.GetBool() ) + { + // no dynamic exposure + + hdrKey = r_hdrKey.GetFloat(); + hdrAverageLuminance = r_hdrMinLuminance.GetFloat(); + hdrMaxLuminance = 1; + } + else + { + curTime = Sys_Milliseconds() / 1000.0f; + + // calculate the average scene luminance + globalFramebuffers.hdr64FBO->Bind(); + + // read back the contents + // glFinish(); + glReadPixels( 0, 0, 64, 64, GL_RGBA, GL_FLOAT, image ); + + sum = 0.0f; + maxLuminance = 0.0f; + for( i = 0; i < ( 64 * 64 ); i += 4 ) + { + color[0] = image[i * 4 + 0]; + color[1] = image[i * 4 + 1]; + color[2] = image[i * 4 + 2]; + color[3] = image[i * 4 + 3]; + + luminance = ( color.x * LUMINANCE_SRGB.x + color.y * LUMINANCE_SRGB.y + color.z * LUMINANCE_SRGB.z ) + 0.0001f; + if( luminance > maxLuminance ) + { + maxLuminance = luminance; + } + + float logLuminance = log( luminance + 1 ); + //if( logLuminance > 0 ) + { + sum += luminance; + } + } +#if 0 + sum /= ( 64.0f * 64.0f ); + avgLuminance = exp( sum ); +#else + avgLuminance = sum / ( 64.0f * 64.0f ); +#endif + + // the user's adapted luminance level is simulated by closing the gap between + // adapted luminance and current luminance by 2% every frame, based on a + // 30 fps rate. This is not an accurate model of human adaptation, which can + // take longer than half an hour. + if( hdrTime > curTime ) + { + hdrTime = curTime; + } + + deltaTime = curTime - hdrTime; + + //if(r_hdrMaxLuminance->value) + { + hdrAverageLuminance = idMath::ClampFloat( r_hdrMinLuminance.GetFloat(), r_hdrMaxLuminance.GetFloat(), hdrAverageLuminance ); + avgLuminance = idMath::ClampFloat( r_hdrMinLuminance.GetFloat(), r_hdrMaxLuminance.GetFloat(), avgLuminance ); + + hdrMaxLuminance = idMath::ClampFloat( r_hdrMinLuminance.GetFloat(), r_hdrMaxLuminance.GetFloat(), hdrMaxLuminance ); + maxLuminance = idMath::ClampFloat( r_hdrMinLuminance.GetFloat(), r_hdrMaxLuminance.GetFloat(), maxLuminance ); + } + + newAdaptation = hdrAverageLuminance + ( avgLuminance - hdrAverageLuminance ) * ( 1.0f - powf( 0.98f, 30.0f * deltaTime ) ); + newMaximum = hdrMaxLuminance + ( maxLuminance - hdrMaxLuminance ) * ( 1.0f - powf( 0.98f, 30.0f * deltaTime ) ); + + if( !IsNAN( newAdaptation ) && !IsNAN( newMaximum ) ) + { +#if 1 + hdrAverageLuminance = newAdaptation; + hdrMaxLuminance = newMaximum; +#else + hdrAverageLuminance = avgLuminance; + hdrMaxLuminance = maxLuminance; +#endif + } + + hdrTime = curTime; + + // calculate HDR image key +#if 0 + // RB: this never worked :/ + if( r_hdrAutoExposure.GetBool() ) + { + // calculation from: Perceptual Effects in Real-time Tone Mapping - Krawczyk et al. + hdrKey = 1.03 - ( 2.0 / ( 2.0 + ( hdrAverageLuminance + 1.0f ) ) ); + } + else +#endif + { + hdrKey = r_hdrKey.GetFloat(); + } + } + + if( r_hdrDebug.GetBool() ) + { + idLib::Printf( "HDR luminance avg = %f, max = %f, key = %f\n", hdrAverageLuminance, hdrMaxLuminance, hdrKey ); + } + + //GL_CheckErrors(); +} + + +void idRenderBackend::Tonemap( const viewDef_t* _viewDef ) +{ + RENDERLOG_PRINTF( "---------- RB_Tonemap( avg = %f, max = %f, key = %f, is2Dgui = %i ) ----------\n", hdrAverageLuminance, hdrMaxLuminance, hdrKey, ( int )viewDef->is2Dgui ); + + //postProcessCommand_t* cmd = ( postProcessCommand_t* )data; + //const idScreenRect& viewport = cmd->viewDef->viewport; + //globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); + + Framebuffer::Unbind(); + + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + GL_Cull( CT_TWO_SIDED ); + + int screenWidth = renderSystem->GetWidth(); + int screenHeight = renderSystem->GetHeight(); + + // set the window clipping + GL_Viewport( 0, 0, screenWidth, screenHeight ); + GL_Scissor( 0, 0, screenWidth, screenHeight ); + + GL_SelectTexture( 0 ); + +#if defined(USE_HDR_MSAA) + if( glConfig.multisamples > 0 ) + { + globalImages->currentRenderHDRImageNoMSAA->Bind(); + } + else +#endif + { + globalImages->currentRenderHDRImage->Bind(); + } + + GL_SelectTexture( 1 ); + globalImages->heatmap7Image->Bind(); + + if( r_hdrDebug.GetBool() ) + { + renderProgManager.BindShader_HDRDebug(); + } + else + { + renderProgManager.BindShader_Tonemap(); + } + + float screenCorrectionParm[4]; + if( _viewDef->is2Dgui ) + { + screenCorrectionParm[0] = 2.0f; + screenCorrectionParm[1] = 1.0f; + screenCorrectionParm[2] = 1.0f; + } + else + { + if( r_hdrAutoExposure.GetBool() ) + { + float exposureOffset = Lerp( -0.01f, 0.02f, idMath::ClampFloat( 0.0, 1.0, r_exposure.GetFloat() ) ); + + screenCorrectionParm[0] = hdrKey + exposureOffset; + screenCorrectionParm[1] = hdrAverageLuminance; + screenCorrectionParm[2] = hdrMaxLuminance; + screenCorrectionParm[3] = exposureOffset; + //screenCorrectionParm[3] = Lerp( -1, 5, idMath::ClampFloat( 0.0, 1.0, r_exposure.GetFloat() ) ); + } + else + { + //float exposureOffset = ( idMath::ClampFloat( 0.0, 1.0, r_exposure.GetFloat() ) * 2.0f - 1.0f ) * 0.01f; + + float exposureOffset = Lerp( -0.01f, 0.01f, idMath::ClampFloat( 0.0, 1.0, r_exposure.GetFloat() ) ); + + screenCorrectionParm[0] = 0.015f + exposureOffset; + screenCorrectionParm[1] = 0.005f; + screenCorrectionParm[2] = 1; + + // RB: this gives a nice exposure curve in Scilab when using + // log2( max( 3 + 0..10, 0.001 ) ) as input for exp2 + //float exposureOffset = r_exposure.GetFloat() * 10.0f; + //screenCorrectionParm[3] = exposureOffset; + } + } + + SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor + + // Draw + DrawElementsWithCounters( &unitSquareSurface ); + + GL_SelectTexture( 0 ); + renderProgManager.Unbind(); + + GL_State( GLS_DEFAULT ); + GL_Cull( CT_FRONT_SIDED ); +} + + +void idRenderBackend::Bloom( const viewDef_t* _viewDef ) +{ + if( _viewDef->is2Dgui || !r_useHDR.GetBool() ) + { + return; + } + + RENDERLOG_PRINTF( "---------- RB_Bloom( avg = %f, max = %f, key = %f ) ----------\n", hdrAverageLuminance, hdrMaxLuminance, hdrKey ); + + // BRIGHTPASS + + //GL_CheckErrors(); + + //Framebuffer::Unbind(); + //globalFramebuffers.hdrQuarterFBO->Bind(); + + glClearColor( 0, 0, 0, 1 ); +// glClear( GL_COLOR_BUFFER_BIT ); + + GL_State( /*GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO |*/ GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + GL_Cull( CT_TWO_SIDED ); + + int screenWidth = renderSystem->GetWidth(); + int screenHeight = renderSystem->GetHeight(); + + // set the window clipping + GL_Viewport( 0, 0, screenWidth / 4, screenHeight / 4 ); + GL_Scissor( 0, 0, screenWidth / 4, screenHeight / 4 ); + + globalFramebuffers.bloomRenderFBO[ 0 ]->Bind(); + + GL_SelectTexture( 0 ); + + if( r_useHDR.GetBool() ) + { + globalImages->currentRenderHDRImage->Bind(); + + renderProgManager.BindShader_Brightpass(); + } + else + { + int x = viewDef->viewport.x1; + int y = viewDef->viewport.y1; + int w = viewDef->viewport.x2 - viewDef->viewport.x1 + 1; + int h = viewDef->viewport.y2 - viewDef->viewport.y1 + 1; + + RENDERLOG_PRINTF( "Resolve to %i x %i buffer\n", w, h ); + + // resolve the screen + globalImages->currentRenderImage->CopyFramebuffer( x, y, w, h ); + + renderProgManager.BindShader_Brightpass(); + } + + float screenCorrectionParm[4]; + screenCorrectionParm[0] = hdrKey; + screenCorrectionParm[1] = hdrAverageLuminance; + screenCorrectionParm[2] = hdrMaxLuminance; + screenCorrectionParm[3] = 1.0f; + SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor + + float overbright[4]; + if( r_useHDR.GetBool() ) + { + if( r_hdrAutoExposure.GetBool() ) + { + overbright[0] = r_hdrContrastDynamicThreshold.GetFloat(); + } + else + { + overbright[0] = r_hdrContrastStaticThreshold.GetFloat(); + } + overbright[1] = r_hdrContrastOffset.GetFloat(); + overbright[2] = 0; + overbright[3] = 0; + } + else + { + overbright[0] = r_ldrContrastThreshold.GetFloat(); + overbright[1] = r_ldrContrastOffset.GetFloat(); + overbright[2] = 0; + overbright[3] = 0; + } + SetFragmentParm( RENDERPARM_OVERBRIGHT, overbright ); // rpOverbright + + // Draw + DrawElementsWithCounters( &unitSquareSurface ); + + + // BLOOM PING PONG rendering + renderProgManager.BindShader_HDRGlareChromatic(); + + int j; + for( j = 0; j < r_hdrGlarePasses.GetInteger(); j++ ) + { + globalFramebuffers.bloomRenderFBO[( j + 1 ) % 2 ]->Bind(); + glClear( GL_COLOR_BUFFER_BIT ); + + globalImages->bloomRenderImage[j % 2]->Bind(); + + DrawElementsWithCounters( &unitSquareSurface ); + } + + // add filtered glare back to main context + Framebuffer::Unbind(); + + ResetViewportAndScissorToDefaultCamera( _viewDef ); + + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + + renderProgManager.BindShader_Screen(); + + globalImages->bloomRenderImage[( j + 1 ) % 2]->Bind(); + + DrawElementsWithCounters( &unitSquareSurface ); + + renderProgManager.Unbind(); + + GL_State( GLS_DEFAULT ); + GL_Cull( CT_FRONT_SIDED ); +} + + +void idRenderBackend::DrawScreenSpaceAmbientOcclusion( const viewDef_t* _viewDef ) +{ + if( !_viewDef->viewEntitys || _viewDef->is2Dgui ) + { + // 3D views only + return; + } + + if( r_useSSAO.GetInteger() <= 0 ) + { + return; + } + + // FIXME very expensive to enable this in subviews + if( _viewDef->isSubview ) + { + return; + } + + RENDERLOG_PRINTF( "---------- RB_SSAO() ----------\n" ); + +#if 0 + GL_CheckErrors(); + + // clear the alpha buffer and draw only the hands + weapon into it so + // we can avoid blurring them + glClearColor( 0, 0, 0, 1 ); + GL_State( GLS_COLORMASK | GLS_DEPTHMASK ); + glClear( GL_COLOR_BUFFER_BIT ); + GL_Color( 0, 0, 0, 0 ); + + + GL_SelectTexture( 0 ); + globalImages->blackImage->Bind(); + backEnd.currentSpace = NULL; + + drawSurf_t** drawSurfs = ( drawSurf_t** )&backEnd.viewDef->drawSurfs[0]; + for( int surfNum = 0; surfNum < backEnd.viewDef->numDrawSurfs; surfNum++ ) + { + const drawSurf_t* surf = drawSurfs[ surfNum ]; + + if( !surf->space->weaponDepthHack && !surf->space->skipMotionBlur && !surf->material->HasSubview() ) + { + // Apply motion blur to this object + continue; + } + + const idMaterial* shader = surf->material; + if( shader->Coverage() == MC_TRANSLUCENT ) + { + // muzzle flash, etc + continue; + } + + // set mvp matrix + if( surf->space != backEnd.currentSpace ) + { + RB_SetMVP( surf->space->mvp ); + backEnd.currentSpace = surf->space; + } + + // this could just be a color, but we don't have a skinned color-only prog + if( surf->jointCache ) + { + renderProgManager.BindShader_TextureVertexColorSkinned(); + } + else + { + renderProgManager.BindShader_TextureVertexColor(); + } + + // draw it solid + RB_DrawElementsWithCounters( surf ); + } + GL_State( GLS_DEPTHFUNC_ALWAYS ); + + // copy off the color buffer and the depth buffer for the motion blur prog + // we use the viewport dimensions for copying the buffers in case resolution scaling is enabled. + const idScreenRect& viewport = backEnd.viewDef->viewport; + globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); + + // in stereo rendering, each eye needs to get a separate previous frame mvp + int mvpIndex = ( backEnd.viewDef->renderView.viewEyeBuffer == 1 ) ? 1 : 0; + + // derive the matrix to go from current pixels to previous frame pixels + idRenderMatrix inverseMVP; + idRenderMatrix::Inverse( backEnd.viewDef->worldSpace.mvp, inverseMVP ); + + idRenderMatrix motionMatrix; + idRenderMatrix::Multiply( backEnd.prevMVP[mvpIndex], inverseMVP, motionMatrix ); + + backEnd.prevMVP[mvpIndex] = backEnd.viewDef->worldSpace.mvp; + + RB_SetMVP( motionMatrix ); +#endif + + currentSpace = &viewDef->worldSpace; + RB_SetMVP( viewDef->worldSpace.mvp ); + + const bool hdrIsActive = ( r_useHDR.GetBool() && globalFramebuffers.hdrFBO != NULL && globalFramebuffers.hdrFBO->IsBound() ); + + int screenWidth = renderSystem->GetWidth(); + int screenHeight = renderSystem->GetHeight(); + + // build hierarchical depth buffer + if( r_useHierarchicalDepthBuffer.GetBool() ) + { + renderProgManager.BindShader_AmbientOcclusionMinify(); + + glClearColor( 0, 0, 0, 1 ); + + GL_SelectTexture( 0 ); + //globalImages->currentDepthImage->Bind(); + + for( int i = 0; i < MAX_HIERARCHICAL_ZBUFFERS; i++ ) + { + int width = globalFramebuffers.csDepthFBO[i]->GetWidth(); + int height = globalFramebuffers.csDepthFBO[i]->GetHeight(); + + GL_Viewport( 0, 0, width, height ); + GL_Scissor( 0, 0, width, height ); + + globalFramebuffers.csDepthFBO[i]->Bind(); + + glClear( GL_COLOR_BUFFER_BIT ); + + if( i == 0 ) + { + renderProgManager.BindShader_AmbientOcclusionReconstructCSZ(); + + globalImages->currentDepthImage->Bind(); + } + else + { + renderProgManager.BindShader_AmbientOcclusionMinify(); + + GL_SelectTexture( 0 ); + globalImages->hierarchicalZbufferImage->Bind(); + } + + float jitterTexScale[4]; + jitterTexScale[0] = i - 1; + jitterTexScale[1] = 0; + jitterTexScale[2] = 0; + jitterTexScale[3] = 0; + SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale +#if 1 + float screenCorrectionParm[4]; + screenCorrectionParm[0] = 1.0f / width; + screenCorrectionParm[1] = 1.0f / height; + screenCorrectionParm[2] = width; + screenCorrectionParm[3] = height; + SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor +#endif + + DrawElementsWithCounters( &unitSquareSurface ); + } + } + + // set the window clipping + GL_Viewport( 0, 0, screenWidth, screenHeight ); + GL_Scissor( 0, 0, screenWidth, screenHeight ); + + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + GL_Cull( CT_TWO_SIDED ); + + if( r_ssaoFiltering.GetBool() ) + { + globalFramebuffers.ambientOcclusionFBO[0]->Bind(); + + glClearColor( 0, 0, 0, 0 ); + glClear( GL_COLOR_BUFFER_BIT ); + + renderProgManager.BindShader_AmbientOcclusion(); + } + else + { + if( r_ssaoDebug.GetInteger() <= 0 ) + { + GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_ALPHAMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + } + + if( hdrIsActive ) + { + globalFramebuffers.hdrFBO->Bind(); + } + else + { + Framebuffer::Unbind(); + } + + renderProgManager.BindShader_AmbientOcclusionAndOutput(); + } + + float screenCorrectionParm[4]; + screenCorrectionParm[0] = 1.0f / screenWidth; + screenCorrectionParm[1] = 1.0f / screenHeight; + screenCorrectionParm[2] = screenWidth; + screenCorrectionParm[3] = screenHeight; + SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor + +#if 0 + // RB: set unprojection matrices so we can convert zbuffer values back to camera and world spaces + idRenderMatrix modelViewMatrix; + idRenderMatrix::Transpose( *( idRenderMatrix* )backEnd.viewDef->worldSpace.modelViewMatrix, modelViewMatrix ); + idRenderMatrix cameraToWorldMatrix; + if( !idRenderMatrix::Inverse( modelViewMatrix, cameraToWorldMatrix ) ) + { + idLib::Warning( "cameraToWorldMatrix invert failed" ); + } + + SetVertexParms( RENDERPARM_MODELMATRIX_X, cameraToWorldMatrix[0], 4 ); + //SetVertexParms( RENDERPARM_MODELMATRIX_X, viewDef->unprojectionToWorldRenderMatrix[0], 4 ); +#endif + SetVertexParms( RENDERPARM_MODELMATRIX_X, viewDef->unprojectionToCameraRenderMatrix[0], 4 ); + + + float jitterTexOffset[4]; + if( r_shadowMapRandomizeJitter.GetBool() ) + { + jitterTexOffset[0] = ( rand() & 255 ) / 255.0; + jitterTexOffset[1] = ( rand() & 255 ) / 255.0; + } + else + { + jitterTexOffset[0] = 0; + jitterTexOffset[1] = 0; + } + jitterTexOffset[2] = viewDef->renderView.time[0] * 0.001f; + jitterTexOffset[3] = 0.0f; + SetFragmentParm( RENDERPARM_JITTERTEXOFFSET, jitterTexOffset ); // rpJitterTexOffset + + GL_SelectTexture( 0 ); + globalImages->currentNormalsImage->Bind(); + + GL_SelectTexture( 1 ); + if( r_useHierarchicalDepthBuffer.GetBool() ) + { + globalImages->hierarchicalZbufferImage->Bind(); + } + else + { + globalImages->currentDepthImage->Bind(); + } + + DrawElementsWithCounters( &unitSquareSurface ); + + if( r_ssaoFiltering.GetBool() ) + { + float jitterTexScale[4]; + + // AO blur X +#if 1 + globalFramebuffers.ambientOcclusionFBO[1]->Bind(); + + renderProgManager.BindShader_AmbientOcclusionBlur(); + + // set axis parameter + jitterTexScale[0] = 1; + jitterTexScale[1] = 0; + jitterTexScale[2] = 0; + jitterTexScale[3] = 0; + SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale + + GL_SelectTexture( 2 ); + globalImages->ambientOcclusionImage[0]->Bind(); + + DrawElementsWithCounters( &unitSquareSurface ); +#endif + + // AO blur Y + if( hdrIsActive ) + { + globalFramebuffers.hdrFBO->Bind(); + } + else + { + Framebuffer::Unbind(); + } + + if( r_ssaoDebug.GetInteger() <= 0 ) + { + GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + } + + renderProgManager.BindShader_AmbientOcclusionBlurAndOutput(); + + // set axis parameter + jitterTexScale[0] = 0; + jitterTexScale[1] = 1; + jitterTexScale[2] = 0; + jitterTexScale[3] = 0; + SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale + + GL_SelectTexture( 2 ); + globalImages->ambientOcclusionImage[1]->Bind(); + + DrawElementsWithCounters( &unitSquareSurface ); + } + + renderProgManager.Unbind(); + + GL_State( GLS_DEFAULT ); + GL_Cull( CT_FRONT_SIDED ); + + //GL_CheckErrors(); +} + +void idRenderBackend::DrawScreenSpaceGlobalIllumination( const viewDef_t* _viewDef ) +{ + if( !_viewDef->viewEntitys || _viewDef->is2Dgui ) + { + // 3D views only + return; + } + + if( r_useSSGI.GetInteger() <= 0 ) + { + return; + } + + // FIXME very expensive to enable this in subviews + if( _viewDef->isSubview ) + { + return; + } + + RENDERLOG_PRINTF( "---------- RB_SSGI() ----------\n" ); + + currentSpace = &viewDef->worldSpace; + RB_SetMVP( viewDef->worldSpace.mvp ); + + const bool hdrIsActive = ( r_useHDR.GetBool() && globalFramebuffers.hdrFBO != NULL && globalFramebuffers.hdrFBO->IsBound() ); + + int screenWidth = renderSystem->GetWidth(); + int screenHeight = renderSystem->GetHeight(); + + // set the window clipping + GL_Viewport( 0, 0, screenWidth, screenHeight ); + GL_Scissor( 0, 0, screenWidth, screenHeight ); + + if( !hdrIsActive ) + { + const idScreenRect& viewport = viewDef->viewport; + globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); + } + + // build hierarchical depth buffer + if( r_useHierarchicalDepthBuffer.GetBool() ) + { + renderProgManager.BindShader_AmbientOcclusionMinify(); + + glClearColor( 0, 0, 0, 1 ); + + GL_SelectTexture( 0 ); + //globalImages->currentDepthImage->Bind(); + + for( int i = 0; i < MAX_HIERARCHICAL_ZBUFFERS; i++ ) + { + int width = globalFramebuffers.csDepthFBO[i]->GetWidth(); + int height = globalFramebuffers.csDepthFBO[i]->GetHeight(); + + GL_Viewport( 0, 0, width, height ); + GL_Scissor( 0, 0, width, height ); + + globalFramebuffers.csDepthFBO[i]->Bind(); + + glClear( GL_COLOR_BUFFER_BIT ); + + if( i == 0 ) + { + renderProgManager.BindShader_AmbientOcclusionReconstructCSZ(); + + globalImages->currentDepthImage->Bind(); + } + else + { + renderProgManager.BindShader_AmbientOcclusionMinify(); + + GL_SelectTexture( 0 ); + globalImages->hierarchicalZbufferImage->Bind(); + } + + float jitterTexScale[4]; + jitterTexScale[0] = i - 1; + jitterTexScale[1] = 0; + jitterTexScale[2] = 0; + jitterTexScale[3] = 0; + SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale +#if 1 + float screenCorrectionParm[4]; + screenCorrectionParm[0] = 1.0f / width; + screenCorrectionParm[1] = 1.0f / height; + screenCorrectionParm[2] = width; + screenCorrectionParm[3] = height; + SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor +#endif + + DrawElementsWithCounters( &unitSquareSurface ); + } + } + + // set the window clipping + GL_Viewport( 0, 0, screenWidth, screenHeight ); + GL_Scissor( 0, 0, screenWidth, screenHeight ); + + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + GL_Cull( CT_TWO_SIDED ); + + if( r_ssgiFiltering.GetBool() ) + { + globalFramebuffers.ambientOcclusionFBO[0]->Bind(); + + // FIXME remove and mix with color from previous frame + glClearColor( 0, 0, 0, 0 ); + glClear( GL_COLOR_BUFFER_BIT ); + + renderProgManager.BindShader_DeepGBufferRadiosity(); + } + else + { + if( r_ssgiDebug.GetInteger() > 0 ) + { + // replace current + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + } + else + { + // add result to main color + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + } + + if( hdrIsActive ) + { + globalFramebuffers.hdrFBO->Bind(); + } + else + { + Framebuffer::Unbind(); + } + + renderProgManager.BindShader_DeepGBufferRadiosity(); + } + + float screenCorrectionParm[4]; + screenCorrectionParm[0] = 1.0f / screenWidth; + screenCorrectionParm[1] = 1.0f / screenHeight; + screenCorrectionParm[2] = screenWidth; + screenCorrectionParm[3] = screenHeight; + SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor + +#if 0 + // RB: set unprojection matrices so we can convert zbuffer values back to camera and world spaces + idRenderMatrix modelViewMatrix; + idRenderMatrix::Transpose( *( idRenderMatrix* )backEnd.viewDef->worldSpace.modelViewMatrix, modelViewMatrix ); + idRenderMatrix cameraToWorldMatrix; + if( !idRenderMatrix::Inverse( modelViewMatrix, cameraToWorldMatrix ) ) + { + idLib::Warning( "cameraToWorldMatrix invert failed" ); + } + + SetVertexParms( RENDERPARM_MODELMATRIX_X, cameraToWorldMatrix[0], 4 ); + //SetVertexParms( RENDERPARM_MODELMATRIX_X, viewDef->unprojectionToWorldRenderMatrix[0], 4 ); +#endif + SetVertexParms( RENDERPARM_MODELMATRIX_X, viewDef->unprojectionToCameraRenderMatrix[0], 4 ); + + + float jitterTexOffset[4]; + if( r_shadowMapRandomizeJitter.GetBool() ) + { + jitterTexOffset[0] = ( rand() & 255 ) / 255.0; + jitterTexOffset[1] = ( rand() & 255 ) / 255.0; + } + else + { + jitterTexOffset[0] = 0; + jitterTexOffset[1] = 0; + } + jitterTexOffset[2] = viewDef->renderView.time[0] * 0.001f; + jitterTexOffset[3] = 0.0f; + SetFragmentParm( RENDERPARM_JITTERTEXOFFSET, jitterTexOffset ); // rpJitterTexOffset + + GL_SelectTexture( 0 ); + globalImages->currentNormalsImage->Bind(); + + GL_SelectTexture( 1 ); + if( r_useHierarchicalDepthBuffer.GetBool() ) + { + globalImages->hierarchicalZbufferImage->Bind(); + } + else + { + globalImages->currentDepthImage->Bind(); + } + + GL_SelectTexture( 2 ); + if( hdrIsActive ) + { + globalImages->currentRenderHDRImage->Bind(); + } + else + { + globalImages->currentRenderImage->Bind(); + } + + DrawElementsWithCounters( &unitSquareSurface ); + + if( r_ssgiFiltering.GetBool() ) + { + float jitterTexScale[4]; + + // AO blur X +#if 1 + globalFramebuffers.ambientOcclusionFBO[1]->Bind(); + + renderProgManager.BindShader_DeepGBufferRadiosityBlur(); + + // set axis parameter + jitterTexScale[0] = 1; + jitterTexScale[1] = 0; + jitterTexScale[2] = 0; + jitterTexScale[3] = 0; + SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale + + GL_SelectTexture( 2 ); + globalImages->ambientOcclusionImage[0]->Bind(); + + DrawElementsWithCounters( &unitSquareSurface ); +#endif + + // AO blur Y + if( hdrIsActive ) + { + globalFramebuffers.hdrFBO->Bind(); + } + else + { + Framebuffer::Unbind(); + } + + if( r_ssgiDebug.GetInteger() > 0 ) + { + // replace current + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + } + else + { + // add result to main color + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + } + + renderProgManager.BindShader_DeepGBufferRadiosityBlurAndOutput(); + + // set axis parameter + jitterTexScale[0] = 0; + jitterTexScale[1] = 1; + jitterTexScale[2] = 0; + jitterTexScale[3] = 0; + SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale + + GL_SelectTexture( 2 ); + globalImages->ambientOcclusionImage[1]->Bind(); + + DrawElementsWithCounters( &unitSquareSurface ); + } + + renderProgManager.Unbind(); + + GL_State( GLS_DEFAULT ); + GL_Cull( CT_FRONT_SIDED ); + + //GL_CheckErrors(); +} +// RB end + +/* +========================================================================================================= + +BACKEND COMMANDS + +========================================================================================================= +*/ + +/* +================== +idRenderBackend::DrawViewInternal +================== +*/ +void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int stereoEye ) +{ + renderLog.OpenBlock( "RB_DrawViewInternal" ); + + //------------------------------------------------- + // guis can wind up referencing purged images that need to be loaded. + // this used to be in the gui emit code, but now that it can be running + // in a separate thread, it must not try to load images, so do it here. + //------------------------------------------------- + drawSurf_t** drawSurfs = ( drawSurf_t** )&_viewDef->drawSurfs[0]; + const int numDrawSurfs = _viewDef->numDrawSurfs; + + for( int i = 0; i < numDrawSurfs; i++ ) + { + const drawSurf_t* ds = _viewDef->drawSurfs[ i ]; + if( ds->material != NULL ) + { + const_cast( ds->material )->EnsureNotPurged(); + } + } + + //------------------------------------------------- + // RB_BeginDrawingView + // + // Any mirrored or portaled views have already been drawn, so prepare + // to actually render the visible surfaces for this view + // + // clear the z buffer, set the projection matrix, etc + //------------------------------------------------- + ResetViewportAndScissorToDefaultCamera( _viewDef ); + + faceCulling = -1; // force face culling to set next time + + // ensures that depth writes are enabled for the depth clear + GL_State( GLS_DEFAULT ); + + //GL_CheckErrors(); + + // RB begin + bool useHDR = r_useHDR.GetBool() && !_viewDef->is2Dgui; + + // Clear the depth buffer and clear the stencil to 128 for stencil shadows as well as gui masking + GL_Clear( false, true, true, STENCIL_SHADOW_TEST_VALUE, 0.0f, 0.0f, 0.0f, 0.0f, useHDR ); + + if( useHDR ) + { + globalFramebuffers.hdrFBO->Bind(); + } + else + { + Framebuffer::Unbind(); + } + // RB end + + //GL_CheckErrors(); + + // normal face culling + GL_Cull( CT_FRONT_SIDED ); + +#if defined(USE_CORE_PROFILE) && !defined(USE_GLES2) && !defined(USE_GLES3) + // bind one global Vertex Array Object (VAO) + glBindVertexArray( glConfig.global_vao ); +#endif + + //------------------------------------ + // sets variables that can be used by all programs + //------------------------------------ + { + // + // set eye position in global space + // + float parm[4]; + parm[0] = viewDef->renderView.vieworg[0]; + parm[1] = viewDef->renderView.vieworg[1]; + parm[2] = viewDef->renderView.vieworg[2]; + parm[3] = 1.0f; + + SetVertexParm( RENDERPARM_GLOBALEYEPOS, parm ); // rpGlobalEyePos + + // sets overbright to make world brighter + // This value is baked into the specularScale and diffuseScale values so + // the interaction programs don't need to perform the extra multiply, + // but any other renderprogs that want to obey the brightness value + // can reference this. + float overbright = r_lightScale.GetFloat() * 0.5f; + parm[0] = overbright; + parm[1] = overbright; + parm[2] = overbright; + parm[3] = overbright; + SetFragmentParm( RENDERPARM_OVERBRIGHT, parm ); + + // Set Projection Matrix + float projMatrixTranspose[16]; + R_MatrixTranspose( viewDef->projectionMatrix, projMatrixTranspose ); + SetVertexParms( RENDERPARM_PROJMATRIX_X, projMatrixTranspose, 4 ); + } + + //------------------------------------------------- + // fill the depth buffer and clear color buffer to black except on subviews + //------------------------------------------------- + FillDepthBufferFast( drawSurfs, numDrawSurfs ); + + //------------------------------------------------- + // FIXME, OPTIMIZE: merge this with FillDepthBufferFast like in a light prepass deferred renderer + // + // fill the geometric buffer with normals and roughness + //------------------------------------------------- + AmbientPass( drawSurfs, numDrawSurfs, true ); + + //------------------------------------------------- + // fill the depth buffer and the color buffer with precomputed Q3A style lighting + //------------------------------------------------- + AmbientPass( drawSurfs, numDrawSurfs, false ); + + //------------------------------------------------- + // main light renderer + //------------------------------------------------- + DrawInteractions( _viewDef ); + + //------------------------------------------------- + // capture the depth for the motion blur before rendering any post process surfaces that may contribute to the depth + //------------------------------------------------- + if( ( r_motionBlur.GetInteger() > 0 || r_useSSAO.GetBool() || r_useSSGI.GetBool() ) && !r_useHDR.GetBool() ) + { + const idScreenRect& viewport = viewDef->viewport; + globalImages->currentDepthImage->CopyDepthbuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); + } + + //------------------------------------------------- + // darken the scene using the screen space ambient occlusion + //------------------------------------------------- + DrawScreenSpaceAmbientOcclusion( _viewDef ); + //RB_SSGI( _viewDef ); + + //------------------------------------------------- + // now draw any non-light dependent shading passes + //------------------------------------------------- + int processed = 0; + if( !r_skipShaderPasses.GetBool() ) + { + renderLog.OpenMainBlock( MRB_DRAW_SHADER_PASSES ); + float guiScreenOffset; + if( _viewDef->viewEntitys != NULL ) + { + // guiScreenOffset will be 0 in non-gui views + guiScreenOffset = 0.0f; + } + else + { + guiScreenOffset = stereoEye * _viewDef->renderView.stereoScreenSeparation; + } + processed = DrawShaderPasses( drawSurfs, numDrawSurfs, guiScreenOffset, stereoEye ); + renderLog.CloseMainBlock(); + } + + //------------------------------------------------- + // use direct light and emissive light contributions to add indirect screen space light + //------------------------------------------------- + //RB_SSGI( viewDef ); + + //------------------------------------------------- + // fog and blend lights, drawn after emissive surfaces + // so they are properly dimmed down + //------------------------------------------------- + FogAllLights(); + + //------------------------------------------------- + // now draw any screen warping post-process effects using _currentRender + //------------------------------------------------- + if( processed < numDrawSurfs && !r_skipPostProcess.GetBool() ) + { + int x = viewDef->viewport.x1; + int y = viewDef->viewport.y1; + int w = viewDef->viewport.x2 - viewDef->viewport.x1 + 1; + int h = viewDef->viewport.y2 - viewDef->viewport.y1 + 1; + + RENDERLOG_PRINTF( "Resolve to %i x %i buffer\n", w, h ); + + GL_SelectTexture( 0 ); + + // resolve the screen + globalImages->currentRenderImage->CopyFramebuffer( x, y, w, h ); + currentRenderCopied = true; + + // RENDERPARM_SCREENCORRECTIONFACTOR amd RENDERPARM_WINDOWCOORD overlap + // diffuseScale and specularScale + + // screen power of two correction factor (no longer relevant now) + float screenCorrectionParm[4]; + screenCorrectionParm[0] = 1.0f; + screenCorrectionParm[1] = 1.0f; + screenCorrectionParm[2] = 0.0f; + screenCorrectionParm[3] = 1.0f; + SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor + + // window coord to 0.0 to 1.0 conversion + float windowCoordParm[4]; + windowCoordParm[0] = 1.0f / w; + windowCoordParm[1] = 1.0f / h; + windowCoordParm[2] = 0.0f; + windowCoordParm[3] = 1.0f; + SetFragmentParm( RENDERPARM_WINDOWCOORD, windowCoordParm ); // rpWindowCoord + + // render the remaining surfaces + renderLog.OpenMainBlock( MRB_DRAW_SHADER_PASSES_POST ); + DrawShaderPasses( drawSurfs + processed, numDrawSurfs - processed, 0.0f /* definitely not a gui */, stereoEye ); + renderLog.CloseMainBlock(); + } + + //------------------------------------------------- + // render debug tools + //------------------------------------------------- + DBG_RenderDebugTools( drawSurfs, numDrawSurfs ); + + // RB: convert back from HDR to LDR range + if( useHDR ) + { + /* + int x = backEnd.viewDef->viewport.x1; + int y = backEnd.viewDef->viewport.y1; + int w = backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1; + int h = backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1; + + GL_Viewport( viewDef->viewport.x1, + viewDef->viewport.y1, + viewDef->viewport.x2 + 1 - viewDef->viewport.x1, + viewDef->viewport.y2 + 1 - viewDef->viewport.y1 ); + */ + + /* + glBindFramebuffer( GL_READ_FRAMEBUFFER, globalFramebuffers.hdrFBO->GetFramebuffer() ); + glBindFramebuffer( GL_DRAW_FRAMEBUFFER, globalFramebuffers.hdrQuarterFBO->GetFramebuffer() ); + glBlitFramebuffer( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), + 0, 0, renderSystem->GetWidth() * 0.25f, renderSystem->GetHeight() * 0.25f, + GL_COLOR_BUFFER_BIT, + GL_LINEAR ); + */ + +#if defined(USE_HDR_MSAA) + if( glConfig.multisamples > 0 ) + { + glBindFramebuffer( GL_READ_FRAMEBUFFER, globalFramebuffers.hdrFBO->GetFramebuffer() ); + glBindFramebuffer( GL_DRAW_FRAMEBUFFER, globalFramebuffers.hdrNonMSAAFBO->GetFramebuffer() ); + glBlitFramebuffer( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), + 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), + GL_COLOR_BUFFER_BIT, + GL_LINEAR ); + + // TODO resolve to 1x1 + glBindFramebuffer( GL_READ_FRAMEBUFFER_EXT, globalFramebuffers.hdrNonMSAAFBO->GetFramebuffer() ); + glBindFramebuffer( GL_DRAW_FRAMEBUFFER_EXT, globalFramebuffers.hdr64FBO->GetFramebuffer() ); + glBlitFramebuffer( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), + 0, 0, 64, 64, + GL_COLOR_BUFFER_BIT, + GL_LINEAR ); + } + else +#endif + { + glBindFramebuffer( GL_READ_FRAMEBUFFER_EXT, globalFramebuffers.hdrFBO->GetFramebuffer() ); + glBindFramebuffer( GL_DRAW_FRAMEBUFFER_EXT, globalFramebuffers.hdr64FBO->GetFramebuffer() ); + glBlitFramebuffer( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), + 0, 0, 64, 64, + GL_COLOR_BUFFER_BIT, + GL_LINEAR ); + } + + CalculateAutomaticExposure(); + + Tonemap( _viewDef ); + } + + Bloom( _viewDef ); + // RB end + + renderLog.CloseBlock(); +} + +/* +================== +RB_MotionBlur + +Experimental feature +================== +*/ +void idRenderBackend::MotionBlur() +{ + if( !viewDef->viewEntitys ) + { + // 3D views only + return; + } + if( r_motionBlur.GetInteger() <= 0 ) + { + return; + } + if( viewDef->isSubview ) + { + return; + } + + GL_CheckErrors(); + + // clear the alpha buffer and draw only the hands + weapon into it so + // we can avoid blurring them + glClearColor( 0, 0, 0, 1 ); + GL_State( GLS_COLORMASK | GLS_DEPTHMASK ); + glClear( GL_COLOR_BUFFER_BIT ); + GL_Color( 0, 0, 0, 0 ); + GL_SelectTexture( 0 ); + globalImages->blackImage->Bind(); + currentSpace = NULL; + + drawSurf_t** drawSurfs = ( drawSurf_t** )&viewDef->drawSurfs[0]; + for( int surfNum = 0; surfNum < viewDef->numDrawSurfs; surfNum++ ) + { + const drawSurf_t* surf = drawSurfs[ surfNum ]; + + if( !surf->space->weaponDepthHack && !surf->space->skipMotionBlur && !surf->material->HasSubview() ) + { + // Apply motion blur to this object + continue; + } + + const idMaterial* shader = surf->material; + if( shader->Coverage() == MC_TRANSLUCENT ) + { + // muzzle flash, etc + continue; + } + + // set mvp matrix + if( surf->space != currentSpace ) + { + RB_SetMVP( surf->space->mvp ); + currentSpace = surf->space; + } + + // this could just be a color, but we don't have a skinned color-only prog + if( surf->jointCache ) + { + renderProgManager.BindShader_TextureVertexColorSkinned(); + } + else + { + renderProgManager.BindShader_TextureVertexColor(); + } + + // draw it solid + DrawElementsWithCounters( surf ); + } + + GL_State( GLS_DEPTHFUNC_ALWAYS ); + + // copy off the color buffer and the depth buffer for the motion blur prog + // we use the viewport dimensions for copying the buffers in case resolution scaling is enabled. + const idScreenRect& viewport = viewDef->viewport; + globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); + + // in stereo rendering, each eye needs to get a separate previous frame mvp + int mvpIndex = ( viewDef->renderView.viewEyeBuffer == 1 ) ? 1 : 0; + + // derive the matrix to go from current pixels to previous frame pixels + idRenderMatrix inverseMVP; + idRenderMatrix::Inverse( viewDef->worldSpace.mvp, inverseMVP ); + + idRenderMatrix motionMatrix; + idRenderMatrix::Multiply( prevMVP[mvpIndex], inverseMVP, motionMatrix ); + + prevMVP[mvpIndex] = viewDef->worldSpace.mvp; + + RB_SetMVP( motionMatrix ); + + GL_State( GLS_DEPTHFUNC_ALWAYS ); + GL_Cull( CT_TWO_SIDED ); + + renderProgManager.BindShader_MotionBlur(); + + // let the fragment program know how many samples we are going to use + idVec4 samples( ( float )( 1 << r_motionBlur.GetInteger() ) ); + SetFragmentParm( RENDERPARM_OVERBRIGHT, samples.ToFloatPtr() ); + + GL_SelectTexture( 0 ); + globalImages->currentRenderImage->Bind(); + GL_SelectTexture( 1 ); + globalImages->currentDepthImage->Bind(); + + DrawElementsWithCounters( &unitSquareSurface ); + GL_CheckErrors(); +} + +/* +================== +idRenderBackend::DrawView + +StereoEye will always be 0 in mono modes, or -1 / 1 in stereo modes. +If the view is a GUI view that is repeated for both eyes, the viewDef.stereoEye value +is 0, so the stereoEye parameter is not always the same as that. +================== +*/ +void idRenderBackend::DrawView( const void* data, const int stereoEye ) +{ + const drawSurfsCommand_t* cmd = ( const drawSurfsCommand_t* )data; + + viewDef = cmd->viewDef; + + // we will need to do a new copyTexSubImage of the screen + // when a SS_POST_PROCESS material is used + currentRenderCopied = false; + + // if there aren't any drawsurfs, do nothing + if( !viewDef->numDrawSurfs ) + { + return; + } + + // skip render bypasses everything that has models, assuming + // them to be 3D views, but leaves 2D rendering visible + if( r_skipRender.GetBool() && viewDef->viewEntitys ) + { + return; + } + + // skip render context sets the wgl context to NULL, + // which should factor out the API cost, under the assumption + // that all gl calls just return if the context isn't valid + + // RB: not really needed + //if( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) + //{ + // GLimp_DeactivateContext(); + //} + // RB end + + pc.c_surfaces += viewDef->numDrawSurfs; + + DBG_ShowOverdraw(); + + // render the scene + DrawViewInternal( cmd->viewDef, stereoEye ); + + MotionBlur(); + + // restore the context for 2D drawing if we were stubbing it out + // RB: not really needed + //if( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) + //{ + // GLimp_ActivateContext(); + // GL_SetDefaultState(); + //} + // RB end + + // optionally draw a box colored based on the eye number + if( r_drawEyeColor.GetBool() ) + { + const idScreenRect& r = viewDef->viewport; + GL_Scissor( ( r.x1 + r.x2 ) / 2, ( r.y1 + r.y2 ) / 2, 32, 32 ); + switch( stereoEye ) + { + case -1: + GL_Clear( true, false, false, 0, 1.0f, 0.0f, 0.0f, 1.0f ); + break; + case 1: + GL_Clear( true, false, false, 0, 0.0f, 1.0f, 0.0f, 1.0f ); + break; + default: + GL_Clear( true, false, false, 0, 0.5f, 0.5f, 0.5f, 1.0f ); + break; + } + } +} + +/* +================== +idRenderBackend::CopyRender + +Copy part of the current framebuffer to an image +================== +*/ +void idRenderBackend::CopyRender( const void* data ) +{ + const copyRenderCommand_t* cmd = ( const copyRenderCommand_t* )data; + + if( r_skipCopyTexture.GetBool() ) + { + return; + } + + RENDERLOG_PRINTF( "***************** RB_CopyRender *****************\n" ); + + if( cmd->image ) + { + cmd->image->CopyFramebuffer( cmd->x, cmd->y, cmd->imageWidth, cmd->imageHeight ); + } + + if( cmd->clearColorAfterCopy ) + { + GL_Clear( true, false, false, STENCIL_SHADOW_TEST_VALUE, 0, 0, 0, 0 ); + } +} + +/* +================== +idRenderBackend::PostProcess + +================== +*/ +extern idCVar rs_enable; +void idRenderBackend::PostProcess( const void* data ) +{ + // only do the post process step if resolution scaling is enabled. Prevents the unnecessary copying of the framebuffer and + // corresponding full screen quad pass. + if( rs_enable.GetInteger() == 0 && !r_useFilmicPostProcessEffects.GetBool() && r_antiAliasing.GetInteger() == 0 ) + { + return; + } + + if( ( r_ssaoDebug.GetInteger() > 0 ) || ( r_ssgiDebug.GetInteger() > 0 ) ) + { + return; + } + + RENDERLOG_PRINTF( "---------- RB_PostProcess() ----------\n" ); + + // resolve the scaled rendering to a temporary texture + postProcessCommand_t* cmd = ( postProcessCommand_t* )data; + const idScreenRect& viewport = cmd->viewDef->viewport; + + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); + GL_Cull( CT_TWO_SIDED ); + + int screenWidth = renderSystem->GetWidth(); + int screenHeight = renderSystem->GetHeight(); + + // set the window clipping + GL_Viewport( 0, 0, screenWidth, screenHeight ); + GL_Scissor( 0, 0, screenWidth, screenHeight ); + + // SMAA + int aaMode = r_antiAliasing.GetInteger(); + if( aaMode == ANTI_ALIASING_SMAA_1X ) + { + /* + * The shader has three passes, chained together as follows: + * + * |input|------------------· + * v | + * [ SMAA*EdgeDetection ] | + * v | + * |edgesTex| | + * v | + * [ SMAABlendingWeightCalculation ] | + * v | + * |blendTex| | + * v | + * [ SMAANeighborhoodBlending ] <------· + * v + * |output| + */ + + globalImages->smaaInputImage->CopyFramebuffer( 0, 0, screenWidth, screenHeight ); + + // set SMAA_RT_METRICS = rpScreenCorrectionFactor + float screenCorrectionParm[4]; + screenCorrectionParm[0] = 1.0f / screenWidth; + screenCorrectionParm[1] = 1.0f / screenHeight; + screenCorrectionParm[2] = screenWidth; + screenCorrectionParm[3] = screenHeight; + SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor + + globalFramebuffers.smaaEdgesFBO->Bind(); + + glClearColor( 0, 0, 0, 0 ); + glClear( GL_COLOR_BUFFER_BIT ); + + GL_SelectTexture( 0 ); + globalImages->smaaInputImage->Bind(); + + renderProgManager.BindShader_SMAA_EdgeDetection(); + DrawElementsWithCounters( &unitSquareSurface ); + +#if 1 + //globalImages->smaaEdgesImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); + + globalFramebuffers.smaaBlendFBO->Bind(); + //Framebuffer::Unbind(); + + glClear( GL_COLOR_BUFFER_BIT ); + + GL_SelectTexture( 0 ); + globalImages->smaaEdgesImage->Bind(); + + GL_SelectTexture( 1 ); + globalImages->smaaAreaImage->Bind(); + + GL_SelectTexture( 2 ); + globalImages->smaaSearchImage->Bind(); + + renderProgManager.BindShader_SMAA_BlendingWeightCalculation(); + DrawElementsWithCounters( &unitSquareSurface ); + + Framebuffer::Unbind(); +#endif + +#if 1 + //GL_SelectTexture( 0 ); + //globalImages->smaaBlendImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); + + GL_SelectTexture( 0 ); + globalImages->smaaInputImage->Bind(); + + GL_SelectTexture( 1 ); + globalImages->smaaBlendImage->Bind(); + + renderProgManager.BindShader_SMAA_NeighborhoodBlending(); + DrawElementsWithCounters( &unitSquareSurface ); +#endif + } + +#if 1 + if( r_useFilmicPostProcessEffects.GetBool() ) + { + globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); + + GL_SelectTexture( 0 ); + globalImages->currentRenderImage->Bind(); + + GL_SelectTexture( 1 ); + globalImages->grainImage1->Bind(); + + renderProgManager.BindShader_PostProcess(); + + const static int GRAIN_SIZE = 128; + + // screen power of two correction factor + float screenCorrectionParm[4]; + screenCorrectionParm[0] = 1.0f / GRAIN_SIZE; + screenCorrectionParm[1] = 1.0f / GRAIN_SIZE; + screenCorrectionParm[2] = 1.0f; + screenCorrectionParm[3] = 1.0f; + SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor + + float jitterTexOffset[4]; + if( r_shadowMapRandomizeJitter.GetBool() ) + { + jitterTexOffset[0] = ( rand() & 255 ) / 255.0; + jitterTexOffset[1] = ( rand() & 255 ) / 255.0; + } + else + { + jitterTexOffset[0] = 0; + jitterTexOffset[1] = 0; + } + jitterTexOffset[2] = 0.0f; + jitterTexOffset[3] = 0.0f; + SetFragmentParm( RENDERPARM_JITTERTEXOFFSET, jitterTexOffset ); // rpJitterTexOffset + + // Draw + DrawElementsWithCounters( &unitSquareSurface ); + } +#endif + + GL_SelectTexture( 0 ); + renderProgManager.Unbind(); + + renderLog.CloseBlock(); +} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderBackend.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderBackend.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderBackend.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderBackend.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,509 @@ +/* +=========================================================================== + +Doom 3 BFG Edition GPL Source Code +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2016-2017 Dustin Land +Copyright (C) 2017 Robert Beckebans + +This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). + +Doom 3 BFG Edition Source Code 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. + +Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . + +In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#ifndef __RENDERER_BACKEND_H__ +#define __RENDERER_BACKEND_H__ + +// RB begin +#define USE_CORE_PROFILE + +bool GL_CheckErrors_( const char* filename, int line ); +#if 1 // !defined(RETAIL) +#define GL_CheckErrors() GL_CheckErrors_(__FILE__, __LINE__) +#else +#define GL_CheckErrors() false +#endif +// RB end + +struct tmu_t +{ + unsigned int current2DMap; + unsigned int current2DArray; + unsigned int currentCubeMap; +}; + +const int MAX_MULTITEXTURE_UNITS = 8; + +enum stencilFace_t +{ + STENCIL_FACE_FRONT, + STENCIL_FACE_BACK, + STENCIL_FACE_NUM +}; + +struct backEndCounters_t +{ + int c_surfaces; + int c_shaders; + + int c_drawElements; + int c_drawIndexes; + + int c_shadowElements; + int c_shadowIndexes; + + int c_copyFrameBuffer; + + float c_overDraw; + + int totalMicroSec; // total microseconds for backend run + int shadowMicroSec; +}; + +struct gfxImpParms_t +{ + int x; // ignored in fullscreen + int y; // ignored in fullscreen + int width; + int height; + int fullScreen; // 0 = windowed, otherwise 1 based monitor number to go full screen on + // -1 = borderless window for spanning multiple displays + int displayHz; + int multiSamples; +}; + +#define MAX_DEBUG_LINES 16384 +#define MAX_DEBUG_TEXT 512 +#define MAX_DEBUG_POLYGONS 8192 + +struct debugLine_t +{ + idVec4 rgb; + idVec3 start; + idVec3 end; + bool depthTest; + int lifeTime; +}; + +struct debugText_t +{ + idStr text; + idVec3 origin; + float scale; + idVec4 color; + idMat3 viewAxis; + int align; + int lifeTime; + bool depthTest; +}; + +struct debugPolygon_t +{ + idVec4 rgb; + idWinding winding; + bool depthTest; + int lifeTime; +}; + +void RB_SetMVP( const idRenderMatrix& mvp ); +void RB_SetVertexColorParms( stageVertexColor_t svc ); +void RB_GetShaderTextureMatrix( const float* shaderRegisters, const textureStage_t* texture, float matrix[16] ); +void RB_LoadShaderTextureMatrix( const float* shaderRegisters, const textureStage_t* texture ); +void RB_BakeTextureMatrixIntoTexgen( idPlane lightProject[3], const float* textureMatrix ); + +//bool ChangeDisplaySettingsIfNeeded( gfxImpParms_t parms ); +//bool CreateGameWindow( gfxImpParms_t parms ); + +#if defined( ID_VULKAN ) + +struct gpuInfo_t +{ + VkPhysicalDevice device; + VkPhysicalDeviceProperties props; + VkPhysicalDeviceMemoryProperties memProps; + VkSurfaceCapabilitiesKHR surfaceCaps; + idList< VkSurfaceFormatKHR > surfaceFormats; + idList< VkPresentModeKHR > presentModes; + idList< VkQueueFamilyProperties > queueFamilyProps; + idList< VkExtensionProperties > extensionProps; +}; + +struct vulkanContext_t +{ + uint64 counter; + uint32 currentFrameData; + + vertCacheHandle_t jointCacheHandle; + uint64 stencilOperations[ STENCIL_FACE_NUM ]; + + VkInstance instance; + VkPhysicalDevice physicalDevice; + VkPhysicalDeviceFeatures physicalDeviceFeatures; + VkDevice device; + VkQueue graphicsQueue; + VkQueue presentQueue; + int graphicsFamilyIdx; + int presentFamilyIdx; + VkDebugReportCallbackEXT callback; + + idList< const char* > instanceExtensions; + idList< const char* > deviceExtensions; + idList< const char* > validationLayers; + + gpuInfo_t* gpu; + idList< gpuInfo_t > gpus; + + VkCommandPool commandPool; + idArray< VkCommandBuffer, NUM_FRAME_DATA > commandBuffer; + idArray< VkFence, NUM_FRAME_DATA > commandBufferFences; + idArray< bool, NUM_FRAME_DATA > commandBufferRecorded; + + VkSurfaceKHR surface; + VkPresentModeKHR presentMode; + VkFormat depthFormat; + VkRenderPass renderPass; + VkPipelineCache pipelineCache; + VkSampleCountFlagBits sampleCount; + bool supersampling; + + int fullscreen; + VkSwapchainKHR swapchain; + VkFormat swapchainFormat; + VkExtent2D swapchainExtent; + uint32 currentSwapIndex; + VkImage msaaImage; + VkImageView msaaImageView; +#if defined( ID_USE_AMD_ALLOCATOR ) + VmaAllocation msaaVmaAllocation; + VmaAllocationInfo msaaAllocation; +#else + vulkanAllocation_t msaaAllocation; +#endif + idArray< idImage*, NUM_FRAME_DATA > swapchainImages; + idArray< VkFramebuffer, NUM_FRAME_DATA > frameBuffers; + idArray< VkSemaphore, NUM_FRAME_DATA > acquireSemaphores; + idArray< VkSemaphore, NUM_FRAME_DATA > renderCompleteSemaphores; + + int currentImageParm; + idArray< idImage*, MAX_IMAGE_PARMS > imageParms; +}; + +extern vulkanContext_t vkcontext; + +#else //if defined( ID_OPENGL ) + +struct glContext_t +{ +// bool bAnisotropicFilterAvailable; +// bool bTextureLODBiasAvailable; + +// float maxTextureAnisotropy; + + tmu_t tmu[ MAX_MULTITEXTURE_UNITS ]; + uint64 stencilOperations[ STENCIL_FACE_NUM ]; +}; + +extern glContext_t glcontext; + +#endif + +/* +=========================================================================== + +idRenderBackend + +all state modified by the back end is separated from the front end state + +=========================================================================== +*/ +class idRenderBackend +{ + friend class Framebuffer; + +public: + idRenderBackend(); + ~idRenderBackend(); + + void Init(); + void Shutdown(); + + void ExecuteBackEndCommands( const emptyCommand_t* cmds ); + void StereoRenderExecuteBackEndCommands( const emptyCommand_t* const allCmds ); + void BlockingSwapBuffers(); + + void Print(); + void CheckCVars(); + +private: + void DrawFlickerBox(); + + void DrawElementsWithCounters( const drawSurf_t* surf ); + void DrawStencilShadowPass( const drawSurf_t* drawSurf, const bool renderZPass ); + + void SetColorMappings(); + void ResizeImages(); + + void DrawViewInternal( const viewDef_t* viewDef, const int stereoEye ); + void DrawView( const void* data, const int stereoEye ); + void CopyRender( const void* data ); + + void BindVariableStageImage( const textureStage_t* texture, const float* shaderRegisters ); + void PrepareStageTexturing( const shaderStage_t* pStage, const drawSurf_t* surf ); + void FinishStageTexturing( const shaderStage_t* pStage, const drawSurf_t* surf ); + + void ResetViewportAndScissorToDefaultCamera( const viewDef_t* _viewDef ); + + void FillDepthBufferGeneric( const drawSurf_t* const* drawSurfs, int numDrawSurfs ); + void FillDepthBufferFast( drawSurf_t** drawSurfs, int numDrawSurfs ); + + void T_BlendLight( const drawSurf_t* drawSurfs, const viewLight_t* vLight ); + void BlendLight( const drawSurf_t* drawSurfs, const drawSurf_t* drawSurfs2, const viewLight_t* vLight ); + void T_BasicFog( const drawSurf_t* drawSurfs, const idPlane fogPlanes[ 4 ], const idRenderMatrix* inverseBaseLightProject ); + void FogPass( const drawSurf_t* drawSurfs, const drawSurf_t* drawSurfs2, const viewLight_t* vLight ); + void FogAllLights(); + + void SetupInteractionStage( const shaderStage_t* surfaceStage, const float* surfaceRegs, const float lightColor[4], + idVec4 matrix[2], float color[4] ); + + void DrawInteractions( const viewDef_t* _viewDef ); + void DrawSingleInteraction( drawInteraction_t* din ); + int DrawShaderPasses( const drawSurf_t* const* const drawSurfs, const int numDrawSurfs, + const float guiStereoScreenOffset, const int stereoEye ); + + void RenderInteractions( const drawSurf_t* surfList, const viewLight_t* vLight, int depthFunc, bool performStencilTest, bool useLightDepthBounds ); + + // RB + void AmbientPass( const drawSurf_t* const* drawSurfs, int numDrawSurfs, bool fillGbuffer ); + void ShadowMapPass( const drawSurf_t* drawSurfs, const viewLight_t* vLight, int side ); + + void StencilShadowPass( const drawSurf_t* drawSurfs, const viewLight_t* vLight ); + void StencilSelectLight( const viewLight_t* vLight ); + + // RB: HDR stuff + + // TODO optimize and replace with compute shader + void CalculateAutomaticExposure(); + void Tonemap( const viewDef_t* viewDef ); + void Bloom( const viewDef_t* viewDef ); + + void DrawScreenSpaceAmbientOcclusion( const viewDef_t* _viewDef ); + void DrawScreenSpaceGlobalIllumination( const viewDef_t* _viewDef ); + + // Experimental feature + void MotionBlur(); + void PostProcess( const void* data ); + +private: + void GL_StartFrame(); + void GL_EndFrame(); + + uint64 GL_GetCurrentState() const; + uint64 GL_GetCurrentStateMinusStencil() const; + void GL_SetDefaultState(); + + void GL_State( uint64 stateBits, bool forceGlState = false ); + void GL_SeparateStencil( stencilFace_t face, uint64 stencilBits ); + void GL_Cull( cullType_t cullType ); // TODO remove + + void GL_SelectTexture( int unit ); +// void GL_BindTexture( idImage* image ); + +// void GL_CopyFrameBuffer( idImage* image, int x, int y, int imageWidth, int imageHeight ); +// void GL_CopyDepthBuffer( idImage* image, int x, int y, int imageWidth, int imageHeight ); + + // RB: HDR parm + void GL_Clear( bool color, bool depth, bool stencil, byte stencilValue, float r, float g, float b, float a, bool clearHDR = true ); + + void GL_DepthBoundsTest( const float zmin, const float zmax ); + void GL_PolygonOffset( float scale, float bias ); + + void GL_Scissor( int x /* left*/, int y /* bottom */, int w, int h ); + void GL_Viewport( int x /* left */, int y /* bottom */, int w, int h ); + + ID_INLINE void GL_Scissor( const idScreenRect& rect ) + { + GL_Scissor( rect.x1, rect.y1, rect.x2 - rect.x1 + 1, rect.y2 - rect.y1 + 1 ); + } + ID_INLINE void GL_Viewport( const idScreenRect& rect ) + { + GL_Viewport( rect.x1, rect.y1, rect.x2 - rect.x1 + 1, rect.y2 - rect.y1 + 1 ); + } + + ID_INLINE void GL_ViewportAndScissor( int x, int y, int w, int h ) + { + GL_Viewport( x, y, w, h ); + GL_Scissor( x, y, w, h ); + } + + ID_INLINE void GL_ViewportAndScissor( const idScreenRect& rect ) + { + GL_Viewport( rect ); + GL_Scissor( rect ); + } + + void GL_Color( float r, float g, float b, float a ); + ID_INLINE void GL_Color( float r, float g, float b ) + { + GL_Color( r, g, b, 1.0f ); + } + + ID_INLINE void GL_Color( const idVec3& color ) + { + GL_Color( color[0], color[1], color[2], 1.0f ); + } + + ID_INLINE void GL_Color( const idVec4& color ) + { + GL_Color( color[0], color[1], color[2], color[3] ); + } + +// void GL_Color( float* color ); + + void SetBuffer( const void* data ); + +private: + void DBG_SimpleSurfaceSetup( const drawSurf_t* drawSurf ); + void DBG_SimpleWorldSetup(); + void DBG_PolygonClear(); + void DBG_ShowDestinationAlpha(); + void DBG_ScanStencilBuffer(); + void DBG_CountStencilBuffer(); + void DBG_ColorByStencilBuffer(); + void DBG_ShowOverdraw(); + void DBG_ShowIntensity(); + void DBG_ShowDepthBuffer(); + void DBG_ShowLightCount(); +// void DBG_EnterWeaponDepthHack(); +// void DBG_EnterModelDepthHack( float depth ); +// void DBG_LeaveDepthHack(); + void DBG_RenderDrawSurfListWithFunction( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_ShowSilhouette(); + void DBG_ShowTris( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_ShowSurfaceInfo( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_ShowViewEntitys( viewEntity_t* vModels ); + void DBG_ShowTexturePolarity( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_ShowUnsmoothedTangents( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_ShowTangentSpace( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_ShowVertexColor( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_ShowNormals( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_ShowTextureVectors( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_ShowDominantTris( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_ShowEdges( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_ShowLights(); + void DBG_ShowShadowMapLODs(); // RB + void DBG_ShowPortals(); + + void DBG_ShowDebugText(); + void DBG_ShowDebugLines(); + void DBG_ShowDebugPolygons(); + + void DBG_ShowCenterOfProjection(); + void DBG_ShowLines(); + + void DBG_TestGamma(); + void DBG_TestGammaBias(); + void DBG_TestImage(); + void DBG_ShowShadowMaps(); // RB + void DBG_ShowTrace( drawSurf_t** drawSurfs, int numDrawSurfs ); + void DBG_RenderDebugTools( drawSurf_t** drawSurfs, int numDrawSurfs ); + +public: + backEndCounters_t pc; + + // surfaces used for code-based drawing + drawSurf_t unitSquareSurface; + drawSurf_t zeroOneCubeSurface; + drawSurf_t testImageSurface; + +private: + uint64 glStateBits; + + const viewDef_t* viewDef; + + const viewEntity_t* currentSpace; // for detecting when a matrix must change + idScreenRect currentScissor; // for scissor clipping, local inside renderView viewport + + bool currentRenderCopied; // true if any material has already referenced _currentRender + + idRenderMatrix prevMVP[2]; // world MVP from previous frame for motion blur + + // RB begin + idRenderMatrix shadowV[6]; // shadow depth view matrix + idRenderMatrix shadowP[6]; // shadow depth projection matrix + + float hdrAverageLuminance; + float hdrMaxLuminance; + float hdrTime; + float hdrKey; + // RB end + +private: +#if !defined( USE_VULKAN ) + int currenttmu; + + unsigned int currentVertexBuffer; + unsigned int currentIndexBuffer; + Framebuffer* currentFramebuffer; // RB: for offscreen rendering + + int faceCulling; + vertexLayoutType_t vertexLayout; + + float polyOfsScale; + float polyOfsBias; + +public: + int GetCurrentTextureUnit() const + { + return currenttmu; + } + +#if 0 + unsigned short gammaTable[ 256 ]; // brightness / gamma modify this + + idStr rendererString; + idStr vendorString; + idStr versionString; + idStr extensionsString; + idStr wglExtensionsString; + idStr shadingLanguageString; + + float glVersion; // atof( version_string ) + graphicsVendor_t vendor; + + int maxTextureSize; // queried from GL + int maxTextureCoords; + int maxTextureImageUnits; + int uniformBufferOffsetAlignment; + + int colorBits; + int depthBits; + int stencilBits; + + bool depthBoundsTestAvailable; + bool timerQueryAvailable; + bool swapControlTearAvailable; + + int displayFrequency; +#endif + +#endif // !defined( USE_VULKAN ) +}; + +#endif \ No newline at end of file diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderCommon.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderCommon.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderCommon.h 1970-01-01 00:00:00.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderCommon.h 2018-10-13 10:08:18.000000000 +0000 @@ -0,0 +1,1470 @@ +/* +=========================================================================== + +Doom 3 BFG Edition GPL Source Code +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2012-2016 Robert Beckebans +Copyright (C) 2014-2016 Kot in Action Creative Artel + +This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). + +Doom 3 BFG Edition Source Code 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. + +Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . + +In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#ifndef __TR_LOCAL_H__ +#define __TR_LOCAL_H__ + +#include "precompiled.h" + +#include "GLState.h" +#include "ScreenRect.h" +#include "Image.h" +#include "Font.h" +#include "Framebuffer.h" + +// everything that is needed by the backend needs +// to be double buffered to allow it to run in +// parallel on a dual cpu machine +const int SMP_FRAMES = 1; + +// maximum texture units +const int MAX_PROG_TEXTURE_PARMS = 16; + +const int FALLOFF_TEXTURE_SIZE = 64; + +const float DEFAULT_FOG_DISTANCE = 500.0f; + +// picky to get the bilerp correct at terminator +const int FOG_ENTER_SIZE = 64; +const float FOG_ENTER = ( FOG_ENTER_SIZE + 1.0f ) / ( FOG_ENTER_SIZE * 2 ); + +enum demoCommand_t +{ + DC_BAD, + DC_RENDERVIEW, + DC_UPDATE_ENTITYDEF, + DC_DELETE_ENTITYDEF, + DC_UPDATE_LIGHTDEF, + DC_DELETE_LIGHTDEF, + DC_LOADMAP, + DC_CROP_RENDER, + DC_UNCROP_RENDER, + DC_CAPTURE_RENDER, + DC_END_FRAME, + DC_DEFINE_MODEL, + DC_SET_PORTAL_STATE, + DC_UPDATE_SOUNDOCCLUSION, + DC_GUI_MODEL, + DC_UPDATE_DECAL, + DC_DELETE_DECAL, + DC_UPDATE_OVERLAY, + DC_DELETE_OVERLAY, + DC_CACHE_SKINS, + DC_CACHE_PARTICLES, + DC_CACHE_MATERIALS, +}; + +/* +============================================================================== + +SURFACES + +============================================================================== +*/ + +#include "ModelDecal.h" +#include "ModelOverlay.h" +#include "Interaction.h" + +class idRenderWorldLocal; +struct viewEntity_t; +struct viewLight_t; + +// drawSurf_t structures command the back end to render surfaces +// a given srfTriangles_t may be used with multiple viewEntity_t, +// as when viewed in a subview or multiple viewport render, or +// with multiple shaders when skinned, or, possibly with multiple +// lights, although currently each lighting interaction creates +// unique srfTriangles_t +// drawSurf_t are always allocated and freed every frame, they are never cached + +struct drawSurf_t +{ + const srfTriangles_t* frontEndGeo; // don't use on the back end, it may be updated by the front end! + int numIndexes; + vertCacheHandle_t indexCache; // triIndex_t + vertCacheHandle_t ambientCache; // idDrawVert + vertCacheHandle_t shadowCache; // idShadowVert / idShadowVertSkinned + vertCacheHandle_t jointCache; // idJointMat + const viewEntity_t* space; + const idMaterial* material; // may be NULL for shadow volumes + uint64 extraGLState; // Extra GL state |'d with material->stage[].drawStateBits + float sort; // material->sort, modified by gui / entity sort offsets + const float* shaderRegisters; // evaluated and adjusted for referenceShaders + drawSurf_t* nextOnLight; // viewLight chains + drawSurf_t** linkChain; // defer linking to lights to a serial section to avoid a mutex + idScreenRect scissorRect; // for scissor clipping, local inside renderView viewport + int renderZFail; + volatile shadowVolumeState_t shadowVolumeState; +}; + +// areas have references to hold all the lights and entities in them +struct areaReference_t +{ + areaReference_t* areaNext; // chain in the area + areaReference_t* areaPrev; + areaReference_t* ownerNext; // chain on either the entityDef or lightDef + idRenderEntityLocal* entity; // only one of entity / light will be non-NULL + idRenderLightLocal* light; // only one of entity / light will be non-NULL + struct portalArea_s* area; // so owners can find all the areas they are in +}; + + +// idRenderLight should become the new public interface replacing the qhandle_t to light defs in the idRenderWorld interface +class idRenderLight +{ +public: + virtual ~idRenderLight() {} + + virtual void FreeRenderLight() = 0; + virtual void UpdateRenderLight( const renderLight_t* re, bool forceUpdate = false ) = 0; + virtual void GetRenderLight( renderLight_t* re ) = 0; + virtual void ForceUpdate() = 0; + virtual int GetIndex() = 0; +}; + + +// idRenderEntity should become the new public interface replacing the qhandle_t to entity defs in the idRenderWorld interface +class idRenderEntity +{ +public: + virtual ~idRenderEntity() {} + + virtual void FreeRenderEntity() = 0; + virtual void UpdateRenderEntity( const renderEntity_t* re, bool forceUpdate = false ) = 0; + virtual void GetRenderEntity( renderEntity_t* re ) = 0; + virtual void ForceUpdate() = 0; + virtual int GetIndex() = 0; + + // overlays are extra polygons that deform with animating models for blood and damage marks + virtual void ProjectOverlay( const idPlane localTextureAxis[2], const idMaterial* material ) = 0; + virtual void RemoveDecals() = 0; +}; + + +class idRenderLightLocal : public idRenderLight +{ +public: + idRenderLightLocal(); + + virtual void FreeRenderLight(); + virtual void UpdateRenderLight( const renderLight_t* re, bool forceUpdate = false ); + virtual void GetRenderLight( renderLight_t* re ); + virtual void ForceUpdate(); + virtual int GetIndex(); + + bool LightCastsShadows() const + { + return parms.forceShadows || ( !parms.noShadows && lightShader->LightCastsShadows() ); + } + + renderLight_t parms; // specification + + bool lightHasMoved; // the light has changed its position since it was + // first added, so the prelight model is not valid + idRenderWorldLocal* world; + int index; // in world lightdefs + + int areaNum; // if not -1, we may be able to cull all the light's + // interactions if !viewDef->connectedAreas[areaNum] + + int lastModifiedFrameNum; // to determine if it is constantly changing, + // and should go in the dynamic frame memory, or kept + // in the cached memory + bool archived; // for demo writing + + + // derived information + idPlane lightProject[4]; // old style light projection where Z and W are flipped and projected lights lightProject[3] is divided by ( zNear + zFar ) + idRenderMatrix baseLightProject; // global xyz1 to projected light strq + idRenderMatrix inverseBaseLightProject;// transforms the zero-to-one cube to exactly cover the light in world space + + const idMaterial* lightShader; // guaranteed to be valid, even if parms.shader isn't + idImage* falloffImage; + + idVec3 globalLightOrigin; // accounting for lightCenter and parallel + idBounds globalLightBounds; + + int viewCount; // if == tr.viewCount, the light is on the viewDef->viewLights list + viewLight_t* viewLight; + + areaReference_t* references; // each area the light is present in will have a lightRef + idInteraction* firstInteraction; // doubly linked list + idInteraction* lastInteraction; + + struct doublePortal_s* foggedPortals; +}; + + +class idRenderEntityLocal : public idRenderEntity +{ +public: + idRenderEntityLocal(); + + virtual void FreeRenderEntity(); + virtual void UpdateRenderEntity( const renderEntity_t* re, bool forceUpdate = false ); + virtual void GetRenderEntity( renderEntity_t* re ); + virtual void ForceUpdate(); + virtual int GetIndex(); + + // overlays are extra polygons that deform with animating models for blood and damage marks + virtual void ProjectOverlay( const idPlane localTextureAxis[2], const idMaterial* material ); + virtual void RemoveDecals(); + + bool IsDirectlyVisible() const; + void ReadFromDemoFile( class idDemoFile* f ); + void WriteToDemoFile( class idDemoFile* f ) const; + renderEntity_t parms; + + float modelMatrix[16]; // this is just a rearrangement of parms.axis and parms.origin + idRenderMatrix modelRenderMatrix; + idRenderMatrix inverseBaseModelProject;// transforms the unit cube to exactly cover the model in world space + + idRenderWorldLocal* world; + int index; // in world entityDefs + + int lastModifiedFrameNum; // to determine if it is constantly changing, + // and should go in the dynamic frame memory, or kept + // in the cached memory + bool archived; // for demo writing + + idRenderModel* dynamicModel; // if parms.model->IsDynamicModel(), this is the generated data + int dynamicModelFrameCount; // continuously animating dynamic models will recreate + // dynamicModel if this doesn't == tr.viewCount + idRenderModel* cachedDynamicModel; + + + // the local bounds used to place entityRefs, either from parms for dynamic entities, or a model bounds + idBounds localReferenceBounds; + + // axis aligned bounding box in world space, derived from refernceBounds and + // modelMatrix in R_CreateEntityRefs() + idBounds globalReferenceBounds; + + // a viewEntity_t is created whenever a idRenderEntityLocal is considered for inclusion + // in a given view, even if it turns out to not be visible + int viewCount; // if tr.viewCount == viewCount, viewEntity is valid, + // but the entity may still be off screen + viewEntity_t* viewEntity; // in frame temporary memory + + idRenderModelDecal* decals; // decals that have been projected on this model + idRenderModelOverlay* overlays; // blood overlays on animated models + + areaReference_t* entityRefs; // chain of all references + idInteraction* firstInteraction; // doubly linked list + idInteraction* lastInteraction; + + bool needsPortalSky; +}; + +struct shadowOnlyEntity_t +{ + shadowOnlyEntity_t* next; + idRenderEntityLocal* edef; +}; + +// viewLights are allocated on the frame temporary stack memory +// a viewLight contains everything that the back end needs out of an idRenderLightLocal, +// which the front end may be modifying simultaniously if running in SMP mode. +// a viewLight may exist even without any surfaces, and may be relevent for fogging, +// but should never exist if its volume does not intersect the view frustum +struct viewLight_t +{ + viewLight_t* next; + + // back end should NOT reference the lightDef, because it can change when running SMP + idRenderLightLocal* lightDef; + + // for scissor clipping, local inside renderView viewport + // scissorRect.Empty() is true if the viewEntity_t was never actually + // seen through any portals + idScreenRect scissorRect; + + // R_AddSingleLight() determined that the light isn't actually needed + bool removeFromList; + + // R_AddSingleLight builds this list of entities that need to be added + // to the viewEntities list because they potentially cast shadows into + // the view, even though the aren't directly visible + shadowOnlyEntity_t* shadowOnlyViewEntities; + + enum interactionState_t + { + INTERACTION_UNCHECKED, + INTERACTION_NO, + INTERACTION_YES + }; + byte* entityInteractionState; // [numEntities] + + idVec3 globalLightOrigin; // global light origin used by backend + idPlane lightProject[4]; // light project used by backend + idPlane fogPlane; // fog plane for backend fog volume rendering + // RB: added for shadow mapping + idRenderMatrix baseLightProject; // global xyz1 to projected light strq + bool pointLight; // otherwise a projection light (should probably invert the sense of this, because points are way more common) + bool parallel; // lightCenter gives the direction to the light at infinity + idVec3 lightCenter; // offset the lighting direction for shading and + int shadowLOD; // level of detail for shadowmap selection + // RB end + idRenderMatrix inverseBaseLightProject; // the matrix for deforming the 'zeroOneCubeModel' to exactly cover the light volume in world space + const idMaterial* lightShader; // light shader used by backend + const float* shaderRegisters; // shader registers used by backend + idImage* falloffImage; // falloff image used by backend + + drawSurf_t* globalShadows; // shadow everything + drawSurf_t* localInteractions; // don't get local shadows + drawSurf_t* localShadows; // don't shadow local surfaces + drawSurf_t* globalInteractions; // get shadows from everything + drawSurf_t* translucentInteractions; // translucent interactions don't get shadows + + // R_AddSingleLight will build a chain of parameters here to setup shadow volumes + preLightShadowVolumeParms_t* preLightShadowVolumes; +}; + +// a viewEntity is created whenever a idRenderEntityLocal is considered for inclusion +// in the current view, but it may still turn out to be culled. +// viewEntity are allocated on the frame temporary stack memory +// a viewEntity contains everything that the back end needs out of a idRenderEntityLocal, +// which the front end may be modifying simultaneously if running in SMP mode. +// A single entityDef can generate multiple viewEntity_t in a single frame, as when seen in a mirror +struct viewEntity_t +{ + viewEntity_t* next; + + // back end should NOT reference the entityDef, because it can change when running SMP + idRenderEntityLocal* entityDef; + + // for scissor clipping, local inside renderView viewport + // scissorRect.Empty() is true if the viewEntity_t was never actually + // seen through any portals, but was created for shadow casting. + // a viewEntity can have a non-empty scissorRect, meaning that an area + // that it is in is visible, and still not be visible. + idScreenRect scissorRect; + + bool isGuiSurface; // force two sided and vertex colors regardless of material setting + + bool skipMotionBlur; + + bool weaponDepthHack; + float modelDepthHack; + + float modelMatrix[16]; // local coords to global coords + float modelViewMatrix[16]; // local coords to eye coords + + idRenderMatrix mvp; + + // parallelAddModels will build a chain of surfaces here that will need to + // be linked to the lights or added to the drawsurf list in a serial code section + drawSurf_t* drawSurfs; + + // R_AddSingleModel will build a chain of parameters here to setup shadow volumes + staticShadowVolumeParms_t* staticShadowVolumes; + dynamicShadowVolumeParms_t* dynamicShadowVolumes; +}; + + +const int MAX_CLIP_PLANES = 1; // we may expand this to six for some subview issues + +// RB: added multiple subfrustums for cascaded shadow mapping +enum frustumPlanes_t +{ + FRUSTUM_PLANE_LEFT, + FRUSTUM_PLANE_RIGHT, + FRUSTUM_PLANE_BOTTOM, + FRUSTUM_PLANE_TOP, + FRUSTUM_PLANE_NEAR, + FRUSTUM_PLANE_FAR, + FRUSTUM_PLANES = 6, + FRUSTUM_CLIPALL = 1 | 2 | 4 | 8 | 16 | 32 +}; + +enum +{ + FRUSTUM_PRIMARY, + FRUSTUM_CASCADE1, + FRUSTUM_CASCADE2, + FRUSTUM_CASCADE3, + FRUSTUM_CASCADE4, + FRUSTUM_CASCADE5, + MAX_FRUSTUMS, +}; + +typedef idPlane frustum_t[FRUSTUM_PLANES]; +// RB end + +// viewDefs are allocated on the frame temporary stack memory +struct viewDef_t +{ + // specified in the call to DrawScene() + renderView_t renderView; + + float projectionMatrix[16]; + idRenderMatrix projectionRenderMatrix; // tech5 version of projectionMatrix + + // RB begin + float unprojectionToCameraMatrix[16]; + idRenderMatrix unprojectionToCameraRenderMatrix; + + float unprojectionToWorldMatrix[16]; + idRenderMatrix unprojectionToWorldRenderMatrix; + // RB end + + viewEntity_t worldSpace; + + idRenderWorldLocal* renderWorld; + + idVec3 initialViewAreaOrigin; + // Used to find the portalArea that view flooding will take place from. + // for a normal view, the initialViewOrigin will be renderView.viewOrg, + // but a mirror may put the projection origin outside + // of any valid area, or in an unconnected area of the map, so the view + // area must be based on a point just off the surface of the mirror / subview. + // It may be possible to get a failed portal pass if the plane of the + // mirror intersects a portal, and the initialViewAreaOrigin is on + // a different side than the renderView.viewOrg is. + + bool isSubview; // true if this view is not the main view + bool isMirror; // the portal is a mirror, invert the face culling + bool isXraySubview; + + bool isEditor; + bool is2Dgui; + + int numClipPlanes; // mirrors will often use a single clip plane + idPlane clipPlanes[MAX_CLIP_PLANES]; // in world space, the positive side + // of the plane is the visible side + idScreenRect viewport; // in real pixels and proper Y flip + + idScreenRect scissor; + // for scissor clipping, local inside renderView viewport + // subviews may only be rendering part of the main view + // these are real physical pixel values, possibly scaled and offset from the + // renderView x/y/width/height + + viewDef_t* superView; // never go into an infinite subview loop + const drawSurf_t* subviewSurface; + + // drawSurfs are the visible surfaces of the viewEntities, sorted + // by the material sort parameter + drawSurf_t** drawSurfs; // we don't use an idList for this, because + int numDrawSurfs; // it is allocated in frame temporary memory + int maxDrawSurfs; // may be resized + + viewLight_t* viewLights; // chain of all viewLights effecting view + viewEntity_t* viewEntitys; // chain of all viewEntities effecting view, including off screen ones casting shadows + // we use viewEntities as a check to see if a given view consists solely + // of 2D rendering, which we can optimize in certain ways. A 2D view will + // not have any viewEntities + + // RB begin + frustum_t frustums[MAX_FRUSTUMS]; // positive sides face outward, [4] is the front clip plane + float frustumSplitDistances[MAX_FRUSTUMS]; + idRenderMatrix frustumMVPs[MAX_FRUSTUMS]; + // RB end + + int areaNum; // -1 = not in a valid area + + // An array in frame temporary memory that lists if an area can be reached without + // crossing a closed door. This is used to avoid drawing interactions + // when the light is behind a closed door. + bool* connectedAreas; +}; + + +// complex light / surface interactions are broken up into multiple passes of a +// simple interaction shader +struct drawInteraction_t +{ + const drawSurf_t* surf; + + idImage* bumpImage; + idImage* diffuseImage; + idImage* specularImage; + + idVec4 diffuseColor; // may have a light color baked into it + idVec4 specularColor; // may have a light color baked into it + stageVertexColor_t vertexColor; // applies to both diffuse and specular + + int ambientLight; // use tr.ambientNormalMap instead of normalization cube map + + // these are loaded into the vertex program + idVec4 bumpMatrix[2]; + idVec4 diffuseMatrix[2]; + idVec4 specularMatrix[2]; +}; + +/* +============================================================= + +RENDERER BACK END COMMAND QUEUE + +TR_CMDS + +============================================================= +*/ + +enum renderCommand_t +{ + RC_NOP, + RC_DRAW_VIEW_3D, // may be at a reduced resolution, will be upsampled before 2D GUIs + RC_DRAW_VIEW_GUI, // not resolution scaled + RC_SET_BUFFER, + RC_COPY_RENDER, + RC_POST_PROCESS, +}; + +struct emptyCommand_t +{ + renderCommand_t commandId; + renderCommand_t* next; +}; + +struct setBufferCommand_t +{ + renderCommand_t commandId; + renderCommand_t* next; + GLenum buffer; +}; + +struct drawSurfsCommand_t +{ + renderCommand_t commandId; + renderCommand_t* next; + viewDef_t* viewDef; +}; + +struct copyRenderCommand_t +{ + renderCommand_t commandId; + renderCommand_t* next; + int x; + int y; + int imageWidth; + int imageHeight; + idImage* image; + int cubeFace; // when copying to a cubeMap + bool clearColorAfterCopy; +}; + +struct postProcessCommand_t +{ + renderCommand_t commandId; + renderCommand_t* next; + viewDef_t* viewDef; +}; + +//======================================================================= + +// this is the inital allocation for max number of drawsurfs +// in a given view, but it will automatically grow if needed +const int INITIAL_DRAWSURFS = 2048; + +enum frameAllocType_t +{ + FRAME_ALLOC_VIEW_DEF, + FRAME_ALLOC_VIEW_ENTITY, + FRAME_ALLOC_VIEW_LIGHT, + FRAME_ALLOC_SURFACE_TRIANGLES, + FRAME_ALLOC_DRAW_SURFACE, + FRAME_ALLOC_INTERACTION_STATE, + FRAME_ALLOC_SHADOW_ONLY_ENTITY, + FRAME_ALLOC_SHADOW_VOLUME_PARMS, + FRAME_ALLOC_SHADER_REGISTER, + FRAME_ALLOC_DRAW_SURFACE_POINTER, + FRAME_ALLOC_DRAW_COMMAND, + FRAME_ALLOC_UNKNOWN, + FRAME_ALLOC_MAX +}; + +// all of the information needed by the back end must be +// contained in a idFrameData. This entire structure is +// duplicated so the front and back end can run in parallel +// on an SMP machine. +class idFrameData +{ +public: + idSysInterlockedInteger frameMemoryAllocated; + idSysInterlockedInteger frameMemoryUsed; + byte* frameMemory; + + int highWaterAllocated; // max used on any frame + int highWaterUsed; + + // the currently building command list commands can be inserted + // at the front if needed, as required for dynamically generated textures + emptyCommand_t* cmdHead; // may be of other command type based on commandId + emptyCommand_t* cmdTail; +}; + +extern idFrameData* frameData; + +//======================================================================= + +void R_AddDrawViewCmd( viewDef_t* parms, bool guiOnly ); +void R_AddDrawPostProcess( viewDef_t* parms ); + +void R_ReloadGuis_f( const idCmdArgs& args ); +void R_ListGuis_f( const idCmdArgs& args ); + +void* R_GetCommandBuffer( int bytes ); + +// this allows a global override of all materials +bool R_GlobalShaderOverride( const idMaterial** shader ); + +// this does various checks before calling the idDeclSkin +const idMaterial* R_RemapShaderBySkin( const idMaterial* shader, const idDeclSkin* customSkin, const idMaterial* customShader ); + + +//==================================================== + + +/* +** performanceCounters_t +*/ +struct performanceCounters_t +{ + int c_box_cull_in; + int c_box_cull_out; + int c_createInteractions; // number of calls to idInteraction::CreateInteraction + int c_createShadowVolumes; + int c_generateMd5; + int c_entityDefCallbacks; + int c_alloc; // counts for R_StaticAllc/R_StaticFree + int c_free; + int c_visibleViewEntities; + int c_shadowViewEntities; + int c_viewLights; + int c_numViews; // number of total views rendered + int c_deformedSurfaces; // idMD5Mesh::GenerateSurface + int c_deformedVerts; // idMD5Mesh::GenerateSurface + int c_deformedIndexes; // idMD5Mesh::GenerateSurface + int c_tangentIndexes; // R_DeriveTangents() + int c_entityUpdates; + int c_lightUpdates; + int c_entityReferences; + int c_lightReferences; + int c_guiSurfs; + int frontEndMicroSec; // sum of time in all RE_RenderScene's in a frame +}; + + + +enum vertexLayoutType_t +{ + LAYOUT_UNKNOWN = 0, + LAYOUT_DRAW_VERT, + LAYOUT_DRAW_SHADOW_VERT, + LAYOUT_DRAW_SHADOW_VERT_SKINNED +}; + +/* +struct glstate_t +{ + tmu_t tmu[MAX_MULTITEXTURE_UNITS]; + + int currenttmu; + + int faceCulling; + + vertexLayoutType_t vertexLayout; + + // RB: 64 bit fixes, changed unsigned int to uintptr_t + uintptr_t currentVertexBuffer; + uintptr_t currentIndexBuffer; + + Framebuffer* currentFramebuffer; + // RB end + + float polyOfsScale; + float polyOfsBias; + + uint64 glStateBits; +}; +*/ + +class idParallelJobList; + +const int MAX_GUI_SURFACES = 1024; // default size of the drawSurfs list for guis, will +// be automatically expanded as needed + +static const int MAX_RENDER_CROPS = 8; + +#include "RenderBackend.h" + +/* +** Most renderer globals are defined here. +** backend functions should never modify any of these fields, +** but may read fields that aren't dynamically modified +** by the frontend. +*/ +class idRenderSystemLocal : public idRenderSystem +{ +public: + // external functions + virtual void Init(); + virtual void Shutdown(); + virtual void ResetGuiModels(); + virtual void InitOpenGL(); + virtual void ShutdownOpenGL(); + virtual bool IsOpenGLRunning() const; + virtual bool IsFullScreen() const; + virtual stereo3DMode_t GetStereo3DMode() const; + virtual bool HasQuadBufferSupport() const; + virtual bool IsStereoScopicRenderingSupported() const; + virtual stereo3DMode_t GetStereoScopicRenderingMode() const; + virtual void EnableStereoScopicRendering( const stereo3DMode_t mode ) const; + virtual int GetWidth() const; + virtual int GetHeight() const; + virtual int GetVirtualWidth() const; + virtual int GetVirtualHeight() const; + virtual float GetPixelAspect() const; + virtual float GetPhysicalScreenWidthInCentimeters() const; + virtual idRenderWorld* AllocRenderWorld(); + virtual void FreeRenderWorld( idRenderWorld* rw ); + virtual void BeginLevelLoad(); + virtual void EndLevelLoad(); + virtual void LoadLevelImages(); + virtual void Preload( const idPreloadManifest& manifest, const char* mapName ); + virtual void BeginAutomaticBackgroundSwaps( autoRenderIconType_t icon = AUTORENDER_DEFAULTICON ); + virtual void EndAutomaticBackgroundSwaps(); + virtual bool AreAutomaticBackgroundSwapsRunning( autoRenderIconType_t* usingAlternateIcon = NULL ) const; + + virtual idFont* RegisterFont( const char* fontName ); + virtual void ResetFonts(); + virtual void PrintMemInfo( MemInfo_t* mi ); + + virtual void SetColor( const idVec4& color ); + virtual uint32 GetColor(); + virtual void SetGLState( const uint64 glState ) ; + virtual void DrawFilled( const idVec4& color, float x, float y, float w, float h ); + virtual void DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial* material ); + virtual void DrawStretchPic( const idVec4& topLeft, const idVec4& topRight, const idVec4& bottomRight, const idVec4& bottomLeft, const idMaterial* material ); + virtual void DrawStretchTri( const idVec2& p1, const idVec2& p2, const idVec2& p3, const idVec2& t1, const idVec2& t2, const idVec2& t3, const idMaterial* material ); + virtual idDrawVert* AllocTris( int numVerts, const triIndex_t* indexes, int numIndexes, const idMaterial* material, const stereoDepthType_t stereoType = STEREO_DEPTH_TYPE_NONE ); + virtual void DrawSmallChar( int x, int y, int ch ); + virtual void DrawSmallStringExt( int x, int y, const char* string, const idVec4& setColor, bool forceColor ); + virtual void DrawBigChar( int x, int y, int ch ); + virtual void DrawBigStringExt( int x, int y, const char* string, const idVec4& setColor, bool forceColor ); + + virtual void WriteDemoPics(); + virtual void WriteEndFrame(); + virtual void DrawDemoPics(); + virtual const emptyCommand_t* SwapCommandBuffers( uint64* frontEndMicroSec, uint64* backEndMicroSec, uint64* shadowMicroSec, uint64* gpuMicroSec ); + + virtual void SwapCommandBuffers_FinishRendering( uint64* frontEndMicroSec, uint64* backEndMicroSec, uint64* shadowMicroSec, uint64* gpuMicroSec ); + virtual const emptyCommand_t* SwapCommandBuffers_FinishCommandBuffers(); + + virtual void RenderCommandBuffers( const emptyCommand_t* commandBuffers ); + virtual void TakeScreenshot( int width, int height, const char* fileName, int downSample, renderView_t* ref, int exten ); + virtual void CropRenderSize( int width, int height ); + virtual void CaptureRenderToImage( const char* imageName, bool clearColorAfterCopy = false ); + virtual void CaptureRenderToFile( const char* fileName, bool fixAlpha ); + virtual void UnCrop(); + virtual bool UploadImage( const char* imageName, const byte* data, int width, int height ); + + void PrintPerformanceCounters(); + + +public: + // internal functions + idRenderSystemLocal(); + ~idRenderSystemLocal(); + + void UpdateStereo3DMode(); + + void Clear(); + void GetCroppedViewport( idScreenRect* viewport ); + void PerformResolutionScaling( int& newWidth, int& newHeight ); + int GetFrameCount() const + { + return frameCount; + }; + + void OnFrame(); + +public: + // renderer globals + bool registered; // cleared at shutdown, set at InitOpenGL + + bool takingScreenshot; + + int frameCount; // incremented every frame + int viewCount; // incremented every view (twice a scene if subviewed) + // and every R_MarkFragments call + + float frameShaderTime; // shader time for all non-world 2D rendering + + idVec4 ambientLightVector; // used for "ambient bump mapping" + + idListworlds; + + idRenderWorldLocal* primaryWorld; + renderView_t primaryRenderView; + viewDef_t* primaryView; + // many console commands need to know which world they should operate on + + const idMaterial* whiteMaterial; + const idMaterial* charSetMaterial; + const idMaterial* defaultPointLight; + const idMaterial* defaultProjectedLight; + const idMaterial* defaultMaterial; + idImage* testImage; + idCinematic* testVideo; + int testVideoStartTime; + + idImage* ambientCubeImage; // hack for testing dependent ambient lighting + + viewDef_t* viewDef; + + performanceCounters_t pc; // performance counters + + viewEntity_t identitySpace; // can use if we don't know viewDef->worldSpace is valid + + idScreenRect renderCrops[MAX_RENDER_CROPS]; + int currentRenderCrop; + + // GUI drawing variables for surface creation + int guiRecursionLevel; // to prevent infinite overruns + uint32 currentColorNativeBytesOrder; + uint64 currentGLState; + class idGuiModel* guiModel; + + idList fonts; + + unsigned short gammaTable[256]; // brightness / gamma modify this + + srfTriangles_t* unitSquareTriangles; + srfTriangles_t* zeroOneCubeTriangles; + srfTriangles_t* testImageTriangles; + + // these are allocated at buffer swap time, but + // the back end should only use the ones in the backEnd stucture, + // which are copied over from the frame that was just swapped. + drawSurf_t unitSquareSurface_; + drawSurf_t zeroOneCubeSurface_; + drawSurf_t testImageSurface_; + + idParallelJobList* frontEndJobList; + + idRenderBackend backend; + + unsigned timerQueryId; // for GL_TIME_ELAPSED_EXT queries +}; + +extern idRenderSystemLocal tr; +extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared during ref re-init + +// +// cvars +// +extern idCVar r_debugContext; // enable various levels of context debug +extern idCVar r_glDriver; // "opengl32", etc +extern idCVar r_skipIntelWorkarounds; // skip work arounds for Intel driver bugs +extern idCVar r_vidMode; // video mode number +extern idCVar r_displayRefresh; // optional display refresh rate option for vid mode +extern idCVar r_fullscreen; // 0 = windowed, 1 = full screen +extern idCVar r_antiAliasing; // anti aliasing mode, SMAA, TXAA, MSAA etc. + +extern idCVar r_znear; // near Z clip plane + +extern idCVar r_swapInterval; // changes wglSwapIntarval +extern idCVar r_offsetFactor; // polygon offset parameter +extern idCVar r_offsetUnits; // polygon offset parameter +extern idCVar r_singleTriangle; // only draw a single triangle per primitive +extern idCVar r_logFile; // number of frames to emit GL logs +extern idCVar r_clear; // force screen clear every frame +extern idCVar r_subviewOnly; // 1 = don't render main view, allowing subviews to be debugged +extern idCVar r_lightScale; // all light intensities are multiplied by this, which is normally 3 +extern idCVar r_flareSize; // scale the flare deforms from the material def + +extern idCVar r_gamma; // changes gamma tables +extern idCVar r_brightness; // changes gamma tables + +extern idCVar r_checkBounds; // compare all surface bounds with precalculated ones +extern idCVar r_maxAnisotropicFiltering; // texture filtering parameter +extern idCVar r_useTrilinearFiltering; // Extra quality filtering +extern idCVar r_lodBias; // lod bias + +extern idCVar r_useLightPortalFlow; // 1 = do a more precise area reference determination +extern idCVar r_useShadowSurfaceScissor; // 1 = scissor shadows by the scissor rect of the interaction surfaces +extern idCVar r_useConstantMaterials; // 1 = use pre-calculated material registers if possible +extern idCVar r_useNodeCommonChildren; // stop pushing reference bounds early when possible +extern idCVar r_useSilRemap; // 1 = consider verts with the same XYZ, but different ST the same for shadows +extern idCVar r_useLightPortalCulling; // 0 = none, 1 = box, 2 = exact clip of polyhedron faces, 3 MVP to plane culling +extern idCVar r_useLightAreaCulling; // 0 = off, 1 = on +extern idCVar r_useLightScissors; // 1 = use custom scissor rectangle for each light +extern idCVar r_useEntityPortalCulling; // 0 = none, 1 = box +extern idCVar r_skipPrelightShadows; // 1 = skip the dmap generated static shadow volumes +extern idCVar r_useCachedDynamicModels; // 1 = cache snapshots of dynamic models +extern idCVar r_useScissor; // 1 = scissor clip as portals and lights are processed +extern idCVar r_usePortals; // 1 = use portals to perform area culling, otherwise draw everything +extern idCVar r_useStateCaching; // avoid redundant state changes in GL_*() calls +extern idCVar r_useEntityCallbacks; // if 0, issue the callback immediately at update time, rather than defering +extern idCVar r_lightAllBackFaces; // light all the back faces, even when they would be shadowed +extern idCVar r_useLightDepthBounds; // use depth bounds test on lights to reduce both shadow and interaction fill +extern idCVar r_useShadowDepthBounds; // use depth bounds test on individual shadows to reduce shadow fill +// RB begin +extern idCVar r_useShadowMapping; // use shadow mapping instead of stencil shadows +extern idCVar r_useHalfLambertLighting; // use Half-Lambert lighting instead of classic Lambert +extern idCVar r_useHDR; +extern idCVar r_useSRGB; +// RB end + +extern idCVar r_skipStaticInteractions; // skip interactions created at level load +extern idCVar r_skipDynamicInteractions; // skip interactions created after level load +extern idCVar r_skipPostProcess; // skip all post-process renderings +extern idCVar r_skipSuppress; // ignore the per-view suppressions +extern idCVar r_skipInteractions; // skip all light/surface interaction drawing +extern idCVar r_skipFrontEnd; // bypasses all front end work, but 2D gui rendering still draws +extern idCVar r_skipBackEnd; // don't draw anything +extern idCVar r_skipCopyTexture; // do all rendering, but don't actually copyTexSubImage2D +extern idCVar r_skipRender; // skip 3D rendering, but pass 2D +extern idCVar r_skipRenderContext; // NULL the rendering context during backend 3D rendering +extern idCVar r_skipTranslucent; // skip the translucent interaction rendering +extern idCVar r_skipAmbient; // bypasses all non-interaction drawing +extern idCVar r_skipNewAmbient; // bypasses all vertex/fragment program ambients +extern idCVar r_skipBlendLights; // skip all blend lights +extern idCVar r_skipFogLights; // skip all fog lights +extern idCVar r_skipSubviews; // 1 = don't render any mirrors / cameras / etc +extern idCVar r_skipGuiShaders; // 1 = don't render any gui elements on surfaces +extern idCVar r_skipParticles; // 1 = don't render any particles +extern idCVar r_skipUpdates; // 1 = don't accept any entity or light updates, making everything static +extern idCVar r_skipDeforms; // leave all deform materials in their original state +extern idCVar r_skipDynamicTextures; // don't dynamically create textures +extern idCVar r_skipBump; // uses a flat surface instead of the bump map +extern idCVar r_skipSpecular; // use black for specular +extern idCVar r_skipDiffuse; // use black for diffuse +extern idCVar r_skipDecals; // skip decal surfaces +extern idCVar r_skipOverlays; // skip overlay surfaces +extern idCVar r_skipShadows; // disable shadows + +extern idCVar r_ignoreGLErrors; + +extern idCVar r_screenFraction; // for testing fill rate, the resolution of the entire screen can be changed +extern idCVar r_showUnsmoothedTangents; // highlight geometry rendered with unsmoothed tangents +extern idCVar r_showSilhouette; // highlight edges that are casting shadow planes +extern idCVar r_showVertexColor; // draws all triangles with the solid vertex color +extern idCVar r_showUpdates; // report entity and light updates and ref counts +extern idCVar r_showDemo; // report reads and writes to the demo file +extern idCVar r_showDynamic; // report stats on dynamic surface generation +extern idCVar r_showIntensity; // draw the screen colors based on intensity, red = 0, green = 128, blue = 255 +extern idCVar r_showTrace; // show the intersection of an eye trace with the world +extern idCVar r_showDepth; // display the contents of the depth buffer and the depth range +extern idCVar r_showTris; // enables wireframe rendering of the world +extern idCVar r_showSurfaceInfo; // show surface material name under crosshair +extern idCVar r_showNormals; // draws wireframe normals +extern idCVar r_showEdges; // draw the sil edges +extern idCVar r_showViewEntitys; // displays the bounding boxes of all view models and optionally the index +extern idCVar r_showTexturePolarity; // shade triangles by texture area polarity +extern idCVar r_showTangentSpace; // shade triangles by tangent space +extern idCVar r_showDominantTri; // draw lines from vertexes to center of dominant triangles +extern idCVar r_showTextureVectors; // draw each triangles texture (tangent) vectors +extern idCVar r_showLights; // 1 = print light info, 2 = also draw volumes +extern idCVar r_showLightCount; // colors surfaces based on light count +extern idCVar r_showShadows; // visualize the stencil shadow volumes +extern idCVar r_showLightScissors; // show light scissor rectangles +extern idCVar r_showMemory; // print frame memory utilization +extern idCVar r_showCull; // report sphere and box culling stats +extern idCVar r_showAddModel; // report stats from tr_addModel +extern idCVar r_showSurfaces; // report surface/light/shadow counts +extern idCVar r_showPrimitives; // report vertex/index/draw counts +extern idCVar r_showPortals; // draw portal outlines in color based on passed / not passed +extern idCVar r_showSkel; // draw the skeleton when model animates +extern idCVar r_showOverDraw; // show overdraw +// RB begin +extern idCVar r_showShadowMaps; +extern idCVar r_showShadowMapLODs; +// RB end +extern idCVar r_jointNameScale; // size of joint names when r_showskel is set to 1 +extern idCVar r_jointNameOffset; // offset of joint names when r_showskel is set to 1 + +extern idCVar r_testGamma; // draw a grid pattern to test gamma levels +extern idCVar r_testGammaBias; // draw a grid pattern to test gamma levels + +extern idCVar r_singleLight; // suppress all but one light +extern idCVar r_singleEntity; // suppress all but one entity +extern idCVar r_singleArea; // only draw the portal area the view is actually in +extern idCVar r_singleSurface; // suppress all but one surface on each entity +extern idCVar r_shadowPolygonOffset; // bias value added to depth test for stencil shadow drawing +extern idCVar r_shadowPolygonFactor; // scale value for stencil shadow drawing + +extern idCVar r_jitter; // randomly subpixel jitter the projection matrix +extern idCVar r_orderIndexes; // perform index reorganization to optimize vertex use + +extern idCVar r_debugLineDepthTest; // perform depth test on debug lines +extern idCVar r_debugLineWidth; // width of debug lines +extern idCVar r_debugArrowStep; // step size of arrow cone line rotation in degrees +extern idCVar r_debugPolygonFilled; + +extern idCVar r_materialOverride; // override all materials + +extern idCVar r_debugRenderToTexture; + +extern idCVar stereoRender_deGhost; // subtract from opposite eye to reduce ghosting + +extern idCVar r_useGPUSkinning; + +// RB begin +extern idCVar r_shadowMapFrustumFOV; +extern idCVar r_shadowMapSingleSide; +extern idCVar r_shadowMapImageSize; +extern idCVar r_shadowMapJitterScale; +extern idCVar r_shadowMapBiasScale; +extern idCVar r_shadowMapRandomizeJitter; +extern idCVar r_shadowMapSamples; +extern idCVar r_shadowMapSplits; +extern idCVar r_shadowMapSplitWeight; +extern idCVar r_shadowMapLodScale; +extern idCVar r_shadowMapLodBias; +extern idCVar r_shadowMapPolygonFactor; +extern idCVar r_shadowMapPolygonOffset; +extern idCVar r_shadowMapOccluderFacing; +extern idCVar r_shadowMapRegularDepthBiasScale; +extern idCVar r_shadowMapSunDepthBiasScale; + +extern idCVar r_hdrAutoExposure; +extern idCVar r_hdrMinLuminance; +extern idCVar r_hdrMaxLuminance; +extern idCVar r_hdrKey; +extern idCVar r_hdrContrastDynamicThreshold; +extern idCVar r_hdrContrastStaticThreshold; +extern idCVar r_hdrContrastOffset; +extern idCVar r_hdrGlarePasses; +extern idCVar r_hdrDebug; + +extern idCVar r_ldrContrastThreshold; +extern idCVar r_ldrContrastOffset; + +extern idCVar r_useFilmicPostProcessEffects; +extern idCVar r_forceAmbient; + +extern idCVar r_useSSGI; +extern idCVar r_ssgiDebug; +extern idCVar r_ssgiFiltering; + +extern idCVar r_useSSAO; +extern idCVar r_ssaoDebug; +extern idCVar r_ssaoFiltering; +extern idCVar r_useHierarchicalDepthBuffer; + +extern idCVar r_exposure; +// RB end + +/* +==================================================================== + +INITIALIZATION + +==================================================================== +*/ + +void R_Init(); +void R_InitOpenGL(); + +void R_SetColorMappings(); + +void R_ScreenShot_f( const idCmdArgs& args ); +void R_StencilShot(); + +/* +==================================================================== + +IMPLEMENTATION SPECIFIC FUNCTIONS + +==================================================================== +*/ + +struct vidMode_t +{ + int width; + int height; + int displayHz; + + // RB begin + vidMode_t() + { + width = 640; + height = 480; + displayHz = 60; + } + + vidMode_t( int width, int height, int displayHz ) : + width( width ), height( height ), displayHz( displayHz ) {} + // RB end + + bool operator==( const vidMode_t& a ) + { + return a.width == width && a.height == height && a.displayHz == displayHz; + } +}; + +// the number of displays can be found by itterating this until it returns false +// displayNum is the 0 based value passed to EnumDisplayDevices(), you must add +// 1 to this to get an r_fullScreen value. +bool R_GetModeListForDisplay( const int displayNum, idList& modeList ); + +struct glimpParms_t +{ + int x; // ignored in fullscreen + int y; // ignored in fullscreen + int width; + int height; + int fullScreen; // 0 = windowed, otherwise 1 based monitor number to go full screen on + // -1 = borderless window for spanning multiple displays + bool stereo; + int displayHz; + int multiSamples; +}; + +// DG: R_GetModeListForDisplay is called before GLimp_Init(), but SDL needs SDL_Init() first. +// So add PreInit for platforms that need it, others can just stub it. +void GLimp_PreInit(); + +// If the desired mode can't be set satisfactorily, false will be returned. +// If succesful, sets glConfig.nativeScreenWidth, glConfig.nativeScreenHeight, and glConfig.pixelAspect +// The renderer will then reset the glimpParms to "safe mode" of 640x480 +// fullscreen and try again. If that also fails, the error will be fatal. +bool GLimp_Init( glimpParms_t parms ); + +// will set up gl up with the new parms +bool GLimp_SetScreenParms( glimpParms_t parms ); + +// Destroys the rendering context, closes the window, resets the resolution, +// and resets the gamma ramps. +void GLimp_Shutdown(); + +// Sets the hardware gamma ramps for gamma and brightness adjustment. +// These are now taken as 16 bit values, so we can take full advantage +// of dacs with >8 bits of precision +void GLimp_SetGamma( unsigned short red[256], + unsigned short green[256], + unsigned short blue[256] ); + + + +/* +============================================================ + +RENDERWORLD_DEFS + +============================================================ +*/ + +void R_DeriveEntityData( idRenderEntityLocal* def ); +void R_CreateEntityRefs( idRenderEntityLocal* def ); +void R_FreeEntityDefDerivedData( idRenderEntityLocal* def, bool keepDecals, bool keepCachedDynamicModel ); +void R_FreeEntityDefCachedDynamicModel( idRenderEntityLocal* def ); +void R_FreeEntityDefDecals( idRenderEntityLocal* def ); +void R_FreeEntityDefOverlay( idRenderEntityLocal* def ); +void R_FreeEntityDefFadedDecals( idRenderEntityLocal* def, int time ); + +// RB: for dmap +void R_DeriveLightData( idRenderLightLocal* light ); + +// Called by the editor and dmap to operate on light volumes +void R_RenderLightFrustum( const renderLight_t& renderLight, idPlane lightFrustum[6] ); + +srfTriangles_t* R_PolytopeSurface( int numPlanes, const idPlane* planes, idWinding** windings ); +// RB end +void R_CreateLightRefs( idRenderLightLocal* light ); +void R_FreeLightDefDerivedData( idRenderLightLocal* light ); + +void R_FreeDerivedData(); +void R_ReCreateWorldReferences(); +void R_CheckForEntityDefsUsingModel( idRenderModel* model ); +void R_ModulateLights_f( const idCmdArgs& args ); + +/* +============================================================ + +RENDERWORLD_PORTALS + +============================================================ +*/ + +viewEntity_t* R_SetEntityDefViewEntity( idRenderEntityLocal* def ); +viewLight_t* R_SetLightDefViewLight( idRenderLightLocal* def ); + +/* +==================================================================== + +TR_FRONTEND_MAIN + +==================================================================== +*/ + +void R_InitFrameData(); +void R_ShutdownFrameData(); +void R_ToggleSmpFrame(); +void* R_FrameAlloc( int bytes, frameAllocType_t type = FRAME_ALLOC_UNKNOWN ); +void* R_ClearedFrameAlloc( int bytes, frameAllocType_t type = FRAME_ALLOC_UNKNOWN ); + +void* R_StaticAlloc( int bytes, const memTag_t tag = TAG_RENDER_STATIC ); // just malloc with error checking +void* R_ClearedStaticAlloc( int bytes ); // with memset +void R_StaticFree( void* data ); + +void R_RenderView( viewDef_t* parms ); +void R_RenderPostProcess( viewDef_t* parms ); + +/* +============================================================ + +TR_FRONTEND_ADDLIGHTS + +============================================================ +*/ + +void R_ShadowBounds( const idBounds& modelBounds, const idBounds& lightBounds, const idVec3& lightOrigin, idBounds& shadowBounds ); + +ID_INLINE bool R_CullModelBoundsToLight( const idRenderLightLocal* light, const idBounds& localBounds, const idRenderMatrix& modelRenderMatrix ) +{ + idRenderMatrix modelLightProject; + idRenderMatrix::Multiply( light->baseLightProject, modelRenderMatrix, modelLightProject ); + return idRenderMatrix::CullBoundsToMVP( modelLightProject, localBounds, true ); +} + +void R_AddLights(); +void R_OptimizeViewLightsList(); + +/* +============================================================ + +TR_FRONTEND_ADDMODELS + +============================================================ +*/ + +bool R_IssueEntityDefCallback( idRenderEntityLocal* def ); +idRenderModel* R_EntityDefDynamicModel( idRenderEntityLocal* def ); +void R_ClearEntityDefDynamicModel( idRenderEntityLocal* def ); + +void R_SetupDrawSurfShader( drawSurf_t* drawSurf, const idMaterial* shader, const renderEntity_t* renderEntity ); +void R_SetupDrawSurfJoints( drawSurf_t* drawSurf, const srfTriangles_t* tri, const idMaterial* shader ); +void R_LinkDrawSurfToView( drawSurf_t* drawSurf, viewDef_t* viewDef ); + +void R_AddModels(); + +/* +============================================================= + +TR_FRONTEND_DEFORM + +============================================================= +*/ + +drawSurf_t* R_DeformDrawSurf( drawSurf_t* drawSurf ); + +/* +============================================================= + +TR_FRONTEND_GUISURF + +============================================================= +*/ + +void R_SurfaceToTextureAxis( const srfTriangles_t* tri, idVec3& origin, idVec3 axis[3] ); +void R_AddInGameGuis( const drawSurf_t* const drawSurfs[], const int numDrawSurfs ); + +/* +============================================================ + +TR_FRONTEND_SUBVIEW + +============================================================ +*/ + +bool R_PreciseCullSurface( const drawSurf_t* drawSurf, idBounds& ndcBounds ); +bool R_GenerateSubViews( const drawSurf_t* const drawSurfs[], const int numDrawSurfs ); + +/* +============================================================ + +TR_TRISURF + +============================================================ +*/ + +srfTriangles_t* R_AllocStaticTriSurf(); +void R_AllocStaticTriSurfVerts( srfTriangles_t* tri, int numVerts ); +void R_AllocStaticTriSurfIndexes( srfTriangles_t* tri, int numIndexes ); +void R_AllocStaticTriSurfPreLightShadowVerts( srfTriangles_t* tri, int numVerts ); +void R_AllocStaticTriSurfSilIndexes( srfTriangles_t* tri, int numIndexes ); +void R_AllocStaticTriSurfDominantTris( srfTriangles_t* tri, int numVerts ); +void R_AllocStaticTriSurfSilEdges( srfTriangles_t* tri, int numSilEdges ); +void R_AllocStaticTriSurfMirroredVerts( srfTriangles_t* tri, int numMirroredVerts ); +void R_AllocStaticTriSurfDupVerts( srfTriangles_t* tri, int numDupVerts ); + +srfTriangles_t* R_CopyStaticTriSurf( const srfTriangles_t* tri ); + +void R_ResizeStaticTriSurfVerts( srfTriangles_t* tri, int numVerts ); +void R_ResizeStaticTriSurfIndexes( srfTriangles_t* tri, int numIndexes ); +void R_ReferenceStaticTriSurfVerts( srfTriangles_t* tri, const srfTriangles_t* reference ); +void R_ReferenceStaticTriSurfIndexes( srfTriangles_t* tri, const srfTriangles_t* reference ); + +void R_FreeStaticTriSurfSilIndexes( srfTriangles_t* tri ); +void R_FreeStaticTriSurf( srfTriangles_t* tri ); +void R_FreeStaticTriSurfVerts( srfTriangles_t* tri ); +void R_FreeStaticTriSurfVertexCaches( srfTriangles_t* tri ); +int R_TriSurfMemory( const srfTriangles_t* tri ); + +void R_BoundTriSurf( srfTriangles_t* tri ); +void R_RemoveDuplicatedTriangles( srfTriangles_t* tri ); +void R_CreateSilIndexes( srfTriangles_t* tri ); +void R_RemoveDegenerateTriangles( srfTriangles_t* tri ); +void R_RemoveUnusedVerts( srfTriangles_t* tri ); +void R_RangeCheckIndexes( const srfTriangles_t* tri ); +void R_CreateVertexNormals( srfTriangles_t* tri ); // also called by dmap +void R_CleanupTriangles( srfTriangles_t* tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents ); +void R_ReverseTriangles( srfTriangles_t* tri ); + +// Only deals with vertexes and indexes, not silhouettes, planes, etc. +// Does NOT perform a cleanup triangles, so there may be duplicated verts in the result. +srfTriangles_t* R_MergeSurfaceList( const srfTriangles_t** surfaces, int numSurfaces ); +srfTriangles_t* R_MergeTriangles( const srfTriangles_t* tri1, const srfTriangles_t* tri2 ); + +// if the deformed verts have significant enough texture coordinate changes to reverse the texture +// polarity of a triangle, the tangents will be incorrect +void R_DeriveTangents( srfTriangles_t* tri ); + +// copy data from a front-end srfTriangles_t to a back-end drawSurf_t +void R_InitDrawSurfFromTri( drawSurf_t& ds, srfTriangles_t& tri ); + +// For static surfaces, the indexes, ambient, and shadow buffers can be pre-created at load +// time, rather than being re-created each frame in the frame temporary buffers. +void R_CreateStaticBuffersForTri( srfTriangles_t& tri ); + +// deformable meshes precalculate as much as possible from a base frame, then generate +// complete srfTriangles_t from just a new set of vertexes +struct deformInfo_t +{ + int numSourceVerts; + + // numOutputVerts may be smaller if the input had duplicated or degenerate triangles + // it will often be larger if the input had mirrored texture seams that needed + // to be busted for proper tangent spaces + int numOutputVerts; + idDrawVert* verts; + + int numIndexes; + triIndex_t* indexes; + + triIndex_t* silIndexes; // indexes changed to be the first vertex with same XYZ, ignoring normal and texcoords + + int numMirroredVerts; // this many verts at the end of the vert list are tangent mirrors + int* mirroredVerts; // tri->mirroredVerts[0] is the mirror of tri->numVerts - tri->numMirroredVerts + 0 + + int numDupVerts; // number of duplicate vertexes + int* dupVerts; // pairs of the number of the first vertex and the number of the duplicate vertex + + int numSilEdges; // number of silhouette edges + silEdge_t* silEdges; // silhouette edges + + vertCacheHandle_t staticIndexCache; // GL_INDEX_TYPE + vertCacheHandle_t staticAmbientCache; // idDrawVert + vertCacheHandle_t staticShadowCache; // idShadowCacheSkinned +}; + + +// if outputVertexes is not NULL, it will point to a newly allocated set of verts that includes the mirrored ones +deformInfo_t* R_BuildDeformInfo( int numVerts, const idDrawVert* verts, int numIndexes, const int* indexes, + bool useUnsmoothedTangents ); +void R_FreeDeformInfo( deformInfo_t* deformInfo ); +int R_DeformInfoMemoryUsed( deformInfo_t* deformInfo ); + +/* +============================================================= + +TR_TRACE + +============================================================= +*/ + +struct localTrace_t +{ + float fraction; + // only valid if fraction < 1.0 + idVec3 point; + idVec3 normal; + int indexes[3]; +}; + +localTrace_t R_LocalTrace( const idVec3& start, const idVec3& end, const float radius, const srfTriangles_t* tri ); + + + +/* +============================================================ + +TR_BACKEND_DRAW + +============================================================ +*/ + +void RB_SetMVP( const idRenderMatrix& mvp ); + +/* +============================================================= + +TR_BACKEND_RENDERTOOLS + +============================================================= +*/ + +float RB_DrawTextLength( const char* text, float scale, int len ); +void RB_AddDebugText( const char* text, const idVec3& origin, float scale, const idVec4& color, const idMat3& viewAxis, const int align, const int lifetime, const bool depthTest ); +void RB_ClearDebugText( int time ); +void RB_AddDebugLine( const idVec4& color, const idVec3& start, const idVec3& end, const int lifeTime, const bool depthTest ); +void RB_ClearDebugLines( int time ); +void RB_AddDebugPolygon( const idVec4& color, const idWinding& winding, const int lifeTime, const bool depthTest ); +void RB_ClearDebugPolygons( int time ); +void RB_DrawBounds( const idBounds& bounds ); + +void RB_ShutdownDebugTools(); +void RB_SetVertexColorParms( stageVertexColor_t svc ); + +//============================================= + +#include "ResolutionScale.h" +#include "RenderLog.h" +#include "jobs/ShadowShared.h" +#include "jobs/prelightshadowvolume/PreLightShadowVolume.h" +#include "jobs/staticshadowvolume/StaticShadowVolume.h" +#include "jobs/dynamicshadowvolume/DynamicShadowVolume.h" +#include "GLMatrix.h" + + + +#include "BufferObject.h" +#include "RenderProgs.h" +#include "RenderWorld_local.h" +#include "GuiModel.h" +#include "VertexCache.h" + +#endif /* !__TR_LOCAL_H__ */ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderEntity.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderEntity.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderEntity.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderEntity.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -31,7 +31,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" idRenderEntityLocal::idRenderEntityLocal() { diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderLog.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderLog.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderLog.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderLog.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -27,7 +27,7 @@ =========================================================================== */ #pragma hdrstop -#include "tr_local.h" +#include "RenderCommon.h" /* ================================================================================================ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderProgs.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderProgs.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderProgs.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderProgs.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" @@ -200,10 +200,10 @@ LoadFragmentShader( i ); LoadGLSLProgram( i, i, i ); } - + r_useHalfLambertLighting.ClearModified(); r_useHDR.ClearModified(); - + // special case handling for fastZ shaders /* switch( glConfig.driverType ) diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderProgs_GLSL.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderProgs_GLSL.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderProgs_GLSL.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderProgs_GLSL.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "RenderProgs_embedded.h" idCVar r_skipStripDeadCode( "r_skipStripDeadCode", "0", CVAR_BOOL, "Skip stripping dead code" ); diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderSystem.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderSystem.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderSystem.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderSystem.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -31,7 +31,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" idRenderSystemLocal tr; idRenderSystem* renderSystem = &tr; @@ -44,56 +44,56 @@ only be called when the back end thread is idle. ===================== */ -static void R_PerformanceCounters() +void idRenderSystemLocal::PrintPerformanceCounters() { if( r_showPrimitives.GetInteger() != 0 ) { common->Printf( "views:%i draws:%i tris:%i (shdw:%i)\n", - tr.pc.c_numViews, - backEnd.pc.c_drawElements + backEnd.pc.c_shadowElements, - ( backEnd.pc.c_drawIndexes + backEnd.pc.c_shadowIndexes ) / 3, - backEnd.pc.c_shadowIndexes / 3 + pc.c_numViews, + backend.pc.c_drawElements + backend.pc.c_shadowElements, + ( backend.pc.c_drawIndexes + backend.pc.c_shadowIndexes ) / 3, + backend.pc.c_shadowIndexes / 3 ); } if( r_showDynamic.GetBool() ) { common->Printf( "callback:%i md5:%i dfrmVerts:%i dfrmTris:%i tangTris:%i guis:%i\n", - tr.pc.c_entityDefCallbacks, - tr.pc.c_generateMd5, - tr.pc.c_deformedVerts, - tr.pc.c_deformedIndexes / 3, - tr.pc.c_tangentIndexes / 3, - tr.pc.c_guiSurfs + pc.c_entityDefCallbacks, + pc.c_generateMd5, + pc.c_deformedVerts, + pc.c_deformedIndexes / 3, + pc.c_tangentIndexes / 3, + pc.c_guiSurfs ); } if( r_showCull.GetBool() ) { common->Printf( "%i box in %i box out\n", - tr.pc.c_box_cull_in, tr.pc.c_box_cull_out ); + pc.c_box_cull_in, pc.c_box_cull_out ); } if( r_showAddModel.GetBool() ) { common->Printf( "callback:%i createInteractions:%i createShadowVolumes:%i\n", - tr.pc.c_entityDefCallbacks, tr.pc.c_createInteractions, tr.pc.c_createShadowVolumes ); - common->Printf( "viewEntities:%i shadowEntities:%i viewLights:%i\n", tr.pc.c_visibleViewEntities, - tr.pc.c_shadowViewEntities, tr.pc.c_viewLights ); + pc.c_entityDefCallbacks, pc.c_createInteractions, pc.c_createShadowVolumes ); + common->Printf( "viewEntities:%i shadowEntities:%i viewLights:%i\n", pc.c_visibleViewEntities, + pc.c_shadowViewEntities, pc.c_viewLights ); } if( r_showUpdates.GetBool() ) { common->Printf( "entityUpdates:%i entityRefs:%i lightUpdates:%i lightRefs:%i\n", - tr.pc.c_entityUpdates, tr.pc.c_entityReferences, - tr.pc.c_lightUpdates, tr.pc.c_lightReferences ); + pc.c_entityUpdates, pc.c_entityReferences, + pc.c_lightUpdates, pc.c_lightReferences ); } if( r_showMemory.GetBool() ) { common->Printf( "frameData: %i (%i)\n", frameData->frameMemoryAllocated.GetValue(), frameData->highWaterAllocated ); } - memset( &tr.pc, 0, sizeof( tr.pc ) ); - memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); + memset( &pc, 0, sizeof( pc ) ); + memset( &backend.pc, 0, sizeof( backend.pc ) ); } /* @@ -136,14 +136,14 @@ glGenQueries( 1, & tr.timerQueryId ); } glBeginQuery( GL_TIME_ELAPSED_EXT, tr.timerQueryId ); - RB_ExecuteBackEndCommands( cmdHead ); + backend.ExecuteBackEndCommands( cmdHead ); glEndQuery( GL_TIME_ELAPSED_EXT ); glFlush(); } else #endif { - RB_ExecuteBackEndCommands( cmdHead ); + backend.ExecuteBackEndCommands( cmdHead ); } } @@ -228,115 +228,7 @@ //================================================================================= -/* -============= -R_CheckCvars -See if some cvars that we watch have changed -============= -*/ -static void R_CheckCvars() -{ - // gamma stuff - if( r_gamma.IsModified() || r_brightness.IsModified() ) - { - r_gamma.ClearModified(); - r_brightness.ClearModified(); - R_SetColorMappings(); - } - - // filtering - if( r_maxAnisotropicFiltering.IsModified() || r_useTrilinearFiltering.IsModified() || r_lodBias.IsModified() ) - { - idLib::Printf( "Updating texture filter parameters.\n" ); - r_maxAnisotropicFiltering.ClearModified(); - r_useTrilinearFiltering.ClearModified(); - r_lodBias.ClearModified(); - for( int i = 0 ; i < globalImages->images.Num() ; i++ ) - { - if( globalImages->images[i] ) - { - globalImages->images[i]->Bind(); - globalImages->images[i]->SetTexParameters(); - } - } - } - - extern idCVar r_useSeamlessCubeMap; - if( r_useSeamlessCubeMap.IsModified() ) - { - r_useSeamlessCubeMap.ClearModified(); - if( glConfig.seamlessCubeMapAvailable ) - { - if( r_useSeamlessCubeMap.GetBool() ) - { - glEnable( GL_TEXTURE_CUBE_MAP_SEAMLESS ); - } - else - { - glDisable( GL_TEXTURE_CUBE_MAP_SEAMLESS ); - } - } - } - - extern idCVar r_useSRGB; - if( r_useSRGB.IsModified() ) - { - r_useSRGB.ClearModified(); - if( glConfig.sRGBFramebufferAvailable ) - { - if( r_useSRGB.GetBool() && r_useSRGB.GetInteger() != 3 ) - { - glEnable( GL_FRAMEBUFFER_SRGB ); - } - else - { - glDisable( GL_FRAMEBUFFER_SRGB ); - } - } - } - - if( r_antiAliasing.IsModified() ) - { - switch( r_antiAliasing.GetInteger() ) - { - case ANTI_ALIASING_MSAA_2X: - case ANTI_ALIASING_MSAA_4X: - case ANTI_ALIASING_MSAA_8X: - if( r_antiAliasing.GetInteger() > 0 ) - { - glEnable( GL_MULTISAMPLE ); - } - break; - - default: - glDisable( GL_MULTISAMPLE ); - break; - } - } - - if (r_useHDR.IsModified() || r_useHalfLambertLighting.IsModified() ) - { - r_useHDR.ClearModified(); - r_useHalfLambertLighting.ClearModified(); - renderProgManager.KillAllShaders(); - renderProgManager.LoadAllShaders(); - } - - // RB: turn off shadow mapping for OpenGL drivers that are too slow - switch( glConfig.driverType ) - { - case GLDRV_OPENGL_ES2: - case GLDRV_OPENGL_ES3: - //case GLDRV_OPENGL_MESA: - r_useShadowMapping.SetInteger( 0 ); - break; - - default: - break; - } - // RB end -} /* ============= @@ -754,8 +646,7 @@ { // wait for our fence to hit, which means the swap has actually happened // We must do this before clearing any resources the GPU may be using - void GL_BlockingSwapBuffers(); - GL_BlockingSwapBuffers(); + backend.BlockingSwapBuffers(); } // read back the start and end timer queries from the previous frame @@ -784,18 +675,18 @@ } if( backEndMicroSec != NULL ) { - *backEndMicroSec = backEnd.pc.totalMicroSec; + *backEndMicroSec = backend.pc.totalMicroSec; } if( shadowMicroSec != NULL ) { - *shadowMicroSec = backEnd.pc.shadowMicroSec; + *shadowMicroSec = backend.pc.shadowMicroSec; } // print any other statistics and clear all of them - R_PerformanceCounters(); + PrintPerformanceCounters(); // check for dynamic changes that require some initialization - R_CheckCvars(); + backend.CheckCVars(); // RB: resize HDR buffers Framebuffer::CheckFramebuffers(); @@ -829,9 +720,9 @@ // copy the code-used drawsurfs that were // allocated at the start of the buffer memory to the backEnd referenced locations - backEnd.unitSquareSurface = tr.unitSquareSurface_; - backEnd.zeroOneCubeSurface = tr.zeroOneCubeSurface_; - backEnd.testImageSurface = tr.testImageSurface_; + backend.unitSquareSurface = tr.unitSquareSurface_; + backend.zeroOneCubeSurface = tr.zeroOneCubeSurface_; + backend.testImageSurface = tr.testImageSurface_; // use the other buffers next frame, because another CPU // may still be rendering into the current buffers diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderSystem_init.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderSystem_init.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderSystem_init.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderSystem_init.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -31,7 +31,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" // RB begin #if defined(_WIN32) @@ -391,8 +391,8 @@ // RB: Mesa support if( idStr::Icmpn( glConfig.renderer_string, "Mesa", 4 ) == 0 || idStr::Icmpn( glConfig.renderer_string, "X.org", 5 ) == 0 || idStr::Icmpn( glConfig.renderer_string, "Gallium", 7 ) == 0 || - strcmp( glConfig.vendor_string, "X.Org" ) == 0 || - idStr::Icmpn( glConfig.renderer_string, "llvmpipe", 8 ) == 0 ) + strcmp( glConfig.vendor_string, "X.Org" ) == 0 || + idStr::Icmpn( glConfig.renderer_string, "llvmpipe", 8 ) == 0 ) { if( glConfig.driverType == GLDRV_OPENGL32_CORE_PROFILE ) { @@ -952,67 +952,7 @@ // RB end } -/* -================== -GL_CheckErrors -================== -*/ -// RB: added filename, line parms -bool GL_CheckErrors_( const char* filename, int line ) -{ - int err; - char s[64]; - int i; - - if( r_ignoreGLErrors.GetBool() ) - { - return false; - } - - // check for up to 10 errors pending - bool error = false; - for( i = 0 ; i < 10 ; i++ ) - { - err = glGetError(); - if( err == GL_NO_ERROR ) - { - break; - } - - error = true; - switch( err ) - { - case GL_INVALID_ENUM: - strcpy( s, "GL_INVALID_ENUM" ); - break; - case GL_INVALID_VALUE: - strcpy( s, "GL_INVALID_VALUE" ); - break; - case GL_INVALID_OPERATION: - strcpy( s, "GL_INVALID_OPERATION" ); - break; -#if !defined(USE_GLES2) && !defined(USE_GLES3) - case GL_STACK_OVERFLOW: - strcpy( s, "GL_STACK_OVERFLOW" ); - break; - case GL_STACK_UNDERFLOW: - strcpy( s, "GL_STACK_UNDERFLOW" ); - break; -#endif - case GL_OUT_OF_MEMORY: - strcpy( s, "GL_OUT_OF_MEMORY" ); - break; - default: - idStr::snPrintf( s, sizeof( s ), "%i", err ); - break; - } - - common->Printf( "caught OpenGL error: %s in file %s line %i\n", s, filename, line ); - } - - return error; -} -// RB end + /* ===================== @@ -2909,7 +2849,7 @@ ambientLightVector[2] = 0.8925f; ambientLightVector[3] = 1.0f; - memset( &backEnd, 0, sizeof( backEnd ) ); + backend.Init(); R_InitCvars(); @@ -2918,9 +2858,9 @@ guiModel = new( TAG_RENDER ) idGuiModel; guiModel->Clear(); tr_guiModel = guiModel; // for DeviceContext fast path - + UpdateStereo3DMode(); - + globalImages->Init(); // RB begin diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -31,7 +31,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" /* =================== diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld_defs.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld_defs.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld_defs.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld_defs.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" /* ================================================================================= diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld_demo.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld_demo.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld_demo.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld_demo.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -31,7 +31,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" idCVar r_writeDemoDecals( "r_writeDemoDecals", "1", CVAR_BOOL | CVAR_SYSTEM, "enable Writing of entity decals to demo files." ); idCVar r_writeDemoOverlays( "r_writeDemoOverlays", "1", CVAR_BOOL | CVAR_SYSTEM, "enable Writing of entity Overlays to demo files." ); diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld_load.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld_load.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld_load.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld_load.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" /* diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld_local.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld_local.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld_local.h 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld_local.h 2018-10-13 10:08:18.000000000 +0000 @@ -251,7 +251,6 @@ { return areaScreenRect[areaNum]; } - void ShowPortals(); //-------------------------- // RenderWorld_demo.cpp diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld_portals.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld_portals.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/RenderWorld_portals.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/RenderWorld_portals.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" // if we hit this many planes, we will just stop cropping the // view down, which is still correct, just conservative @@ -1157,57 +1157,3 @@ return doublePortals[portal - 1].blockingBits; } -/* -===================== -idRenderWorldLocal::ShowPortals - -Debugging tool, won't work correctly with SMP or when mirrors are present -===================== -*/ -void idRenderWorldLocal::ShowPortals() -{ - int i, j; - portalArea_t* area; - portal_t* p; - idWinding* w; - - // flood out through portals, setting area viewCount - for( i = 0; i < numPortalAreas; i++ ) - { - area = &portalAreas[i]; - if( area->viewCount != tr.viewCount ) - { - continue; - } - for( p = area->portals; p; p = p->next ) - { - w = p->w; - if( !w ) - { - continue; - } - - if( portalAreas[ p->intoArea ].viewCount != tr.viewCount ) - { - // red = can't see - GL_Color( 1, 0, 0 ); - } - else - { - // green = see through - GL_Color( 0, 1, 0 ); - } - - // RB begin - renderProgManager.CommitUniforms(); - // RB end - - glBegin( GL_LINE_LOOP ); - for( j = 0; j < w->GetNumPoints(); j++ ) - { - glVertex3fv( ( *w )[j].ToFloatPtr() ); - } - glEnd(); - } - } -} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ResolutionScale.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ResolutionScale.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ResolutionScale.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ResolutionScale.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "ResolutionScale.h" diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ScreenRect.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ScreenRect.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/ScreenRect.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/ScreenRect.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" /* ========================================================================================== diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_backend_draw.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_backend_draw.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_backend_draw.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_backend_draw.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,5876 +0,0 @@ -/* -=========================================================================== - -Doom 3 BFG Edition GPL Source Code -Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. -Copyright (C) 2013-2015 Robert Beckebans -Copyright (C) 2014 Carl Kenner - -This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). - -Doom 3 BFG Edition Source Code 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. - -Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . - -In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#pragma hdrstop -#include "precompiled.h" - -#include "tr_local.h" -#include "Framebuffer.h" - -idCVar r_drawEyeColor( "r_drawEyeColor", "0", CVAR_RENDERER | CVAR_BOOL, "Draw a colored box, red = left eye, blue = right eye, grey = non-stereo" ); -idCVar r_motionBlur( "r_motionBlur", "0", CVAR_RENDERER | CVAR_INTEGER | CVAR_ARCHIVE, "1 - 5, log2 of the number of motion blur samples" ); -idCVar r_forceZPassStencilShadows( "r_forceZPassStencilShadows", "0", CVAR_RENDERER | CVAR_BOOL, "force Z-pass rendering for performance testing" ); -idCVar r_useStencilShadowPreload( "r_useStencilShadowPreload", "1", CVAR_RENDERER | CVAR_BOOL, "use stencil shadow preload algorithm instead of Z-fail" ); -idCVar r_skipShaderPasses( "r_skipShaderPasses", "0", CVAR_RENDERER | CVAR_BOOL, "" ); -idCVar r_skipInteractionFastPath( "r_skipInteractionFastPath", "1", CVAR_RENDERER | CVAR_BOOL, "" ); -idCVar r_useLightStencilSelect( "r_useLightStencilSelect", "0", CVAR_RENDERER | CVAR_BOOL, "use stencil select pass" ); - -extern idCVar stereoRender_swapEyes; - -backEndState_t backEnd; - -/* -================ -SetVertexParm -================ -*/ -static ID_INLINE void SetVertexParm( renderParm_t rp, const float* value ) -{ - renderProgManager.SetUniformValue( rp, value ); -} - -/* -================ -SetVertexParms -================ -*/ -static ID_INLINE void SetVertexParms( renderParm_t rp, const float* value, int num ) -{ - for( int i = 0; i < num; i++ ) - { - renderProgManager.SetUniformValue( ( renderParm_t )( rp + i ), value + ( i * 4 ) ); - } -} - -/* -================ -SetFragmentParm -================ -*/ -static ID_INLINE void SetFragmentParm( renderParm_t rp, const float* value ) -{ - renderProgManager.SetUniformValue( rp, value ); -} - -/* -================ -RB_SetMVP -================ -*/ -void RB_SetMVP( const idRenderMatrix& mvp ) -{ - SetVertexParms( RENDERPARM_MVPMATRIX_X, mvp[0], 4 ); -} - -/* -================ -RB_SetMVPWithStereoOffset -================ -*/ -static void RB_SetMVPWithStereoOffset( const idRenderMatrix& mvp, const float stereoOffset ) -{ - idRenderMatrix offset = mvp; - offset[0][3] += stereoOffset; - - SetVertexParms( RENDERPARM_MVPMATRIX_X, offset[0], 4 ); -} - -static const float zero[4] = { 0, 0, 0, 0 }; -static const float one[4] = { 1, 1, 1, 1 }; -static const float negOne[4] = { -1, -1, -1, -1 }; - -/* -================ -RB_SetVertexColorParms -================ -*/ -void RB_SetVertexColorParms( stageVertexColor_t svc ) -{ - switch( svc ) - { - case SVC_IGNORE: - SetVertexParm( RENDERPARM_VERTEXCOLOR_MODULATE, zero ); - SetVertexParm( RENDERPARM_VERTEXCOLOR_ADD, one ); - break; - case SVC_MODULATE: - SetVertexParm( RENDERPARM_VERTEXCOLOR_MODULATE, one ); - SetVertexParm( RENDERPARM_VERTEXCOLOR_ADD, zero ); - break; - case SVC_INVERSE_MODULATE: - SetVertexParm( RENDERPARM_VERTEXCOLOR_MODULATE, negOne ); - SetVertexParm( RENDERPARM_VERTEXCOLOR_ADD, one ); - break; - } -} - -/* -================ -RB_DrawElementsWithCounters -================ -*/ -void RB_DrawElementsWithCounters( const drawSurf_t* surf ) -{ - // get vertex buffer - const vertCacheHandle_t vbHandle = surf->ambientCache; - idVertexBuffer* vertexBuffer; - if( vertexCache.CacheIsStatic( vbHandle ) ) - { - vertexBuffer = &vertexCache.staticData.vertexBuffer; - } - else - { - const uint64 frameNum = ( int )( vbHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK; - if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) - { - idLib::Warning( "RB_DrawElementsWithCounters, vertexBuffer == NULL" ); - return; - } - vertexBuffer = &vertexCache.frameData[vertexCache.drawListNum].vertexBuffer; - } - const int vertOffset = ( int )( vbHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK; - - // get index buffer - const vertCacheHandle_t ibHandle = surf->indexCache; - idIndexBuffer* indexBuffer; - if( vertexCache.CacheIsStatic( ibHandle ) ) - { - indexBuffer = &vertexCache.staticData.indexBuffer; - } - else - { - const uint64 frameNum = ( int )( ibHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK; - if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) - { - idLib::Warning( "RB_DrawElementsWithCounters, indexBuffer == NULL" ); - return; - } - indexBuffer = &vertexCache.frameData[vertexCache.drawListNum].indexBuffer; - } - // RB: 64 bit fixes, changed int to GLintptr - const GLintptr indexOffset = ( GLintptr )( ibHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK; - // RB end - - RENDERLOG_PRINTF( "Binding Buffers: %p:%i %p:%i\n", vertexBuffer, vertOffset, indexBuffer, indexOffset ); - - if( surf->jointCache ) - { - // DG: this happens all the time in the erebus1 map with blendlight.vfp, - // so don't call assert (through verify) here until it's fixed (if fixable) - // else the game crashes on linux when using debug builds - - // FIXME: fix this properly if possible? - // RB: yes but it would require an additional blend light skinned shader - //if( !verify( renderProgManager.ShaderUsesJoints() ) ) - if( !renderProgManager.ShaderUsesJoints() ) - // DG end - { - return; - } - } - else - { - if( !verify( !renderProgManager.ShaderUsesJoints() || renderProgManager.ShaderHasOptionalSkinning() ) ) - { - return; - } - } - - - if( surf->jointCache ) - { - idJointBuffer jointBuffer; - if( !vertexCache.GetJointBuffer( surf->jointCache, &jointBuffer ) ) - { - idLib::Warning( "RB_DrawElementsWithCounters, jointBuffer == NULL" ); - return; - } - assert( ( jointBuffer.GetOffset() & ( glConfig.uniformBufferOffsetAlignment - 1 ) ) == 0 ); - - // RB: 64 bit fixes, changed GLuint to GLintptr - const GLintptr ubo = reinterpret_cast< GLintptr >( jointBuffer.GetAPIObject() ); - // RB end - - glBindBufferRange( GL_UNIFORM_BUFFER, 0, ubo, jointBuffer.GetOffset(), jointBuffer.GetNumJoints() * sizeof( idJointMat ) ); - } - - renderProgManager.CommitUniforms(); - - // RB: 64 bit fixes, changed GLuint to GLintptr - if( backEnd.glState.currentIndexBuffer != ( GLintptr )indexBuffer->GetAPIObject() || !r_useStateCaching.GetBool() ) - { - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ( GLintptr )indexBuffer->GetAPIObject() ); - backEnd.glState.currentIndexBuffer = ( GLintptr )indexBuffer->GetAPIObject(); - } - - if( ( backEnd.glState.vertexLayout != LAYOUT_DRAW_VERT ) || ( backEnd.glState.currentVertexBuffer != ( GLintptr )vertexBuffer->GetAPIObject() ) || !r_useStateCaching.GetBool() ) - { - glBindBuffer( GL_ARRAY_BUFFER, ( GLintptr )vertexBuffer->GetAPIObject() ); - backEnd.glState.currentVertexBuffer = ( GLintptr )vertexBuffer->GetAPIObject(); - - glEnableVertexAttribArray( PC_ATTRIB_INDEX_VERTEX ); - glEnableVertexAttribArray( PC_ATTRIB_INDEX_NORMAL ); - glEnableVertexAttribArray( PC_ATTRIB_INDEX_COLOR ); - glEnableVertexAttribArray( PC_ATTRIB_INDEX_COLOR2 ); - glEnableVertexAttribArray( PC_ATTRIB_INDEX_ST ); - glEnableVertexAttribArray( PC_ATTRIB_INDEX_TANGENT ); - -#if defined(USE_GLES2) || defined(USE_GLES3) - glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_XYZ_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_NORMAL, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_NORMAL_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_COLOR_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_COLOR2_OFFSET ) ); -#if defined(USE_ANGLE) - glVertexAttribPointer( PC_ATTRIB_INDEX_ST, 2, GL_HALF_FLOAT_OES, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_ST_OFFSET ) ); -#else - glVertexAttribPointer( PC_ATTRIB_INDEX_ST, 2, GL_HALF_FLOAT, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_ST_OFFSET ) ); -#endif - glVertexAttribPointer( PC_ATTRIB_INDEX_TANGENT, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( vertOffset + DRAWVERT_TANGENT_OFFSET ) ); - -#else - glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof( idDrawVert ), ( void* )( DRAWVERT_XYZ_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_NORMAL, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( DRAWVERT_NORMAL_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( DRAWVERT_COLOR_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( DRAWVERT_COLOR2_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_ST, 2, GL_HALF_FLOAT, GL_TRUE, sizeof( idDrawVert ), ( void* )( DRAWVERT_ST_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_TANGENT, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), ( void* )( DRAWVERT_TANGENT_OFFSET ) ); -#endif // #if defined(USE_GLES2) || defined(USE_GLES3) - - backEnd.glState.vertexLayout = LAYOUT_DRAW_VERT; - } - // RB end - -#if defined(USE_GLES3) //defined(USE_GLES2) - glDrawElements( GL_TRIANGLES, - r_singleTriangle.GetBool() ? 3 : surf->numIndexes, - GL_INDEX_TYPE, - ( triIndex_t* )indexOffset ); -#else - glDrawElementsBaseVertex( GL_TRIANGLES, - r_singleTriangle.GetBool() ? 3 : surf->numIndexes, - GL_INDEX_TYPE, - ( triIndex_t* )indexOffset, - vertOffset / sizeof( idDrawVert ) ); -#endif - - // RB: added stats - backEnd.pc.c_drawElements++; - backEnd.pc.c_drawIndexes += surf->numIndexes; - // RB end -} - -/* -====================== -RB_GetShaderTextureMatrix -====================== -*/ -static void RB_GetShaderTextureMatrix( const float* shaderRegisters, const textureStage_t* texture, float matrix[16] ) -{ - matrix[0 * 4 + 0] = shaderRegisters[ texture->matrix[0][0] ]; - matrix[1 * 4 + 0] = shaderRegisters[ texture->matrix[0][1] ]; - matrix[2 * 4 + 0] = 0.0f; - matrix[3 * 4 + 0] = shaderRegisters[ texture->matrix[0][2] ]; - - matrix[0 * 4 + 1] = shaderRegisters[ texture->matrix[1][0] ]; - matrix[1 * 4 + 1] = shaderRegisters[ texture->matrix[1][1] ]; - matrix[2 * 4 + 1] = 0.0f; - matrix[3 * 4 + 1] = shaderRegisters[ texture->matrix[1][2] ]; - - // we attempt to keep scrolls from generating incredibly large texture values, but - // center rotations and center scales can still generate offsets that need to be > 1 - if( matrix[3 * 4 + 0] < -40.0f || matrix[12] > 40.0f ) - { - matrix[3 * 4 + 0] -= ( int )matrix[3 * 4 + 0]; - } - if( matrix[13] < -40.0f || matrix[13] > 40.0f ) - { - matrix[13] -= ( int )matrix[13]; - } - - matrix[0 * 4 + 2] = 0.0f; - matrix[1 * 4 + 2] = 0.0f; - matrix[2 * 4 + 2] = 1.0f; - matrix[3 * 4 + 2] = 0.0f; - - matrix[0 * 4 + 3] = 0.0f; - matrix[1 * 4 + 3] = 0.0f; - matrix[2 * 4 + 3] = 0.0f; - matrix[3 * 4 + 3] = 1.0f; -} - -/* -====================== -RB_LoadShaderTextureMatrix -====================== -*/ -static void RB_LoadShaderTextureMatrix( const float* shaderRegisters, const textureStage_t* texture ) -{ - float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; - float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f }; - - if( texture->hasMatrix ) - { - float matrix[16]; - RB_GetShaderTextureMatrix( shaderRegisters, texture, matrix ); - texS[0] = matrix[0 * 4 + 0]; - texS[1] = matrix[1 * 4 + 0]; - texS[2] = matrix[2 * 4 + 0]; - texS[3] = matrix[3 * 4 + 0]; - - texT[0] = matrix[0 * 4 + 1]; - texT[1] = matrix[1 * 4 + 1]; - texT[2] = matrix[2 * 4 + 1]; - texT[3] = matrix[3 * 4 + 1]; - - RENDERLOG_PRINTF( "Setting Texture Matrix\n" ); - renderLog.Indent(); - RENDERLOG_PRINTF( "Texture Matrix S : %4.3f, %4.3f, %4.3f, %4.3f\n", texS[0], texS[1], texS[2], texS[3] ); - RENDERLOG_PRINTF( "Texture Matrix T : %4.3f, %4.3f, %4.3f, %4.3f\n", texT[0], texT[1], texT[2], texT[3] ); - renderLog.Outdent(); - } - - SetVertexParm( RENDERPARM_TEXTUREMATRIX_S, texS ); - SetVertexParm( RENDERPARM_TEXTUREMATRIX_T, texT ); -} - -/* -===================== -RB_BakeTextureMatrixIntoTexgen -===================== -*/ -static void RB_BakeTextureMatrixIntoTexgen( idPlane lightProject[3], const float* textureMatrix ) -{ - float genMatrix[16]; - float final[16]; - - genMatrix[0 * 4 + 0] = lightProject[0][0]; - genMatrix[1 * 4 + 0] = lightProject[0][1]; - genMatrix[2 * 4 + 0] = lightProject[0][2]; - genMatrix[3 * 4 + 0] = lightProject[0][3]; - - genMatrix[0 * 4 + 1] = lightProject[1][0]; - genMatrix[1 * 4 + 1] = lightProject[1][1]; - genMatrix[2 * 4 + 1] = lightProject[1][2]; - genMatrix[3 * 4 + 1] = lightProject[1][3]; - - genMatrix[0 * 4 + 2] = 0.0f; - genMatrix[1 * 4 + 2] = 0.0f; - genMatrix[2 * 4 + 2] = 0.0f; - genMatrix[3 * 4 + 2] = 0.0f; - - genMatrix[0 * 4 + 3] = lightProject[2][0]; - genMatrix[1 * 4 + 3] = lightProject[2][1]; - genMatrix[2 * 4 + 3] = lightProject[2][2]; - genMatrix[3 * 4 + 3] = lightProject[2][3]; - - R_MatrixMultiply( genMatrix, textureMatrix, final ); - - lightProject[0][0] = final[0 * 4 + 0]; - lightProject[0][1] = final[1 * 4 + 0]; - lightProject[0][2] = final[2 * 4 + 0]; - lightProject[0][3] = final[3 * 4 + 0]; - - lightProject[1][0] = final[0 * 4 + 1]; - lightProject[1][1] = final[1 * 4 + 1]; - lightProject[1][2] = final[2 * 4 + 1]; - lightProject[1][3] = final[3 * 4 + 1]; -} - -/* -====================== -RB_BindVariableStageImage - -Handles generating a cinematic frame if needed -====================== -*/ -static void RB_BindVariableStageImage( const textureStage_t* texture, const float* shaderRegisters ) -{ - if( texture->cinematic ) - { - cinData_t cin; - - if( r_skipDynamicTextures.GetBool() ) - { - globalImages->defaultImage->Bind(); - return; - } - - // offset time by shaderParm[7] (FIXME: make the time offset a parameter of the shader?) - // We make no attempt to optimize for multiple identical cinematics being in view, or - // for cinematics going at a lower framerate than the renderer. - cin = texture->cinematic->ImageForTime( backEnd.viewDef->renderView.time[0] + idMath::Ftoi( 1000.0f * backEnd.viewDef->renderView.shaderParms[11] ) ); - if( cin.imageY != NULL ) - { - GL_SelectTexture( 0 ); - cin.imageY->Bind(); - GL_SelectTexture( 1 ); - cin.imageCr->Bind(); - GL_SelectTexture( 2 ); - cin.imageCb->Bind(); - - } - else if( cin.image != NULL ) - { - // Carl: A single RGB image works better with the FFMPEG BINK codec. - GL_SelectTexture( 0 ); - cin.image->Bind(); - - /* - if( backEnd.viewDef->is2Dgui ) - { - renderProgManager.BindShader_TextureVertexColor_sRGB(); - } - else - { - renderProgManager.BindShader_TextureVertexColor(); - } - */ - } - else - { - globalImages->blackImage->Bind(); - // because the shaders may have already been set - we need to make sure we are not using a bink shader which would - // display incorrectly. We may want to get rid of RB_BindVariableStageImage and inline the code so that the - // SWF GUI case is handled better, too - renderProgManager.BindShader_TextureVertexColor(); - } - } - else - { - // FIXME: see why image is invalid - if( texture->image != NULL ) - { - texture->image->Bind(); - } - } -} - -/* -================ -RB_PrepareStageTexturing -================ -*/ -static void RB_PrepareStageTexturing( const shaderStage_t* pStage, const drawSurf_t* surf ) -{ - float useTexGenParm[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - - // set the texture matrix if needed - RB_LoadShaderTextureMatrix( surf->shaderRegisters, &pStage->texture ); - - // texgens - if( pStage->texture.texgen == TG_REFLECT_CUBE ) - { - - // see if there is also a bump map specified - const shaderStage_t* bumpStage = surf->material->GetBumpStage(); - if( bumpStage != NULL ) - { - // per-pixel reflection mapping with bump mapping - GL_SelectTexture( 1 ); - bumpStage->texture.image->Bind(); - GL_SelectTexture( 0 ); - - RENDERLOG_PRINTF( "TexGen: TG_REFLECT_CUBE: Bumpy Environment\n" ); - if( surf->jointCache ) - { - renderProgManager.BindShader_BumpyEnvironmentSkinned(); - } - else - { - renderProgManager.BindShader_BumpyEnvironment(); - } - } - else - { - RENDERLOG_PRINTF( "TexGen: TG_REFLECT_CUBE: Environment\n" ); - if( surf->jointCache ) - { - renderProgManager.BindShader_EnvironmentSkinned(); - } - else - { - renderProgManager.BindShader_Environment(); - } - } - - } - else if( pStage->texture.texgen == TG_SKYBOX_CUBE ) - { - - renderProgManager.BindShader_SkyBox(); - - } - else if( pStage->texture.texgen == TG_WOBBLESKY_CUBE ) - { - - const int* parms = surf->material->GetTexGenRegisters(); - - float wobbleDegrees = surf->shaderRegisters[ parms[0] ] * ( idMath::PI / 180.0f ); - float wobbleSpeed = surf->shaderRegisters[ parms[1] ] * ( 2.0f * idMath::PI / 60.0f ); - float rotateSpeed = surf->shaderRegisters[ parms[2] ] * ( 2.0f * idMath::PI / 60.0f ); - - idVec3 axis[3]; - { - // very ad-hoc "wobble" transform - float s, c; - idMath::SinCos( wobbleSpeed * backEnd.viewDef->renderView.time[0] * 0.001f, s, c ); - - float ws, wc; - idMath::SinCos( wobbleDegrees, ws, wc ); - - axis[2][0] = ws * c; - axis[2][1] = ws * s; - axis[2][2] = wc; - - axis[1][0] = -s * s * ws; - axis[1][2] = -s * ws * ws; - axis[1][1] = idMath::Sqrt( idMath::Fabs( 1.0f - ( axis[1][0] * axis[1][0] + axis[1][2] * axis[1][2] ) ) ); - - // make the second vector exactly perpendicular to the first - axis[1] -= ( axis[2] * axis[1] ) * axis[2]; - axis[1].Normalize(); - - // construct the third with a cross - axis[0].Cross( axis[1], axis[2] ); - } - - // add the rotate - float rs, rc; - idMath::SinCos( rotateSpeed * backEnd.viewDef->renderView.time[0] * 0.001f, rs, rc ); - - float transform[12]; - transform[0 * 4 + 0] = axis[0][0] * rc + axis[1][0] * rs; - transform[0 * 4 + 1] = axis[0][1] * rc + axis[1][1] * rs; - transform[0 * 4 + 2] = axis[0][2] * rc + axis[1][2] * rs; - transform[0 * 4 + 3] = 0.0f; - - transform[1 * 4 + 0] = axis[1][0] * rc - axis[0][0] * rs; - transform[1 * 4 + 1] = axis[1][1] * rc - axis[0][1] * rs; - transform[1 * 4 + 2] = axis[1][2] * rc - axis[0][2] * rs; - transform[1 * 4 + 3] = 0.0f; - - transform[2 * 4 + 0] = axis[2][0]; - transform[2 * 4 + 1] = axis[2][1]; - transform[2 * 4 + 2] = axis[2][2]; - transform[2 * 4 + 3] = 0.0f; - - SetVertexParms( RENDERPARM_WOBBLESKY_X, transform, 3 ); - renderProgManager.BindShader_WobbleSky(); - - } - else if( ( pStage->texture.texgen == TG_SCREEN ) || ( pStage->texture.texgen == TG_SCREEN2 ) ) - { - - useTexGenParm[0] = 1.0f; - useTexGenParm[1] = 1.0f; - useTexGenParm[2] = 1.0f; - useTexGenParm[3] = 1.0f; - - float mat[16]; - R_MatrixMultiply( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, mat ); - - RENDERLOG_PRINTF( "TexGen : %s\n", ( pStage->texture.texgen == TG_SCREEN ) ? "TG_SCREEN" : "TG_SCREEN2" ); - renderLog.Indent(); - - float plane[4]; - plane[0] = mat[0 * 4 + 0]; - plane[1] = mat[1 * 4 + 0]; - plane[2] = mat[2 * 4 + 0]; - plane[3] = mat[3 * 4 + 0]; - SetVertexParm( RENDERPARM_TEXGEN_0_S, plane ); - RENDERLOG_PRINTF( "TEXGEN_S = %4.3f, %4.3f, %4.3f, %4.3f\n", plane[0], plane[1], plane[2], plane[3] ); - - plane[0] = mat[0 * 4 + 1]; - plane[1] = mat[1 * 4 + 1]; - plane[2] = mat[2 * 4 + 1]; - plane[3] = mat[3 * 4 + 1]; - SetVertexParm( RENDERPARM_TEXGEN_0_T, plane ); - RENDERLOG_PRINTF( "TEXGEN_T = %4.3f, %4.3f, %4.3f, %4.3f\n", plane[0], plane[1], plane[2], plane[3] ); - - plane[0] = mat[0 * 4 + 3]; - plane[1] = mat[1 * 4 + 3]; - plane[2] = mat[2 * 4 + 3]; - plane[3] = mat[3 * 4 + 3]; - SetVertexParm( RENDERPARM_TEXGEN_0_Q, plane ); - RENDERLOG_PRINTF( "TEXGEN_Q = %4.3f, %4.3f, %4.3f, %4.3f\n", plane[0], plane[1], plane[2], plane[3] ); - - renderLog.Outdent(); - - } - else if( pStage->texture.texgen == TG_DIFFUSE_CUBE ) - { - - // As far as I can tell, this is never used - idLib::Warning( "Using Diffuse Cube! Please contact Brian!" ); - - } - else if( pStage->texture.texgen == TG_GLASSWARP ) - { - - // As far as I can tell, this is never used - idLib::Warning( "Using GlassWarp! Please contact Brian!" ); - } - - SetVertexParm( RENDERPARM_TEXGEN_0_ENABLED, useTexGenParm ); -} - -/* -================ -RB_FinishStageTexturing -================ -*/ -static void RB_FinishStageTexturing( const shaderStage_t* pStage, const drawSurf_t* surf ) -{ - - if( pStage->texture.cinematic ) - { - // unbind the extra bink textures - GL_SelectTexture( 1 ); - globalImages->BindNull(); - GL_SelectTexture( 2 ); - globalImages->BindNull(); - GL_SelectTexture( 0 ); - } - - if( pStage->texture.texgen == TG_REFLECT_CUBE ) - { - // see if there is also a bump map specified - const shaderStage_t* bumpStage = surf->material->GetBumpStage(); - if( bumpStage != NULL ) - { - // per-pixel reflection mapping with bump mapping - GL_SelectTexture( 1 ); - globalImages->BindNull(); - GL_SelectTexture( 0 ); - } - else - { - // per-pixel reflection mapping without bump mapping - } - renderProgManager.Unbind(); - } -} - -// RB: moved this up because we need to call this several times for shadow mapping -static void RB_ResetViewportAndScissorToDefaultCamera( const viewDef_t* viewDef ) -{ - // set the window clipping - GL_Viewport( viewDef->viewport.x1, - viewDef->viewport.y1, - viewDef->viewport.x2 + 1 - viewDef->viewport.x1, - viewDef->viewport.y2 + 1 - viewDef->viewport.y1 ); - - // the scissor may be smaller than the viewport for subviews - GL_Scissor( backEnd.viewDef->viewport.x1 + viewDef->scissor.x1, - backEnd.viewDef->viewport.y1 + viewDef->scissor.y1, - viewDef->scissor.x2 + 1 - viewDef->scissor.x1, - viewDef->scissor.y2 + 1 - viewDef->scissor.y1 ); - backEnd.currentScissor = viewDef->scissor; -} -// RB end - -/* -========================================================================================= - -DEPTH BUFFER RENDERING - -========================================================================================= -*/ - -/* -================== -RB_FillDepthBufferGeneric -================== -*/ -static void RB_FillDepthBufferGeneric( const drawSurf_t* const* drawSurfs, int numDrawSurfs ) -{ - for( int i = 0; i < numDrawSurfs; i++ ) - { - const drawSurf_t* drawSurf = drawSurfs[i]; - const idMaterial* shader = drawSurf->material; - - // translucent surfaces don't put anything in the depth buffer and don't - // test against it, which makes them fail the mirror clip plane operation - if( shader->Coverage() == MC_TRANSLUCENT ) - { - continue; - } - - // get the expressions for conditionals / color / texcoords - const float* regs = drawSurf->shaderRegisters; - - // if all stages of a material have been conditioned off, don't do anything - int stage = 0; - for( ; stage < shader->GetNumStages(); stage++ ) - { - const shaderStage_t* pStage = shader->GetStage( stage ); - // check the stage enable condition - if( regs[ pStage->conditionRegister ] != 0 ) - { - break; - } - } - if( stage == shader->GetNumStages() ) - { - continue; - } - - // change the matrix if needed - if( drawSurf->space != backEnd.currentSpace ) - { - RB_SetMVP( drawSurf->space->mvp ); - - backEnd.currentSpace = drawSurf->space; - } - - uint64 surfGLState = 0; - - // set polygon offset if necessary - if( shader->TestMaterialFlag( MF_POLYGONOFFSET ) ) - { - surfGLState |= GLS_POLYGON_OFFSET; - GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); - } - - // subviews will just down-modulate the color buffer - idVec4 color; - if( shader->GetSort() == SS_SUBVIEW ) - { - surfGLState |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHFUNC_LESS; - color[0] = 1.0f; - color[1] = 1.0f; - color[2] = 1.0f; - color[3] = 1.0f; - } - else - { - // others just draw black - color[0] = 0.0f; - color[1] = 0.0f; - color[2] = 0.0f; - color[3] = 1.0f; - } - - renderLog.OpenBlock( shader->GetName() ); - - bool drawSolid = false; - if( shader->Coverage() == MC_OPAQUE ) - { - drawSolid = true; - } - else if( shader->Coverage() == MC_PERFORATED ) - { - // we may have multiple alpha tested stages - // if the only alpha tested stages are condition register omitted, - // draw a normal opaque surface - bool didDraw = false; - - // perforated surfaces may have multiple alpha tested stages - for( stage = 0; stage < shader->GetNumStages(); stage++ ) - { - const shaderStage_t* pStage = shader->GetStage( stage ); - - if( !pStage->hasAlphaTest ) - { - continue; - } - - // check the stage enable condition - if( regs[ pStage->conditionRegister ] == 0 ) - { - continue; - } - - // if we at least tried to draw an alpha tested stage, - // we won't draw the opaque surface - didDraw = true; - - // set the alpha modulate - color[3] = regs[ pStage->color.registers[3] ]; - - // skip the entire stage if alpha would be black - if( color[3] <= 0.0f ) - { - continue; - } - - uint64 stageGLState = surfGLState; - - // set privatePolygonOffset if necessary - if( pStage->privatePolygonOffset ) - { - GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * pStage->privatePolygonOffset ); - stageGLState |= GLS_POLYGON_OFFSET; - } - - GL_Color( color ); - -#ifdef USE_CORE_PROFILE - GL_State( stageGLState ); - idVec4 alphaTestValue( regs[ pStage->alphaTestRegister ] ); - SetFragmentParm( RENDERPARM_ALPHA_TEST, alphaTestValue.ToFloatPtr() ); -#else - GL_State( stageGLState | GLS_ALPHATEST_FUNC_GREATER | GLS_ALPHATEST_MAKE_REF( idMath::Ftob( 255.0f * regs[ pStage->alphaTestRegister ] ) ) ); -#endif - - if( drawSurf->jointCache ) - { - renderProgManager.BindShader_TextureVertexColorSkinned(); - } - else - { - renderProgManager.BindShader_TextureVertexColor(); - } - - RB_SetVertexColorParms( SVC_IGNORE ); - - // bind the texture - GL_SelectTexture( 0 ); - pStage->texture.image->Bind(); - - // set texture matrix and texGens - RB_PrepareStageTexturing( pStage, drawSurf ); - - // must render with less-equal for Z-Cull to work properly - assert( ( GL_GetCurrentState() & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS ); - - // draw it - RB_DrawElementsWithCounters( drawSurf ); - - // clean up - RB_FinishStageTexturing( pStage, drawSurf ); - - // unset privatePolygonOffset if necessary - if( pStage->privatePolygonOffset ) - { - GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); - } - } - - if( !didDraw ) - { - drawSolid = true; - } - } - - // draw the entire surface solid - if( drawSolid ) - { - if( shader->GetSort() == SS_SUBVIEW ) - { - renderProgManager.BindShader_Color(); - GL_Color( color ); - GL_State( surfGLState ); - } - else - { - if( drawSurf->jointCache ) - { - renderProgManager.BindShader_DepthSkinned(); - } - else - { - renderProgManager.BindShader_Depth(); - } - GL_State( surfGLState | GLS_ALPHAMASK ); - } - - // must render with less-equal for Z-Cull to work properly - assert( ( GL_GetCurrentState() & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS ); - - // draw it - RB_DrawElementsWithCounters( drawSurf ); - } - - renderLog.CloseBlock(); - } - -#ifdef USE_CORE_PROFILE - SetFragmentParm( RENDERPARM_ALPHA_TEST, vec4_zero.ToFloatPtr() ); -#endif -} - -/* -===================== -RB_FillDepthBufferFast - -Optimized fast path code. - -If there are subview surfaces, they must be guarded in the depth buffer to allow -the mirror / subview to show through underneath the current view rendering. - -Surfaces with perforated shaders need the full shader setup done, but should be -drawn after the opaque surfaces. - -The bulk of the surfaces should be simple opaque geometry that can be drawn very rapidly. - -If there are no subview surfaces, we could clear to black and use fast-Z rendering -on the 360. -===================== -*/ -static void RB_FillDepthBufferFast( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - if( numDrawSurfs == 0 ) - { - return; - } - - // if we are just doing 2D rendering, no need to fill the depth buffer - if( backEnd.viewDef->viewEntitys == NULL ) - { - return; - } - - renderLog.OpenMainBlock( MRB_FILL_DEPTH_BUFFER ); - renderLog.OpenBlock( "RB_FillDepthBufferFast" ); - - GL_StartDepthPass( backEnd.viewDef->scissor ); - - // force MVP change on first surface - backEnd.currentSpace = NULL; - - // draw all the subview surfaces, which will already be at the start of the sorted list, - // with the general purpose path - GL_State( GLS_DEFAULT ); - - int surfNum; - for( surfNum = 0; surfNum < numDrawSurfs; surfNum++ ) - { - if( drawSurfs[surfNum]->material->GetSort() != SS_SUBVIEW ) - { - break; - } - RB_FillDepthBufferGeneric( &drawSurfs[surfNum], 1 ); - } - - const drawSurf_t** perforatedSurfaces = ( const drawSurf_t** )_alloca( numDrawSurfs * sizeof( drawSurf_t* ) ); - int numPerforatedSurfaces = 0; - - // draw all the opaque surfaces and build up a list of perforated surfaces that - // we will defer drawing until all opaque surfaces are done - GL_State( GLS_DEFAULT ); - - // continue checking past the subview surfaces - for( ; surfNum < numDrawSurfs; surfNum++ ) - { - const drawSurf_t* surf = drawSurfs[ surfNum ]; - const idMaterial* shader = surf->material; - - // translucent surfaces don't put anything in the depth buffer - if( shader->Coverage() == MC_TRANSLUCENT ) - { - continue; - } - if( shader->Coverage() == MC_PERFORATED ) - { - // save for later drawing - perforatedSurfaces[ numPerforatedSurfaces ] = surf; - numPerforatedSurfaces++; - continue; - } - - // set polygon offset? - - // set mvp matrix - if( surf->space != backEnd.currentSpace ) - { - RB_SetMVP( surf->space->mvp ); - backEnd.currentSpace = surf->space; - } - - renderLog.OpenBlock( shader->GetName() ); - - if( surf->jointCache ) - { - renderProgManager.BindShader_DepthSkinned(); - } - else - { - renderProgManager.BindShader_Depth(); - } - - // must render with less-equal for Z-Cull to work properly - assert( ( GL_GetCurrentState() & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS ); - - // draw it solid - RB_DrawElementsWithCounters( surf ); - - renderLog.CloseBlock(); - } - - // draw all perforated surfaces with the general code path - if( numPerforatedSurfaces > 0 ) - { - RB_FillDepthBufferGeneric( perforatedSurfaces, numPerforatedSurfaces ); - } - - // Allow platform specific data to be collected after the depth pass. - GL_FinishDepthPass(); - - renderLog.CloseBlock(); - renderLog.CloseMainBlock(); -} - -/* -========================================================================================= - -GENERAL INTERACTION RENDERING - -========================================================================================= -*/ - -const int INTERACTION_TEXUNIT_BUMP = 0; -const int INTERACTION_TEXUNIT_FALLOFF = 1; -const int INTERACTION_TEXUNIT_PROJECTION = 2; -const int INTERACTION_TEXUNIT_DIFFUSE = 3; -const int INTERACTION_TEXUNIT_SPECULAR = 4; -const int INTERACTION_TEXUNIT_SHADOWMAPS = 5; -const int INTERACTION_TEXUNIT_JITTER = 6; - -/* -================== -RB_SetupInteractionStage -================== -*/ -static void RB_SetupInteractionStage( const shaderStage_t* surfaceStage, const float* surfaceRegs, const float lightColor[4], - idVec4 matrix[2], float color[4] ) -{ - - if( surfaceStage->texture.hasMatrix ) - { - matrix[0][0] = surfaceRegs[surfaceStage->texture.matrix[0][0]]; - matrix[0][1] = surfaceRegs[surfaceStage->texture.matrix[0][1]]; - matrix[0][2] = 0.0f; - matrix[0][3] = surfaceRegs[surfaceStage->texture.matrix[0][2]]; - - matrix[1][0] = surfaceRegs[surfaceStage->texture.matrix[1][0]]; - matrix[1][1] = surfaceRegs[surfaceStage->texture.matrix[1][1]]; - matrix[1][2] = 0.0f; - matrix[1][3] = surfaceRegs[surfaceStage->texture.matrix[1][2]]; - - // we attempt to keep scrolls from generating incredibly large texture values, but - // center rotations and center scales can still generate offsets that need to be > 1 - if( matrix[0][3] < -40.0f || matrix[0][3] > 40.0f ) - { - matrix[0][3] -= idMath::Ftoi( matrix[0][3] ); - } - if( matrix[1][3] < -40.0f || matrix[1][3] > 40.0f ) - { - matrix[1][3] -= idMath::Ftoi( matrix[1][3] ); - } - } - else - { - matrix[0][0] = 1.0f; - matrix[0][1] = 0.0f; - matrix[0][2] = 0.0f; - matrix[0][3] = 0.0f; - - matrix[1][0] = 0.0f; - matrix[1][1] = 1.0f; - matrix[1][2] = 0.0f; - matrix[1][3] = 0.0f; - } - - if( color != NULL ) - { - for( int i = 0; i < 4; i++ ) - { - // clamp here, so cards with a greater range don't look different. - // we could perform overbrighting like we do for lights, but - // it doesn't currently look worth it. - color[i] = idMath::ClampFloat( 0.0f, 1.0f, surfaceRegs[surfaceStage->color.registers[i]] ) * lightColor[i]; - } - } -} - -/* -================= -RB_DrawSingleInteraction -================= -*/ -static void RB_DrawSingleInteraction( drawInteraction_t* din ) -{ - if( din->bumpImage == NULL ) - { - // stage wasn't actually an interaction - return; - } - - if( din->diffuseImage == NULL || r_skipDiffuse.GetBool() ) - { - // this isn't a YCoCg black, but it doesn't matter, because - // the diffuseColor will also be 0 - din->diffuseImage = globalImages->blackImage; - } - if( din->specularImage == NULL || r_skipSpecular.GetBool() || din->ambientLight ) - { - din->specularImage = globalImages->blackImage; - } - if( r_skipBump.GetBool() ) - { - din->bumpImage = globalImages->flatNormalMap; - } - - // if we wouldn't draw anything, don't call the Draw function - const bool diffuseIsBlack = ( din->diffuseImage == globalImages->blackImage ) - || ( ( din->diffuseColor[0] <= 0 ) && ( din->diffuseColor[1] <= 0 ) && ( din->diffuseColor[2] <= 0 ) ); - const bool specularIsBlack = ( din->specularImage == globalImages->blackImage ) - || ( ( din->specularColor[0] <= 0 ) && ( din->specularColor[1] <= 0 ) && ( din->specularColor[2] <= 0 ) ); - if( diffuseIsBlack && specularIsBlack ) - { - return; - } - - // bump matrix - SetVertexParm( RENDERPARM_BUMPMATRIX_S, din->bumpMatrix[0].ToFloatPtr() ); - SetVertexParm( RENDERPARM_BUMPMATRIX_T, din->bumpMatrix[1].ToFloatPtr() ); - - // diffuse matrix - SetVertexParm( RENDERPARM_DIFFUSEMATRIX_S, din->diffuseMatrix[0].ToFloatPtr() ); - SetVertexParm( RENDERPARM_DIFFUSEMATRIX_T, din->diffuseMatrix[1].ToFloatPtr() ); - - // specular matrix - SetVertexParm( RENDERPARM_SPECULARMATRIX_S, din->specularMatrix[0].ToFloatPtr() ); - SetVertexParm( RENDERPARM_SPECULARMATRIX_T, din->specularMatrix[1].ToFloatPtr() ); - - RB_SetVertexColorParms( din->vertexColor ); - - SetFragmentParm( RENDERPARM_DIFFUSEMODIFIER, din->diffuseColor.ToFloatPtr() ); - SetFragmentParm( RENDERPARM_SPECULARMODIFIER, din->specularColor.ToFloatPtr() ); - - // texture 0 will be the per-surface bump map - GL_SelectTexture( INTERACTION_TEXUNIT_BUMP ); - din->bumpImage->Bind(); - - // texture 3 is the per-surface diffuse map - GL_SelectTexture( INTERACTION_TEXUNIT_DIFFUSE ); - din->diffuseImage->Bind(); - - // texture 4 is the per-surface specular map - GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR ); - din->specularImage->Bind(); - - RB_DrawElementsWithCounters( din->surf ); -} - -/* -================= -RB_SetupForFastPathInteractions - -These are common for all fast path surfaces -================= -*/ -static void RB_SetupForFastPathInteractions( const idVec4& diffuseColor, const idVec4& specularColor ) -{ - const idVec4 sMatrix( 1, 0, 0, 0 ); - const idVec4 tMatrix( 0, 1, 0, 0 ); - - // bump matrix - SetVertexParm( RENDERPARM_BUMPMATRIX_S, sMatrix.ToFloatPtr() ); - SetVertexParm( RENDERPARM_BUMPMATRIX_T, tMatrix.ToFloatPtr() ); - - // diffuse matrix - SetVertexParm( RENDERPARM_DIFFUSEMATRIX_S, sMatrix.ToFloatPtr() ); - SetVertexParm( RENDERPARM_DIFFUSEMATRIX_T, tMatrix.ToFloatPtr() ); - - // specular matrix - SetVertexParm( RENDERPARM_SPECULARMATRIX_S, sMatrix.ToFloatPtr() ); - SetVertexParm( RENDERPARM_SPECULARMATRIX_T, tMatrix.ToFloatPtr() ); - - RB_SetVertexColorParms( SVC_IGNORE ); - - SetFragmentParm( RENDERPARM_DIFFUSEMODIFIER, diffuseColor.ToFloatPtr() ); - SetFragmentParm( RENDERPARM_SPECULARMODIFIER, specularColor.ToFloatPtr() ); -} - -/* -============= -RB_RenderInteractions - -With added sorting and trivial path work. -============= -*/ -static void RB_RenderInteractions( const drawSurf_t* surfList, const viewLight_t* vLight, int depthFunc, bool performStencilTest, bool useLightDepthBounds ) -{ - if( surfList == NULL ) - { - return; - } - - // change the scissor if needed, it will be constant across all the surfaces lit by the light - if( !backEnd.currentScissor.Equals( vLight->scissorRect ) && r_useScissor.GetBool() ) - { - GL_Scissor( backEnd.viewDef->viewport.x1 + vLight->scissorRect.x1, - backEnd.viewDef->viewport.y1 + vLight->scissorRect.y1, - vLight->scissorRect.x2 + 1 - vLight->scissorRect.x1, - vLight->scissorRect.y2 + 1 - vLight->scissorRect.y1 ); - backEnd.currentScissor = vLight->scissorRect; - } - - // perform setup here that will be constant for all interactions - if( performStencilTest ) - { - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | depthFunc | GLS_STENCIL_FUNC_EQUAL | GLS_STENCIL_MAKE_REF( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK( STENCIL_SHADOW_MASK_VALUE ) ); - - } - else - { - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | depthFunc | GLS_STENCIL_FUNC_ALWAYS ); - } - - // some rare lights have multiple animating stages, loop over them outside the surface list - const idMaterial* lightShader = vLight->lightShader; - const float* lightRegs = vLight->shaderRegisters; - - drawInteraction_t inter = {}; - inter.ambientLight = lightShader->IsAmbientLight(); - - //--------------------------------- - // Split out the complex surfaces from the fast-path surfaces - // so we can do the fast path ones all in a row. - // The surfaces should already be sorted by space because they - // are added single-threaded, and there is only a negligable amount - // of benefit to trying to sort by materials. - //--------------------------------- - static const int MAX_INTERACTIONS_PER_LIGHT = 1024; - static const int MAX_COMPLEX_INTERACTIONS_PER_LIGHT = 256; - idStaticList< const drawSurf_t*, MAX_INTERACTIONS_PER_LIGHT > allSurfaces; - idStaticList< const drawSurf_t*, MAX_COMPLEX_INTERACTIONS_PER_LIGHT > complexSurfaces; - for( const drawSurf_t* walk = surfList; walk != NULL; walk = walk->nextOnLight ) - { - - // make sure the triangle culling is done - if( walk->shadowVolumeState != SHADOWVOLUME_DONE ) - { - assert( walk->shadowVolumeState == SHADOWVOLUME_UNFINISHED || walk->shadowVolumeState == SHADOWVOLUME_DONE ); - - uint64 start = Sys_Microseconds(); - while( walk->shadowVolumeState == SHADOWVOLUME_UNFINISHED ) - { - Sys_Yield(); - } - uint64 end = Sys_Microseconds(); - - backEnd.pc.shadowMicroSec += end - start; - } - - const idMaterial* surfaceShader = walk->material; - if( surfaceShader->GetFastPathBumpImage() ) - { - allSurfaces.Append( walk ); - } - else - { - complexSurfaces.Append( walk ); - } - } - for( int i = 0; i < complexSurfaces.Num(); i++ ) - { - allSurfaces.Append( complexSurfaces[i] ); - } - - bool lightDepthBoundsDisabled = false; - - // RB begin - if( r_useShadowMapping.GetBool() ) - { - const static int JITTER_SIZE = 128; - - // default high quality - float jitterSampleScale = 1.0f; - float shadowMapSamples = r_shadowMapSamples.GetInteger(); - - // screen power of two correction factor - float screenCorrectionParm[4]; - screenCorrectionParm[0] = 1.0f / ( JITTER_SIZE * shadowMapSamples ) ; - screenCorrectionParm[1] = 1.0f / JITTER_SIZE; - screenCorrectionParm[2] = 1.0f / shadowMapResolutions[vLight->shadowLOD]; - screenCorrectionParm[3] = vLight->parallel ? r_shadowMapSunDepthBiasScale.GetFloat() : r_shadowMapRegularDepthBiasScale.GetFloat(); - SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor - - float jitterTexScale[4]; - jitterTexScale[0] = r_shadowMapJitterScale.GetFloat() * jitterSampleScale; // TODO shadow buffer size fraction shadowMapSize / maxShadowMapSize - jitterTexScale[1] = r_shadowMapJitterScale.GetFloat() * jitterSampleScale; - jitterTexScale[2] = -r_shadowMapBiasScale.GetFloat(); - jitterTexScale[3] = 0.0f; - SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale - - float jitterTexOffset[4]; - if( r_shadowMapRandomizeJitter.GetBool() ) - { - jitterTexOffset[0] = ( rand() & 255 ) / 255.0; - jitterTexOffset[1] = ( rand() & 255 ) / 255.0; - } - else - { - jitterTexOffset[0] = 0; - jitterTexOffset[1] = 0; - } - jitterTexOffset[2] = 0.0f; - jitterTexOffset[3] = 0.0f; - SetFragmentParm( RENDERPARM_JITTERTEXOFFSET, jitterTexOffset ); // rpJitterTexOffset - - if( vLight->parallel ) - { - float cascadeDistances[4]; - cascadeDistances[0] = backEnd.viewDef->frustumSplitDistances[0]; - cascadeDistances[1] = backEnd.viewDef->frustumSplitDistances[1]; - cascadeDistances[2] = backEnd.viewDef->frustumSplitDistances[2]; - cascadeDistances[3] = backEnd.viewDef->frustumSplitDistances[3]; - SetFragmentParm( RENDERPARM_CASCADEDISTANCES, cascadeDistances ); // rpCascadeDistances - } - - } - // RB end - - float lightScale = r_useHDR.GetBool() ? 3.0f : r_lightScale.GetFloat(); - - for( int lightStageNum = 0; lightStageNum < lightShader->GetNumStages(); lightStageNum++ ) - { - const shaderStage_t* lightStage = lightShader->GetStage( lightStageNum ); - - // ignore stages that fail the condition - if( !lightRegs[ lightStage->conditionRegister ] ) - { - continue; - } - - const idVec4 lightColor( - lightScale * lightRegs[ lightStage->color.registers[0] ], - lightScale * lightRegs[ lightStage->color.registers[1] ], - lightScale * lightRegs[ lightStage->color.registers[2] ], - lightRegs[ lightStage->color.registers[3] ] ); - // apply the world-global overbright and the 2x factor for specular - const idVec4 diffuseColor = lightColor; - const idVec4 specularColor = lightColor * 2.0f; - - float lightTextureMatrix[16]; - if( lightStage->texture.hasMatrix ) - { - RB_GetShaderTextureMatrix( lightRegs, &lightStage->texture, lightTextureMatrix ); - } - - // texture 1 will be the light falloff texture - GL_SelectTexture( INTERACTION_TEXUNIT_FALLOFF ); - vLight->falloffImage->Bind(); - - // texture 2 will be the light projection texture - GL_SelectTexture( INTERACTION_TEXUNIT_PROJECTION ); - lightStage->texture.image->Bind(); - - if( r_useShadowMapping.GetBool() ) - { - // texture 5 will be the shadow maps array - GL_SelectTexture( INTERACTION_TEXUNIT_SHADOWMAPS ); - globalImages->shadowImage[vLight->shadowLOD]->Bind(); - - // texture 6 will be the jitter texture for soft shadowing - GL_SelectTexture( INTERACTION_TEXUNIT_JITTER ); - if( r_shadowMapSamples.GetInteger() == 16 ) - { - globalImages->jitterImage16->Bind(); - } - else if( r_shadowMapSamples.GetInteger() == 4 ) - { - globalImages->jitterImage4->Bind(); - } - else - { - globalImages->jitterImage1->Bind(); - } - } - - // force the light textures to not use anisotropic filtering, which is wasted on them - // all of the texture sampler parms should be constant for all interactions, only - // the actual texture image bindings will change - - //---------------------------------- - // For all surfaces on this light list, generate an interaction for this light stage - //---------------------------------- - - // setup renderparms assuming we will be drawing trivial surfaces first - RB_SetupForFastPathInteractions( diffuseColor, specularColor ); - - // even if the space does not change between light stages, each light stage may need a different lightTextureMatrix baked in - backEnd.currentSpace = NULL; - - for( int sortedSurfNum = 0; sortedSurfNum < allSurfaces.Num(); sortedSurfNum++ ) - { - const drawSurf_t* const surf = allSurfaces[ sortedSurfNum ]; - - // select the render prog - if( lightShader->IsAmbientLight() ) - { - if( surf->jointCache ) - { - renderProgManager.BindShader_InteractionAmbientSkinned(); - } - else - { - renderProgManager.BindShader_InteractionAmbient(); - } - } - else - { - if( r_useShadowMapping.GetBool() && vLight->globalShadows ) - { - // RB: we have shadow mapping enabled and shadow maps so do a shadow compare - - if( vLight->parallel ) - { - if( surf->jointCache ) - { - renderProgManager.BindShader_Interaction_ShadowMapping_Parallel_Skinned(); - } - else - { - renderProgManager.BindShader_Interaction_ShadowMapping_Parallel(); - } - } - else if( vLight->pointLight ) - { - if( surf->jointCache ) - { - renderProgManager.BindShader_Interaction_ShadowMapping_Point_Skinned(); - } - else - { - renderProgManager.BindShader_Interaction_ShadowMapping_Point(); - } - } - else - { - if( surf->jointCache ) - { - renderProgManager.BindShader_Interaction_ShadowMapping_Spot_Skinned(); - } - else - { - renderProgManager.BindShader_Interaction_ShadowMapping_Spot(); - } - } - } - else - { - if( surf->jointCache ) - { - renderProgManager.BindShader_InteractionSkinned(); - } - else - { - renderProgManager.BindShader_Interaction(); - } - } - } - - const idMaterial* surfaceShader = surf->material; - const float* surfaceRegs = surf->shaderRegisters; - - inter.surf = surf; - - // change the MVP matrix, view/light origin and light projection vectors if needed - if( surf->space != backEnd.currentSpace ) - { - backEnd.currentSpace = surf->space; - - // turn off the light depth bounds test if this model is rendered with a depth hack - if( useLightDepthBounds ) - { - if( !surf->space->weaponDepthHack && surf->space->modelDepthHack == 0.0f ) - { - if( lightDepthBoundsDisabled ) - { - GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax ); - lightDepthBoundsDisabled = false; - } - } - else - { - if( !lightDepthBoundsDisabled ) - { - GL_DepthBoundsTest( 0.0f, 0.0f ); - lightDepthBoundsDisabled = true; - } - } - } - - // model-view-projection - RB_SetMVP( surf->space->mvp ); - - // RB begin - idRenderMatrix modelMatrix; - idRenderMatrix::Transpose( *( idRenderMatrix* )surf->space->modelMatrix, modelMatrix ); - - SetVertexParms( RENDERPARM_MODELMATRIX_X, modelMatrix[0], 4 ); - - // for determining the shadow mapping cascades - idRenderMatrix modelViewMatrix, tmp; - idRenderMatrix::Transpose( *( idRenderMatrix* )surf->space->modelViewMatrix, modelViewMatrix ); - SetVertexParms( RENDERPARM_MODELVIEWMATRIX_X, modelViewMatrix[0], 4 ); - - idVec4 globalLightOrigin( vLight->globalLightOrigin.x, vLight->globalLightOrigin.y, vLight->globalLightOrigin.z, 1.0f ); - SetVertexParm( RENDERPARM_GLOBALLIGHTORIGIN, globalLightOrigin.ToFloatPtr() ); - // RB end - - // tranform the light/view origin into model local space - idVec4 localLightOrigin( 0.0f ); - idVec4 localViewOrigin( 1.0f ); - R_GlobalPointToLocal( surf->space->modelMatrix, vLight->globalLightOrigin, localLightOrigin.ToVec3() ); - R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.viewDef->renderView.vieworg, localViewOrigin.ToVec3() ); - - // set the local light/view origin - SetVertexParm( RENDERPARM_LOCALLIGHTORIGIN, localLightOrigin.ToFloatPtr() ); - SetVertexParm( RENDERPARM_LOCALVIEWORIGIN, localViewOrigin.ToFloatPtr() ); - - // transform the light project into model local space - idPlane lightProjection[4]; - for( int i = 0; i < 4; i++ ) - { - R_GlobalPlaneToLocal( surf->space->modelMatrix, vLight->lightProject[i], lightProjection[i] ); - } - - // optionally multiply the local light projection by the light texture matrix - if( lightStage->texture.hasMatrix ) - { - RB_BakeTextureMatrixIntoTexgen( lightProjection, lightTextureMatrix ); - } - - // set the light projection - SetVertexParm( RENDERPARM_LIGHTPROJECTION_S, lightProjection[0].ToFloatPtr() ); - SetVertexParm( RENDERPARM_LIGHTPROJECTION_T, lightProjection[1].ToFloatPtr() ); - SetVertexParm( RENDERPARM_LIGHTPROJECTION_Q, lightProjection[2].ToFloatPtr() ); - SetVertexParm( RENDERPARM_LIGHTFALLOFF_S, lightProjection[3].ToFloatPtr() ); - - // RB begin - if( r_useShadowMapping.GetBool() ) - { - if( vLight->parallel ) - { - for( int i = 0; i < ( r_shadowMapSplits.GetInteger() + 1 ); i++ ) - { - idRenderMatrix modelToShadowMatrix; - idRenderMatrix::Multiply( backEnd.shadowV[i], modelMatrix, modelToShadowMatrix ); - - idRenderMatrix shadowClipMVP; - idRenderMatrix::Multiply( backEnd.shadowP[i], modelToShadowMatrix, shadowClipMVP ); - - idRenderMatrix shadowWindowMVP; - idRenderMatrix::Multiply( renderMatrix_clipSpaceToWindowSpace, shadowClipMVP, shadowWindowMVP ); - - SetVertexParms( ( renderParm_t )( RENDERPARM_SHADOW_MATRIX_0_X + i * 4 ), shadowWindowMVP[0], 4 ); - } - } - else if( vLight->pointLight ) - { - for( int i = 0; i < 6; i++ ) - { - idRenderMatrix modelToShadowMatrix; - idRenderMatrix::Multiply( backEnd.shadowV[i], modelMatrix, modelToShadowMatrix ); - - idRenderMatrix shadowClipMVP; - idRenderMatrix::Multiply( backEnd.shadowP[i], modelToShadowMatrix, shadowClipMVP ); - - idRenderMatrix shadowWindowMVP; - idRenderMatrix::Multiply( renderMatrix_clipSpaceToWindowSpace, shadowClipMVP, shadowWindowMVP ); - - SetVertexParms( ( renderParm_t )( RENDERPARM_SHADOW_MATRIX_0_X + i * 4 ), shadowWindowMVP[0], 4 ); - } - } - else - { - // spot light - - idRenderMatrix modelToShadowMatrix; - idRenderMatrix::Multiply( backEnd.shadowV[0], modelMatrix, modelToShadowMatrix ); - - idRenderMatrix shadowClipMVP; - idRenderMatrix::Multiply( backEnd.shadowP[0], modelToShadowMatrix, shadowClipMVP ); - - SetVertexParms( ( renderParm_t )( RENDERPARM_SHADOW_MATRIX_0_X ), shadowClipMVP[0], 4 ); - - } - } - // RB end - } - - // check for the fast path - if( surfaceShader->GetFastPathBumpImage() && !r_skipInteractionFastPath.GetBool() ) - { - renderLog.OpenBlock( surf->material->GetName() ); - - // texture 0 will be the per-surface bump map - GL_SelectTexture( INTERACTION_TEXUNIT_BUMP ); - surfaceShader->GetFastPathBumpImage()->Bind(); - - // texture 3 is the per-surface diffuse map - GL_SelectTexture( INTERACTION_TEXUNIT_DIFFUSE ); - surfaceShader->GetFastPathDiffuseImage()->Bind(); - - // texture 4 is the per-surface specular map - GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR ); - surfaceShader->GetFastPathSpecularImage()->Bind(); - - RB_DrawElementsWithCounters( surf ); - - renderLog.CloseBlock(); - continue; - } - - renderLog.OpenBlock( surf->material->GetName() ); - - inter.bumpImage = NULL; - inter.specularImage = NULL; - inter.diffuseImage = NULL; - inter.diffuseColor[0] = inter.diffuseColor[1] = inter.diffuseColor[2] = inter.diffuseColor[3] = 0; - inter.specularColor[0] = inter.specularColor[1] = inter.specularColor[2] = inter.specularColor[3] = 0; - - // go through the individual surface stages - // - // This is somewhat arcane because of the old support for video cards that had to render - // interactions in multiple passes. - // - // We also have the very rare case of some materials that have conditional interactions - // for the "hell writing" that can be shined on them. - for( int surfaceStageNum = 0; surfaceStageNum < surfaceShader->GetNumStages(); surfaceStageNum++ ) - { - const shaderStage_t* surfaceStage = surfaceShader->GetStage( surfaceStageNum ); - - switch( surfaceStage->lighting ) - { - case SL_COVERAGE: - { - // ignore any coverage stages since they should only be used for the depth fill pass - // for diffuse stages that use alpha test. - break; - } - case SL_AMBIENT: - { - // ignore ambient stages while drawing interactions - break; - } - case SL_BUMP: - { - // ignore stage that fails the condition - if( !surfaceRegs[ surfaceStage->conditionRegister ] ) - { - break; - } - // draw any previous interaction - if( inter.bumpImage != NULL ) - { - RB_DrawSingleInteraction( &inter ); - } - inter.bumpImage = surfaceStage->texture.image; - inter.diffuseImage = NULL; - inter.specularImage = NULL; - RB_SetupInteractionStage( surfaceStage, surfaceRegs, NULL, - inter.bumpMatrix, NULL ); - break; - } - case SL_DIFFUSE: - { - // ignore stage that fails the condition - if( !surfaceRegs[ surfaceStage->conditionRegister ] ) - { - break; - } - // draw any previous interaction - if( inter.diffuseImage != NULL ) - { - RB_DrawSingleInteraction( &inter ); - } - inter.diffuseImage = surfaceStage->texture.image; - inter.vertexColor = surfaceStage->vertexColor; - RB_SetupInteractionStage( surfaceStage, surfaceRegs, diffuseColor.ToFloatPtr(), - inter.diffuseMatrix, inter.diffuseColor.ToFloatPtr() ); - break; - } - case SL_SPECULAR: - { - // ignore stage that fails the condition - if( !surfaceRegs[ surfaceStage->conditionRegister ] ) - { - break; - } - // draw any previous interaction - if( inter.specularImage != NULL ) - { - RB_DrawSingleInteraction( &inter ); - } - inter.specularImage = surfaceStage->texture.image; - inter.vertexColor = surfaceStage->vertexColor; - RB_SetupInteractionStage( surfaceStage, surfaceRegs, specularColor.ToFloatPtr(), - inter.specularMatrix, inter.specularColor.ToFloatPtr() ); - break; - } - } - } - - // draw the final interaction - RB_DrawSingleInteraction( &inter ); - - renderLog.CloseBlock(); - } - } - - if( useLightDepthBounds && lightDepthBoundsDisabled ) - { - GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax ); - } - - renderProgManager.Unbind(); -} - -// RB begin - -/* -========================================================================================= - -AMBIENT PASS RENDERING - -========================================================================================= -*/ - -/* -================== -RB_AmbientPass -================== -*/ -static void RB_AmbientPass( const drawSurf_t* const* drawSurfs, int numDrawSurfs, bool fillGbuffer ) -{ - if( fillGbuffer ) - { - if( !r_useSSGI.GetBool() && !r_useSSAO.GetBool() ) - { - return; - } - } - else - { - if( r_forceAmbient.GetFloat() <= 0 || r_skipAmbient.GetBool() ) - { - return; - } - } - - if( numDrawSurfs == 0 ) - { - return; - } - - // if we are just doing 2D rendering, no need to fill the depth buffer - if( backEnd.viewDef->viewEntitys == NULL ) - { - return; - } - - const bool hdrIsActive = ( r_useHDR.GetBool() && globalFramebuffers.hdrFBO != NULL && globalFramebuffers.hdrFBO->IsBound() ); - - /* - if( fillGbuffer ) - { - globalFramebuffers.geometryBufferFBO->Bind(); - - glClearColor( 0, 0, 0, 0 ); - glClear( GL_COLOR_BUFFER_BIT ); - } - */ - - renderLog.OpenMainBlock( MRB_AMBIENT_PASS ); - renderLog.OpenBlock( "RB_AmbientPass" ); - - // RB: not needed - // GL_StartDepthPass( backEnd.viewDef->scissor ); - - // force MVP change on first surface - backEnd.currentSpace = NULL; - - // draw all the subview surfaces, which will already be at the start of the sorted list, - // with the general purpose path - //GL_State( GLS_DEFAULT ); - - //if( fillGbuffer ) - { - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL ); - } - //else - //{ - // GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL ); - //} - - GL_Color( colorWhite ); - - const float lightScale = 1.0f; //r_lightScale.GetFloat(); - const idVec4 lightColor = colorWhite * lightScale; - // apply the world-global overbright and the 2x factor for specular - const idVec4 diffuseColor = lightColor; - const idVec4 specularColor = lightColor * 2.0f; - - idVec4 ambientColor; - float ambientBoost = 1.0f; - ambientBoost += r_useSSAO.GetBool() ? 0.2f : 0.0f; - ambientBoost *= r_useHDR.GetBool() ? 1.1f : 1.0f; - ambientColor.x = r_forceAmbient.GetFloat() * ambientBoost; - ambientColor.y = r_forceAmbient.GetFloat() * ambientBoost; - ambientColor.z = r_forceAmbient.GetFloat() * ambientBoost; - ambientColor.w = 1; - - renderProgManager.SetRenderParm( RENDERPARM_AMBIENT_COLOR, ambientColor.ToFloatPtr() ); - - // setup renderparms assuming we will be drawing trivial surfaces first - RB_SetupForFastPathInteractions( diffuseColor, specularColor ); - - for( int i = 0; i < numDrawSurfs; i++ ) - { - const drawSurf_t* drawSurf = drawSurfs[i]; - const idMaterial* surfaceMaterial = drawSurf->material; - - // translucent surfaces don't put anything in the depth buffer and don't - // test against it, which makes them fail the mirror clip plane operation - if( surfaceMaterial->Coverage() == MC_TRANSLUCENT ) - { - continue; - } - - // get the expressions for conditionals / color / texcoords - const float* surfaceRegs = drawSurf->shaderRegisters; - - // if all stages of a material have been conditioned off, don't do anything - int stage = 0; - for( ; stage < surfaceMaterial->GetNumStages(); stage++ ) - { - const shaderStage_t* pStage = surfaceMaterial->GetStage( stage ); - // check the stage enable condition - if( surfaceRegs[ pStage->conditionRegister ] != 0 ) - { - break; - } - } - if( stage == surfaceMaterial->GetNumStages() ) - { - continue; - } - - //bool isWorldModel = ( drawSurf->space->entityDef->parms.origin == vec3_origin ); - - //if( isWorldModel ) - //{ - // renderProgManager.BindShader_VertexLighting(); - //} - //else - { -#if 1 - if( fillGbuffer ) - { - // fill geometry buffer with normal/roughness information - if( drawSurf->jointCache ) - { - renderProgManager.BindShader_SmallGeometryBufferSkinned(); - } - else - { - renderProgManager.BindShader_SmallGeometryBuffer(); - } - } - else -#endif - { - // draw Quake 4 style ambient - if( drawSurf->jointCache ) - { - renderProgManager.BindShader_AmbientLightingSkinned(); - } - else - { - renderProgManager.BindShader_AmbientLighting(); - } - } - } - - // change the matrix if needed - if( drawSurf->space != backEnd.currentSpace ) - { - backEnd.currentSpace = drawSurf->space; - - RB_SetMVP( drawSurf->space->mvp ); - - // tranform the view origin into model local space - idVec4 localViewOrigin( 1.0f ); - R_GlobalPointToLocal( drawSurf->space->modelMatrix, backEnd.viewDef->renderView.vieworg, localViewOrigin.ToVec3() ); - SetVertexParm( RENDERPARM_LOCALVIEWORIGIN, localViewOrigin.ToFloatPtr() ); - - //if( !isWorldModel ) - //{ - // // tranform the light direction into model local space - // idVec3 globalLightDirection( 0.0f, 0.0f, -1.0f ); // HACK - // idVec4 localLightDirection( 0.0f ); - // R_GlobalVectorToLocal( drawSurf->space->modelMatrix, globalLightDirection, localLightDirection.ToVec3() ); - // - // SetVertexParm( RENDERPARM_LOCALLIGHTORIGIN, localLightDirection.ToFloatPtr() ); - //} - - // RB: if we want to store the normals in world space so we need the model -> world matrix - idRenderMatrix modelMatrix; - idRenderMatrix::Transpose( *( idRenderMatrix* )drawSurf->space->modelMatrix, modelMatrix ); - - SetVertexParms( RENDERPARM_MODELMATRIX_X, modelMatrix[0], 4 ); - - // RB: if we want to store the normals in camera space so we need the model -> camera matrix - float modelViewMatrixTranspose[16]; - R_MatrixTranspose( drawSurf->space->modelViewMatrix, modelViewMatrixTranspose ); - SetVertexParms( RENDERPARM_MODELVIEWMATRIX_X, modelViewMatrixTranspose, 4 ); - } - -#if 0 - if( !isWorldModel ) - { - idVec4 directedColor; - directedColor.x = drawSurf->space->gridDirectedLight.x; - directedColor.y = drawSurf->space->gridDirectedLight.y; - directedColor.z = drawSurf->space->gridDirectedLight.z; - directedColor.w = 1; - - idVec4 ambientColor; - ambientColor.x = drawSurf->space->gridAmbientLight.x; - ambientColor.y = drawSurf->space->gridAmbientLight.y; - ambientColor.z = drawSurf->space->gridAmbientLight.z; - ambientColor.w = 1; - - renderProgManager.SetRenderParm( RENDERPARM_COLOR, directedColor.ToFloatPtr() ); - renderProgManager.SetRenderParm( RENDERPARM_AMBIENT_COLOR, ambientColor.ToFloatPtr() ); - } -#endif - - /* - uint64 surfGLState = 0; - - // set polygon offset if necessary - if( surfaceMaterial->TestMaterialFlag( MF_POLYGONOFFSET ) ) - { - surfGLState |= GLS_POLYGON_OFFSET; - GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * surfaceMaterial->GetPolygonOffset() ); - } - - // subviews will just down-modulate the color buffer - idVec4 color; - if( surfaceMaterial->GetSort() == SS_SUBVIEW ) - { - surfGLState |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHFUNC_LESS; - color[0] = 1.0f; - color[1] = 1.0f; - color[2] = 1.0f; - color[3] = 1.0f; - } - else - { - // others just draw black - #if 0 - color[0] = 0.0f; - color[1] = 0.0f; - color[2] = 0.0f; - color[3] = 1.0f; - #else - color = colorWhite; - #endif - } - */ - - // check for the fast path - if( surfaceMaterial->GetFastPathBumpImage() && !r_skipInteractionFastPath.GetBool() ) - { - renderLog.OpenBlock( surfaceMaterial->GetName() ); - - // texture 0 will be the per-surface bump map - GL_SelectTexture( INTERACTION_TEXUNIT_BUMP ); - surfaceMaterial->GetFastPathBumpImage()->Bind(); - - // texture 3 is the per-surface diffuse map - GL_SelectTexture( INTERACTION_TEXUNIT_DIFFUSE ); - surfaceMaterial->GetFastPathDiffuseImage()->Bind(); - - // texture 4 is the per-surface specular map - GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR ); - surfaceMaterial->GetFastPathSpecularImage()->Bind(); - - RB_DrawElementsWithCounters( drawSurf ); - - renderLog.CloseBlock(); - continue; - } - - renderLog.OpenBlock( surfaceMaterial->GetName() ); - - //bool drawSolid = false; - - - // we may have multiple alpha tested stages - // if the only alpha tested stages are condition register omitted, - // draw a normal opaque surface - bool didDraw = false; - - drawInteraction_t inter = {}; - inter.surf = drawSurf; - inter.bumpImage = NULL; - inter.specularImage = NULL; - inter.diffuseImage = NULL; - - inter.diffuseColor[0] = inter.diffuseColor[1] = inter.diffuseColor[2] = inter.diffuseColor[3] = 1; - inter.specularColor[0] = inter.specularColor[1] = inter.specularColor[2] = inter.specularColor[3] = 0; - - // perforated surfaces may have multiple alpha tested stages - for( stage = 0; stage < surfaceMaterial->GetNumStages(); stage++ ) - { - const shaderStage_t* surfaceStage = surfaceMaterial->GetStage( stage ); - - switch( surfaceStage->lighting ) - { - case SL_COVERAGE: - { - // ignore any coverage stages since they should only be used for the depth fill pass - // for diffuse stages that use alpha test. - break; - } - - case SL_AMBIENT: - { - // ignore ambient stages while drawing interactions - break; - } - - case SL_BUMP: - { - // ignore stage that fails the condition - if( !surfaceRegs[ surfaceStage->conditionRegister ] ) - { - break; - } - // draw any previous interaction - if( inter.bumpImage != NULL ) - { - RB_DrawSingleInteraction( &inter ); - } - inter.bumpImage = surfaceStage->texture.image; - inter.diffuseImage = NULL; - inter.specularImage = NULL; - RB_SetupInteractionStage( surfaceStage, surfaceRegs, NULL, - inter.bumpMatrix, NULL ); - break; - } - - case SL_DIFFUSE: - { - // ignore stage that fails the condition - if( !surfaceRegs[ surfaceStage->conditionRegister ] ) - { - break; - } - - // draw any previous interaction - if( inter.diffuseImage != NULL ) - { - RB_DrawSingleInteraction( &inter ); - } - - inter.diffuseImage = surfaceStage->texture.image; - inter.vertexColor = surfaceStage->vertexColor; - RB_SetupInteractionStage( surfaceStage, surfaceRegs, diffuseColor.ToFloatPtr(), - inter.diffuseMatrix, inter.diffuseColor.ToFloatPtr() ); - break; - } - - case SL_SPECULAR: - { - // ignore stage that fails the condition - if( !surfaceRegs[ surfaceStage->conditionRegister ] ) - { - break; - } - // draw any previous interaction - if( inter.specularImage != NULL ) - { - RB_DrawSingleInteraction( &inter ); - } - inter.specularImage = surfaceStage->texture.image; - inter.vertexColor = surfaceStage->vertexColor; - RB_SetupInteractionStage( surfaceStage, surfaceRegs, specularColor.ToFloatPtr(), - inter.specularMatrix, inter.specularColor.ToFloatPtr() ); - break; - } - } - } - - // draw the final interaction - RB_DrawSingleInteraction( &inter ); - - renderLog.CloseBlock(); - } - -#ifdef USE_CORE_PROFILE - SetFragmentParm( RENDERPARM_ALPHA_TEST, vec4_zero.ToFloatPtr() ); -#endif - - renderLog.CloseBlock(); - renderLog.CloseMainBlock(); - - if( fillGbuffer ) - { - GL_SelectTexture( 0 ); - - // FIXME: this copies RGBA16F into _currentNormals if HDR is enabled - const idScreenRect& viewport = backEnd.viewDef->viewport; - globalImages->currentNormalsImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); - - //GL_Clear( true, false, false, STENCIL_SHADOW_TEST_VALUE, 0.0f, 0.0f, 0.0f, 1.0f, false ); - - - /* - if( hdrIsActive ) - { - globalFramebuffers.hdrFBO->Bind(); - } - else - { - Framebuffer::Unbind(); - } - */ - } - - // unbind texture units - for( int i = 0; i < 7; i++ ) - { - GL_SelectTexture( i ); - globalImages->BindNull(); - } - - renderProgManager.Unbind(); -} - -// RB end - -/* -============================================================================================== - -STENCIL SHADOW RENDERING - -============================================================================================== -*/ - -/* -===================== -RB_StencilShadowPass - -The stencil buffer should have been set to 128 on any surfaces that might receive shadows. -===================== -*/ -static void RB_StencilShadowPass( const drawSurf_t* drawSurfs, const viewLight_t* vLight ) -{ - if( r_skipShadows.GetBool() ) - { - return; - } - - if( drawSurfs == NULL ) - { - return; - } - - RENDERLOG_PRINTF( "---------- RB_StencilShadowPass ----------\n" ); - - renderProgManager.BindShader_Shadow(); - - GL_SelectTexture( 0 ); - globalImages->BindNull(); - - uint64 glState = 0; - - // for visualizing the shadows - if( r_showShadows.GetInteger() ) - { - // set the debug shadow color - SetFragmentParm( RENDERPARM_COLOR, colorMagenta.ToFloatPtr() ); - if( r_showShadows.GetInteger() == 2 ) - { - // draw filled in - glState = GLS_DEPTHMASK | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_LESS; - } - else - { - // draw as lines, filling the depth buffer - glState = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS; - } - } - else - { - // don't write to the color or depth buffer, just the stencil buffer - glState = GLS_DEPTHMASK | GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHFUNC_LESS; - } - - GL_PolygonOffset( r_shadowPolygonFactor.GetFloat(), -r_shadowPolygonOffset.GetFloat() ); - - // the actual stencil func will be set in the draw code, but we need to make sure it isn't - // disabled here, and that the value will get reset for the interactions without looking - // like a no-change-required - GL_State( glState | GLS_STENCIL_OP_FAIL_KEEP | GLS_STENCIL_OP_ZFAIL_KEEP | GLS_STENCIL_OP_PASS_INCR | - GLS_STENCIL_MAKE_REF( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK( STENCIL_SHADOW_MASK_VALUE ) | GLS_POLYGON_OFFSET ); - - // Two Sided Stencil reduces two draw calls to one for slightly faster shadows - GL_Cull( CT_TWO_SIDED ); - - - // process the chain of shadows with the current rendering state - backEnd.currentSpace = NULL; - - for( const drawSurf_t* drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight ) - { - if( drawSurf->scissorRect.IsEmpty() ) - { - continue; // !@# FIXME: find out why this is sometimes being hit! - // temporarily jump over the scissor and draw so the gl error callback doesn't get hit - } - - // make sure the shadow volume is done - if( drawSurf->shadowVolumeState != SHADOWVOLUME_DONE ) - { - assert( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED || drawSurf->shadowVolumeState == SHADOWVOLUME_DONE ); - - uint64 start = Sys_Microseconds(); - while( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED ) - { - Sys_Yield(); - } - uint64 end = Sys_Microseconds(); - - backEnd.pc.shadowMicroSec += end - start; - } - - if( drawSurf->numIndexes == 0 ) - { - continue; // a job may have created an empty shadow volume - } - - if( !backEnd.currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) - { - // change the scissor - GL_Scissor( backEnd.viewDef->viewport.x1 + drawSurf->scissorRect.x1, - backEnd.viewDef->viewport.y1 + drawSurf->scissorRect.y1, - drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1, - drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 ); - backEnd.currentScissor = drawSurf->scissorRect; - } - - if( drawSurf->space != backEnd.currentSpace ) - { - // change the matrix - RB_SetMVP( drawSurf->space->mvp ); - - // set the local light position to allow the vertex program to project the shadow volume end cap to infinity - idVec4 localLight( 0.0f ); - R_GlobalPointToLocal( drawSurf->space->modelMatrix, vLight->globalLightOrigin, localLight.ToVec3() ); - SetVertexParm( RENDERPARM_LOCALLIGHTORIGIN, localLight.ToFloatPtr() ); - - backEnd.currentSpace = drawSurf->space; - } - - if( r_showShadows.GetInteger() == 0 ) - { - if( drawSurf->jointCache ) - { - renderProgManager.BindShader_ShadowSkinned(); - } - else - { - renderProgManager.BindShader_Shadow(); - } - } - else - { - if( drawSurf->jointCache ) - { - renderProgManager.BindShader_ShadowDebugSkinned(); - } - else - { - renderProgManager.BindShader_ShadowDebug(); - } - } - - // set depth bounds per shadow - if( r_useShadowDepthBounds.GetBool() ) - { - GL_DepthBoundsTest( drawSurf->scissorRect.zmin, drawSurf->scissorRect.zmax ); - } - - // Determine whether or not the shadow volume needs to be rendered with Z-pass or - // Z-fail. It is worthwhile to spend significant resources to reduce the number of - // cases where shadow volumes need to be rendered with Z-fail because Z-fail - // rendering can be significantly slower even on today's hardware. For instance, - // on NVIDIA hardware Z-fail rendering causes the Z-Cull to be used in reverse: - // Z-near becomes Z-far (trivial accept becomes trivial reject). Using the Z-Cull - // in reverse is far less efficient because the Z-Cull only stores Z-near per 16x16 - // pixels while the Z-far is stored per 4x2 pixels. (The Z-near coallesce buffer - // which has 4x4 granularity is only used when updating the depth which is not the - // case for shadow volumes.) Note that it is also important to NOT use a Z-Cull - // reconstruct because that would clear the Z-near of the Z-Cull which results in - // no trivial rejection for Z-fail stencil shadow rendering. - - const bool renderZPass = ( drawSurf->renderZFail == 0 ) || r_forceZPassStencilShadows.GetBool(); - - - if( renderZPass ) - { - // Z-pass - glStencilOpSeparate( GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR ); - glStencilOpSeparate( GL_BACK, GL_KEEP, GL_KEEP, GL_DECR ); - } - else if( r_useStencilShadowPreload.GetBool() ) - { - // preload + Z-pass - glStencilOpSeparate( GL_FRONT, GL_KEEP, GL_DECR, GL_DECR ); - glStencilOpSeparate( GL_BACK, GL_KEEP, GL_INCR, GL_INCR ); - } - else - { - // Z-fail - } - - - // get vertex buffer - const vertCacheHandle_t vbHandle = drawSurf->shadowCache; - idVertexBuffer* vertexBuffer; - if( vertexCache.CacheIsStatic( vbHandle ) ) - { - vertexBuffer = &vertexCache.staticData.vertexBuffer; - } - else - { - const uint64 frameNum = ( int )( vbHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK; - if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) - { - idLib::Warning( "RB_DrawElementsWithCounters, vertexBuffer == NULL" ); - continue; - } - vertexBuffer = &vertexCache.frameData[vertexCache.drawListNum].vertexBuffer; - } - const int vertOffset = ( int )( vbHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK; - - // get index buffer - const vertCacheHandle_t ibHandle = drawSurf->indexCache; - idIndexBuffer* indexBuffer; - if( vertexCache.CacheIsStatic( ibHandle ) ) - { - indexBuffer = &vertexCache.staticData.indexBuffer; - } - else - { - const uint64 frameNum = ( int )( ibHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK; - if( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) - { - idLib::Warning( "RB_DrawElementsWithCounters, indexBuffer == NULL" ); - continue; - } - indexBuffer = &vertexCache.frameData[vertexCache.drawListNum].indexBuffer; - } - const uint64 indexOffset = ( int )( ibHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK; - - RENDERLOG_PRINTF( "Binding Buffers: %p %p\n", vertexBuffer, indexBuffer ); - - // RB: 64 bit fixes, changed GLuint to GLintptr - if( backEnd.glState.currentIndexBuffer != ( GLintptr )indexBuffer->GetAPIObject() || !r_useStateCaching.GetBool() ) - { - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ( GLintptr )indexBuffer->GetAPIObject() ); - backEnd.glState.currentIndexBuffer = ( GLintptr )indexBuffer->GetAPIObject(); - } - - if( drawSurf->jointCache ) - { - assert( renderProgManager.ShaderUsesJoints() ); - - idJointBuffer jointBuffer; - if( !vertexCache.GetJointBuffer( drawSurf->jointCache, &jointBuffer ) ) - { - idLib::Warning( "RB_DrawElementsWithCounters, jointBuffer == NULL" ); - continue; - } - assert( ( jointBuffer.GetOffset() & ( glConfig.uniformBufferOffsetAlignment - 1 ) ) == 0 ); - - const GLintptr ubo = reinterpret_cast< GLintptr >( jointBuffer.GetAPIObject() ); - glBindBufferRange( GL_UNIFORM_BUFFER, 0, ubo, jointBuffer.GetOffset(), jointBuffer.GetNumJoints() * sizeof( idJointMat ) ); - - if( ( backEnd.glState.vertexLayout != LAYOUT_DRAW_SHADOW_VERT_SKINNED ) || ( backEnd.glState.currentVertexBuffer != ( GLintptr )vertexBuffer->GetAPIObject() ) || !r_useStateCaching.GetBool() ) - { - glBindBuffer( GL_ARRAY_BUFFER, ( GLintptr )vertexBuffer->GetAPIObject() ); - backEnd.glState.currentVertexBuffer = ( GLintptr )vertexBuffer->GetAPIObject(); - - glEnableVertexAttribArray( PC_ATTRIB_INDEX_VERTEX ); - glDisableVertexAttribArray( PC_ATTRIB_INDEX_NORMAL ); - glEnableVertexAttribArray( PC_ATTRIB_INDEX_COLOR ); - glEnableVertexAttribArray( PC_ATTRIB_INDEX_COLOR2 ); - glDisableVertexAttribArray( PC_ATTRIB_INDEX_ST ); - glDisableVertexAttribArray( PC_ATTRIB_INDEX_TANGENT ); - -#if defined(USE_GLES2) || defined(USE_GLES3) - glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 4, GL_FLOAT, GL_FALSE, sizeof( idShadowVertSkinned ), ( void* )( vertOffset + SHADOWVERTSKINNED_XYZW_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), ( void* )( vertOffset + SHADOWVERTSKINNED_COLOR_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), ( void* )( vertOffset + SHADOWVERTSKINNED_COLOR2_OFFSET ) ); -#else - glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 4, GL_FLOAT, GL_FALSE, sizeof( idShadowVertSkinned ), ( void* )( SHADOWVERTSKINNED_XYZW_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), ( void* )( SHADOWVERTSKINNED_COLOR_OFFSET ) ); - glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), ( void* )( SHADOWVERTSKINNED_COLOR2_OFFSET ) ); -#endif - - backEnd.glState.vertexLayout = LAYOUT_DRAW_SHADOW_VERT_SKINNED; - } - - } - else - { - if( ( backEnd.glState.vertexLayout != LAYOUT_DRAW_SHADOW_VERT ) || ( backEnd.glState.currentVertexBuffer != ( GLintptr )vertexBuffer->GetAPIObject() ) || !r_useStateCaching.GetBool() ) - { - glBindBuffer( GL_ARRAY_BUFFER, ( GLintptr )vertexBuffer->GetAPIObject() ); - backEnd.glState.currentVertexBuffer = ( GLintptr )vertexBuffer->GetAPIObject(); - - glEnableVertexAttribArray( PC_ATTRIB_INDEX_VERTEX ); - glDisableVertexAttribArray( PC_ATTRIB_INDEX_NORMAL ); - glDisableVertexAttribArray( PC_ATTRIB_INDEX_COLOR ); - glDisableVertexAttribArray( PC_ATTRIB_INDEX_COLOR2 ); - glDisableVertexAttribArray( PC_ATTRIB_INDEX_ST ); - glDisableVertexAttribArray( PC_ATTRIB_INDEX_TANGENT ); - -#if defined(USE_GLES2) || defined(USE_GLES3) - glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 4, GL_FLOAT, GL_FALSE, sizeof( idShadowVert ), ( void* )( vertOffset + SHADOWVERT_XYZW_OFFSET ) ); -#else - glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 4, GL_FLOAT, GL_FALSE, sizeof( idShadowVert ), ( void* )( SHADOWVERT_XYZW_OFFSET ) ); -#endif - - backEnd.glState.vertexLayout = LAYOUT_DRAW_SHADOW_VERT; - } - } - // RB end - - renderProgManager.CommitUniforms(); - - if( drawSurf->jointCache ) - { -#if defined(USE_GLES3) //defined(USE_GLES2) - glDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset ); -#else - glDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset, vertOffset / sizeof( idShadowVertSkinned ) ); -#endif - } - else - { -#if defined(USE_GLES3) - glDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset ); -#else - glDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset, vertOffset / sizeof( idShadowVert ) ); -#endif - } - - // RB: added stats - backEnd.pc.c_shadowElements++; - backEnd.pc.c_shadowIndexes += drawSurf->numIndexes; - // RB end - - if( !renderZPass && r_useStencilShadowPreload.GetBool() ) - { - // render again with Z-pass - glStencilOpSeparate( GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR ); - glStencilOpSeparate( GL_BACK, GL_KEEP, GL_KEEP, GL_DECR ); - - if( drawSurf->jointCache ) - { -#if defined(USE_GLES3) - glDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset ); -#else - glDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset, vertOffset / sizeof( idShadowVertSkinned ) ); -#endif - } - else - { -#if defined(USE_GLES3) - glDrawElements( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset ); -#else - glDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, ( triIndex_t* )indexOffset, vertOffset / sizeof( idShadowVert ) ); -#endif - } - - // RB: added stats - backEnd.pc.c_shadowElements++; - backEnd.pc.c_shadowIndexes += drawSurf->numIndexes; - // RB end - } - } - - // cleanup the shadow specific rendering state - - GL_Cull( CT_FRONT_SIDED ); - - // reset depth bounds - if( r_useShadowDepthBounds.GetBool() ) - { - if( r_useLightDepthBounds.GetBool() ) - { - GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax ); - } - else - { - GL_DepthBoundsTest( 0.0f, 0.0f ); - } - } -} - -/* -================== -RB_StencilSelectLight - -Deform the zeroOneCubeModel to exactly cover the light volume. Render the deformed cube model to the stencil buffer in -such a way that only fragments that are directly visible and contained within the volume will be written creating a -mask to be used by the following stencil shadow and draw interaction passes. -================== -*/ -static void RB_StencilSelectLight( const viewLight_t* vLight ) -{ - renderLog.OpenBlock( "Stencil Select" ); - - // enable the light scissor - if( !backEnd.currentScissor.Equals( vLight->scissorRect ) && r_useScissor.GetBool() ) - { - GL_Scissor( backEnd.viewDef->viewport.x1 + vLight->scissorRect.x1, - backEnd.viewDef->viewport.y1 + vLight->scissorRect.y1, - vLight->scissorRect.x2 + 1 - vLight->scissorRect.x1, - vLight->scissorRect.y2 + 1 - vLight->scissorRect.y1 ); - backEnd.currentScissor = vLight->scissorRect; - } - - // clear stencil buffer to 0 (not drawable) - uint64 glStateMinusStencil = GL_GetCurrentStateMinusStencil(); - GL_State( glStateMinusStencil | GLS_STENCIL_FUNC_ALWAYS | GLS_STENCIL_MAKE_REF( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK( STENCIL_SHADOW_MASK_VALUE ) ); // make sure stencil mask passes for the clear - GL_Clear( false, false, true, 0, 0.0f, 0.0f, 0.0f, 0.0f, false ); // clear to 0 for stencil select - - // set the depthbounds - GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax ); - - - GL_State( GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS | GLS_STENCIL_FUNC_ALWAYS | GLS_STENCIL_MAKE_REF( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK( STENCIL_SHADOW_MASK_VALUE ) ); - GL_Cull( CT_TWO_SIDED ); - - renderProgManager.BindShader_Depth(); - - // set the matrix for deforming the 'zeroOneCubeModel' into the frustum to exactly cover the light volume - idRenderMatrix invProjectMVPMatrix; - idRenderMatrix::Multiply( backEnd.viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix ); - RB_SetMVP( invProjectMVPMatrix ); - - // two-sided stencil test - glStencilOpSeparate( GL_FRONT, GL_KEEP, GL_REPLACE, GL_ZERO ); - glStencilOpSeparate( GL_BACK, GL_KEEP, GL_ZERO, GL_REPLACE ); - - RB_DrawElementsWithCounters( &backEnd.zeroOneCubeSurface ); - - // reset stencil state - - GL_Cull( CT_FRONT_SIDED ); - - renderProgManager.Unbind(); - - - // unset the depthbounds - GL_DepthBoundsTest( 0.0f, 0.0f ); - - renderLog.CloseBlock(); -} - -/* -============================================================================================== - -SHADOW MAPS RENDERING - -============================================================================================== -*/ - -/* -same as D3DXMatrixOrthoOffCenterRH - -http://msdn.microsoft.com/en-us/library/bb205348(VS.85).aspx -*/ -static void MatrixOrthogonalProjectionRH( float m[16], float left, float right, float bottom, float top, float zNear, float zFar ) -{ - m[0] = 2 / ( right - left ); - m[4] = 0; - m[8] = 0; - m[12] = ( left + right ) / ( left - right ); - m[1] = 0; - m[5] = 2 / ( top - bottom ); - m[9] = 0; - m[13] = ( top + bottom ) / ( bottom - top ); - m[2] = 0; - m[6] = 0; - m[10] = 1 / ( zNear - zFar ); - m[14] = zNear / ( zNear - zFar ); - m[3] = 0; - m[7] = 0; - m[11] = 0; - m[15] = 1; -} - -void MatrixCrop( float m[16], const idVec3 mins, const idVec3 maxs ) -{ - float scaleX, scaleY, scaleZ; - float offsetX, offsetY, offsetZ; - - scaleX = 2.0f / ( maxs[0] - mins[0] ); - scaleY = 2.0f / ( maxs[1] - mins[1] ); - - offsetX = -0.5f * ( maxs[0] + mins[0] ) * scaleX; - offsetY = -0.5f * ( maxs[1] + mins[1] ) * scaleY; - - scaleZ = 1.0f / ( maxs[2] - mins[2] ); - offsetZ = -mins[2] * scaleZ; - - m[ 0] = scaleX; - m[ 4] = 0; - m[ 8] = 0; - m[12] = offsetX; - m[ 1] = 0; - m[ 5] = scaleY; - m[ 9] = 0; - m[13] = offsetY; - m[ 2] = 0; - m[ 6] = 0; - m[10] = scaleZ; - m[14] = offsetZ; - m[ 3] = 0; - m[ 7] = 0; - m[11] = 0; - m[15] = 1; -} - -void MatrixLookAtRH( float m[16], const idVec3& eye, const idVec3& dir, const idVec3& up ) -{ - idVec3 dirN; - idVec3 upN; - idVec3 sideN; - - sideN = dir.Cross( up ); - sideN.Normalize(); - - upN = sideN.Cross( dir ); - upN.Normalize(); - - dirN = dir; - dirN.Normalize(); - - m[ 0] = sideN[0]; - m[ 4] = sideN[1]; - m[ 8] = sideN[2]; - m[12] = -( sideN * eye ); - m[ 1] = upN[0]; - m[ 5] = upN[1]; - m[ 9] = upN[2]; - m[13] = -( upN * eye ); - m[ 2] = -dirN[0]; - m[ 6] = -dirN[1]; - m[10] = -dirN[2]; - m[14] = ( dirN * eye ); - m[ 3] = 0; - m[ 7] = 0; - m[11] = 0; - m[15] = 1; -} - -/* -===================== -RB_ShadowMapPass -===================== -*/ -static void RB_ShadowMapPass( const drawSurf_t* drawSurfs, const viewLight_t* vLight, int side ) -{ - if( r_skipShadows.GetBool() ) - { - return; - } - - if( drawSurfs == NULL ) - { - return; - } - - RENDERLOG_PRINTF( "---------- RB_ShadowMapPass( side = %i ) ----------\n", side ); - - renderProgManager.BindShader_Depth(); - - GL_SelectTexture( 0 ); - globalImages->BindNull(); - - uint64 glState = 0; - - // the actual stencil func will be set in the draw code, but we need to make sure it isn't - // disabled here, and that the value will get reset for the interactions without looking - // like a no-change-required - GL_State( glState | GLS_POLYGON_OFFSET ); - - switch( r_shadowMapOccluderFacing.GetInteger() ) - { - case 0: - GL_Cull( CT_FRONT_SIDED ); - GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat(), r_shadowMapPolygonOffset.GetFloat() ); - break; - - case 1: - GL_Cull( CT_BACK_SIDED ); - GL_PolygonOffset( -r_shadowMapPolygonFactor.GetFloat(), -r_shadowMapPolygonOffset.GetFloat() ); - break; - - default: - GL_Cull( CT_TWO_SIDED ); - GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat(), r_shadowMapPolygonOffset.GetFloat() ); - break; - } - - idRenderMatrix lightProjectionRenderMatrix; - idRenderMatrix lightViewRenderMatrix; - - - if( vLight->parallel && side >= 0 ) - { - assert( side >= 0 && side < 6 ); - - // original light direction is from surface to light origin - idVec3 lightDir = -vLight->lightCenter; - if( lightDir.Normalize() == 0.0f ) - { - lightDir[2] = -1.0f; - } - - idMat3 rotation = lightDir.ToMat3(); - //idAngles angles = lightDir.ToAngles(); - //idMat3 rotation = angles.ToMat3(); - - const idVec3 viewDir = backEnd.viewDef->renderView.viewaxis[0]; - const idVec3 viewPos = backEnd.viewDef->renderView.vieworg; - -#if 1 - idRenderMatrix::CreateViewMatrix( backEnd.viewDef->renderView.vieworg, rotation, lightViewRenderMatrix ); -#else - float lightViewMatrix[16]; - MatrixLookAtRH( lightViewMatrix, viewPos, lightDir, viewDir ); - idRenderMatrix::Transpose( *( idRenderMatrix* )lightViewMatrix, lightViewRenderMatrix ); -#endif - - idBounds lightBounds; - lightBounds.Clear(); - - ALIGNTYPE16 frustumCorners_t corners; - idRenderMatrix::GetFrustumCorners( corners, vLight->inverseBaseLightProject, bounds_zeroOneCube ); - - idVec4 point, transf; - for( int j = 0; j < 8; j++ ) - { - point[0] = corners.x[j]; - point[1] = corners.y[j]; - point[2] = corners.z[j]; - point[3] = 1; - - lightViewRenderMatrix.TransformPoint( point, transf ); - transf[0] /= transf[3]; - transf[1] /= transf[3]; - transf[2] /= transf[3]; - - lightBounds.AddPoint( transf.ToVec3() ); - } - - float lightProjectionMatrix[16]; - MatrixOrthogonalProjectionRH( lightProjectionMatrix, lightBounds[0][0], lightBounds[1][0], lightBounds[0][1], lightBounds[1][1], -lightBounds[1][2], -lightBounds[0][2] ); - idRenderMatrix::Transpose( *( idRenderMatrix* )lightProjectionMatrix, lightProjectionRenderMatrix ); - - - // 'frustumMVP' goes from global space -> camera local space -> camera projective space - // invert the MVP projection so we can deform zero-to-one cubes into the frustum pyramid shape and calculate global bounds - - idRenderMatrix splitFrustumInverse; - if( !idRenderMatrix::Inverse( backEnd.viewDef->frustumMVPs[FRUSTUM_CASCADE1 + side], splitFrustumInverse ) ) - { - idLib::Warning( "splitFrustumMVP invert failed" ); - } - - // splitFrustumCorners in global space - ALIGNTYPE16 frustumCorners_t splitFrustumCorners; - idRenderMatrix::GetFrustumCorners( splitFrustumCorners, splitFrustumInverse, bounds_unitCube ); - -#if 0 - idBounds splitFrustumBounds; - splitFrustumBounds.Clear(); - for( int j = 0; j < 8; j++ ) - { - point[0] = splitFrustumCorners.x[j]; - point[1] = splitFrustumCorners.y[j]; - point[2] = splitFrustumCorners.z[j]; - - splitFrustumBounds.AddPoint( point.ToVec3() ); - } - - idVec3 center = splitFrustumBounds.GetCenter(); - float radius = splitFrustumBounds.GetRadius( center ); - - //ALIGNTYPE16 frustumCorners_t splitFrustumCorners; - splitFrustumBounds[0] = idVec3( -radius, -radius, -radius ); - splitFrustumBounds[1] = idVec3( radius, radius, radius ); - splitFrustumBounds.TranslateSelf( viewPos ); - idVec3 splitFrustumCorners2[8]; - splitFrustumBounds.ToPoints( splitFrustumCorners2 ); - - for( int j = 0; j < 8; j++ ) - { - splitFrustumCorners.x[j] = splitFrustumCorners2[j].x; - splitFrustumCorners.y[j] = splitFrustumCorners2[j].y; - splitFrustumCorners.z[j] = splitFrustumCorners2[j].z; - } -#endif - - - idRenderMatrix lightViewProjectionRenderMatrix; - idRenderMatrix::Multiply( lightProjectionRenderMatrix, lightViewRenderMatrix, lightViewProjectionRenderMatrix ); - - // find the bounding box of the current split in the light's clip space - idBounds cropBounds; - cropBounds.Clear(); - for( int j = 0; j < 8; j++ ) - { - point[0] = splitFrustumCorners.x[j]; - point[1] = splitFrustumCorners.y[j]; - point[2] = splitFrustumCorners.z[j]; - point[3] = 1; - - lightViewRenderMatrix.TransformPoint( point, transf ); - transf[0] /= transf[3]; - transf[1] /= transf[3]; - transf[2] /= transf[3]; - - cropBounds.AddPoint( transf.ToVec3() ); - } - - // don't let the frustum AABB be bigger than the light AABB - if( cropBounds[0][0] < lightBounds[0][0] ) - { - cropBounds[0][0] = lightBounds[0][0]; - } - - if( cropBounds[0][1] < lightBounds[0][1] ) - { - cropBounds[0][1] = lightBounds[0][1]; - } - - if( cropBounds[1][0] > lightBounds[1][0] ) - { - cropBounds[1][0] = lightBounds[1][0]; - } - - if( cropBounds[1][1] > lightBounds[1][1] ) - { - cropBounds[1][1] = lightBounds[1][1]; - } - - cropBounds[0][2] = lightBounds[0][2]; - cropBounds[1][2] = lightBounds[1][2]; - - //float cropMatrix[16]; - //MatrixCrop(cropMatrix, cropBounds[0], cropBounds[1]); - - //idRenderMatrix cropRenderMatrix; - //idRenderMatrix::Transpose( *( idRenderMatrix* )cropMatrix, cropRenderMatrix ); - - //idRenderMatrix tmp = lightProjectionRenderMatrix; - //idRenderMatrix::Multiply( cropRenderMatrix, tmp, lightProjectionRenderMatrix ); - - MatrixOrthogonalProjectionRH( lightProjectionMatrix, cropBounds[0][0], cropBounds[1][0], cropBounds[0][1], cropBounds[1][1], -cropBounds[1][2], -cropBounds[0][2] ); - idRenderMatrix::Transpose( *( idRenderMatrix* )lightProjectionMatrix, lightProjectionRenderMatrix ); - - backEnd.shadowV[side] = lightViewRenderMatrix; - backEnd.shadowP[side] = lightProjectionRenderMatrix; - } - else if( vLight->pointLight && side >= 0 ) - { - assert( side >= 0 && side < 6 ); - - // FIXME OPTIMIZE no memset - - float viewMatrix[16]; - - idVec3 vec; - idVec3 origin = vLight->globalLightOrigin; - - // side of a point light - memset( viewMatrix, 0, sizeof( viewMatrix ) ); - switch( side ) - { - case 0: - viewMatrix[0] = 1; - viewMatrix[9] = 1; - viewMatrix[6] = -1; - break; - case 1: - viewMatrix[0] = -1; - viewMatrix[9] = -1; - viewMatrix[6] = -1; - break; - case 2: - viewMatrix[4] = 1; - viewMatrix[1] = -1; - viewMatrix[10] = 1; - break; - case 3: - viewMatrix[4] = -1; - viewMatrix[1] = -1; - viewMatrix[10] = -1; - break; - case 4: - viewMatrix[8] = 1; - viewMatrix[1] = -1; - viewMatrix[6] = -1; - break; - case 5: - viewMatrix[8] = -1; - viewMatrix[1] = 1; - viewMatrix[6] = -1; - break; - } - - viewMatrix[12] = -origin[0] * viewMatrix[0] + -origin[1] * viewMatrix[4] + -origin[2] * viewMatrix[8]; - viewMatrix[13] = -origin[0] * viewMatrix[1] + -origin[1] * viewMatrix[5] + -origin[2] * viewMatrix[9]; - viewMatrix[14] = -origin[0] * viewMatrix[2] + -origin[1] * viewMatrix[6] + -origin[2] * viewMatrix[10]; - - viewMatrix[3] = 0; - viewMatrix[7] = 0; - viewMatrix[11] = 0; - viewMatrix[15] = 1; - - // from world space to light origin, looking down the X axis - float unflippedLightViewMatrix[16]; - - // from world space to OpenGL view space, looking down the negative Z axis - float lightViewMatrix[16]; - - static float s_flipMatrix[16] = - { - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 - }; - - memcpy( unflippedLightViewMatrix, viewMatrix, sizeof( unflippedLightViewMatrix ) ); - R_MatrixMultiply( viewMatrix, s_flipMatrix, lightViewMatrix ); - - idRenderMatrix::Transpose( *( idRenderMatrix* )lightViewMatrix, lightViewRenderMatrix ); - - - - - // set up 90 degree projection matrix - const float zNear = 4; - const float fov = r_shadowMapFrustumFOV.GetFloat(); - - float ymax = zNear * tan( fov * idMath::PI / 360.0f ); - float ymin = -ymax; - - float xmax = zNear * tan( fov * idMath::PI / 360.0f ); - float xmin = -xmax; - - const float width = xmax - xmin; - const float height = ymax - ymin; - - // from OpenGL view space to OpenGL NDC ( -1 : 1 in XYZ ) - float lightProjectionMatrix[16]; - - lightProjectionMatrix[0 * 4 + 0] = 2.0f * zNear / width; - lightProjectionMatrix[1 * 4 + 0] = 0.0f; - lightProjectionMatrix[2 * 4 + 0] = ( xmax + xmin ) / width; // normally 0 - lightProjectionMatrix[3 * 4 + 0] = 0.0f; - - lightProjectionMatrix[0 * 4 + 1] = 0.0f; - lightProjectionMatrix[1 * 4 + 1] = 2.0f * zNear / height; - lightProjectionMatrix[2 * 4 + 1] = ( ymax + ymin ) / height; // normally 0 - lightProjectionMatrix[3 * 4 + 1] = 0.0f; - - // this is the far-plane-at-infinity formulation, and - // crunches the Z range slightly so w=0 vertexes do not - // rasterize right at the wraparound point - lightProjectionMatrix[0 * 4 + 2] = 0.0f; - lightProjectionMatrix[1 * 4 + 2] = 0.0f; - lightProjectionMatrix[2 * 4 + 2] = -0.999f; // adjust value to prevent imprecision issues - lightProjectionMatrix[3 * 4 + 2] = -2.0f * zNear; - - lightProjectionMatrix[0 * 4 + 3] = 0.0f; - lightProjectionMatrix[1 * 4 + 3] = 0.0f; - lightProjectionMatrix[2 * 4 + 3] = -1.0f; - lightProjectionMatrix[3 * 4 + 3] = 0.0f; - - idRenderMatrix::Transpose( *( idRenderMatrix* )lightProjectionMatrix, lightProjectionRenderMatrix ); - - backEnd.shadowV[side] = lightViewRenderMatrix; - backEnd.shadowP[side] = lightProjectionRenderMatrix; - } - else - { - lightViewRenderMatrix.Identity(); - lightProjectionRenderMatrix = vLight->baseLightProject; - - backEnd.shadowV[0] = lightViewRenderMatrix; - backEnd.shadowP[0] = lightProjectionRenderMatrix; - } - - - - globalFramebuffers.shadowFBO[vLight->shadowLOD]->Bind(); - - if( side < 0 ) - { - globalFramebuffers.shadowFBO[vLight->shadowLOD]->AttachImageDepthLayer( globalImages->shadowImage[vLight->shadowLOD], 0 ); - } - else - { - globalFramebuffers.shadowFBO[vLight->shadowLOD]->AttachImageDepthLayer( globalImages->shadowImage[vLight->shadowLOD], side ); - } - - globalFramebuffers.shadowFBO[vLight->shadowLOD]->Check(); - - GL_ViewportAndScissor( 0, 0, shadowMapResolutions[vLight->shadowLOD], shadowMapResolutions[vLight->shadowLOD] ); - - glClear( GL_DEPTH_BUFFER_BIT ); - - // process the chain of shadows with the current rendering state - backEnd.currentSpace = NULL; - - for( const drawSurf_t* drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight ) - { - -#if 1 - // make sure the shadow occluder geometry is done - if( drawSurf->shadowVolumeState != SHADOWVOLUME_DONE ) - { - assert( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED || drawSurf->shadowVolumeState == SHADOWVOLUME_DONE ); - - uint64 start = Sys_Microseconds(); - while( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED ) - { - Sys_Yield(); - } - uint64 end = Sys_Microseconds(); - - backEnd.pc.shadowMicroSec += end - start; - } -#endif - - if( drawSurf->numIndexes == 0 ) - { - continue; // a job may have created an empty shadow geometry - } - - if( drawSurf->space != backEnd.currentSpace ) - { - idRenderMatrix modelRenderMatrix; - idRenderMatrix::Transpose( *( idRenderMatrix* )drawSurf->space->modelMatrix, modelRenderMatrix ); - - idRenderMatrix modelToLightRenderMatrix; - idRenderMatrix::Multiply( lightViewRenderMatrix, modelRenderMatrix, modelToLightRenderMatrix ); - - idRenderMatrix clipMVP; - idRenderMatrix::Multiply( lightProjectionRenderMatrix, modelToLightRenderMatrix, clipMVP ); - - if( vLight->parallel ) - { - idRenderMatrix MVP; - idRenderMatrix::Multiply( renderMatrix_clipSpaceToWindowSpace, clipMVP, MVP ); - - RB_SetMVP( clipMVP ); - } - else if( side < 0 ) - { - // from OpenGL view space to OpenGL NDC ( -1 : 1 in XYZ ) - idRenderMatrix MVP; - idRenderMatrix::Multiply( renderMatrix_windowSpaceToClipSpace, clipMVP, MVP ); - - RB_SetMVP( MVP ); - } - else - { - RB_SetMVP( clipMVP ); - } - - // set the local light position to allow the vertex program to project the shadow volume end cap to infinity - /* - idVec4 localLight( 0.0f ); - R_GlobalPointToLocal( drawSurf->space->modelMatrix, vLight->globalLightOrigin, localLight.ToVec3() ); - SetVertexParm( RENDERPARM_LOCALLIGHTORIGIN, localLight.ToFloatPtr() ); - */ - - backEnd.currentSpace = drawSurf->space; - } - - bool didDraw = false; - - const idMaterial* shader = drawSurf->material; - - // get the expressions for conditionals / color / texcoords - const float* regs = drawSurf->shaderRegisters; - idVec4 color( 0, 0, 0, 1 ); - - uint64 surfGLState = 0; - - // set polygon offset if necessary - if( shader && shader->TestMaterialFlag( MF_POLYGONOFFSET ) ) - { - surfGLState |= GLS_POLYGON_OFFSET; - GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); - } - -#if 1 - if( shader && shader->Coverage() == MC_PERFORATED ) - { - // perforated surfaces may have multiple alpha tested stages - for( int stage = 0; stage < shader->GetNumStages(); stage++ ) - { - const shaderStage_t* pStage = shader->GetStage( stage ); - - if( !pStage->hasAlphaTest ) - { - continue; - } - - // check the stage enable condition - if( regs[ pStage->conditionRegister ] == 0 ) - { - continue; - } - - // if we at least tried to draw an alpha tested stage, - // we won't draw the opaque surface - didDraw = true; - - // set the alpha modulate - color[3] = regs[ pStage->color.registers[3] ]; - - // skip the entire stage if alpha would be black - if( color[3] <= 0.0f ) - { - continue; - } - - uint64 stageGLState = surfGLState; - - // set privatePolygonOffset if necessary - if( pStage->privatePolygonOffset ) - { - GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * pStage->privatePolygonOffset ); - stageGLState |= GLS_POLYGON_OFFSET; - } - - GL_Color( color ); - -#ifdef USE_CORE_PROFILE - GL_State( stageGLState ); - idVec4 alphaTestValue( regs[ pStage->alphaTestRegister ] ); - SetFragmentParm( RENDERPARM_ALPHA_TEST, alphaTestValue.ToFloatPtr() ); -#else - GL_State( stageGLState | GLS_ALPHATEST_FUNC_GREATER | GLS_ALPHATEST_MAKE_REF( idMath::Ftob( 255.0f * regs[ pStage->alphaTestRegister ] ) ) ); -#endif - - if( drawSurf->jointCache ) - { - renderProgManager.BindShader_TextureVertexColorSkinned(); - } - else - { - renderProgManager.BindShader_TextureVertexColor(); - } - - RB_SetVertexColorParms( SVC_IGNORE ); - - // bind the texture - GL_SelectTexture( 0 ); - pStage->texture.image->Bind(); - - // set texture matrix and texGens - RB_PrepareStageTexturing( pStage, drawSurf ); - - // must render with less-equal for Z-Cull to work properly - assert( ( GL_GetCurrentState() & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS ); - - // draw it - RB_DrawElementsWithCounters( drawSurf ); - - // clean up - RB_FinishStageTexturing( pStage, drawSurf ); - - // unset privatePolygonOffset if necessary - if( pStage->privatePolygonOffset ) - { - GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); - } - } - } -#endif - - if( !didDraw ) - { - if( drawSurf->jointCache ) - { - renderProgManager.BindShader_DepthSkinned(); - } - else - { - renderProgManager.BindShader_Depth(); - } - - RB_DrawElementsWithCounters( drawSurf ); - } - } - - // cleanup the shadow specific rendering state - if( r_useHDR.GetBool() ) //&& !backEnd.viewDef->is2Dgui ) - { - globalFramebuffers.hdrFBO->Bind(); - } - else - { - Framebuffer::Unbind(); - } - renderProgManager.Unbind(); - - GL_State( GLS_DEFAULT ); - GL_Cull( CT_FRONT_SIDED ); - -#ifdef USE_CORE_PROFILE - SetFragmentParm( RENDERPARM_ALPHA_TEST, vec4_zero.ToFloatPtr() ); -#endif -} - -/* -============================================================================================== - -DRAW INTERACTIONS - -============================================================================================== -*/ -/* -================== -RB_DrawInteractions -================== -*/ -static void RB_DrawInteractions( const viewDef_t* viewDef ) -{ - if( r_skipInteractions.GetBool() ) - { - return; - } - - renderLog.OpenMainBlock( MRB_DRAW_INTERACTIONS ); - renderLog.OpenBlock( "RB_DrawInteractions" ); - - GL_SelectTexture( 0 ); - - - const bool useLightDepthBounds = r_useLightDepthBounds.GetBool() && !r_useShadowMapping.GetBool(); - - // - // for each light, perform shadowing and adding - // - for( const viewLight_t* vLight = backEnd.viewDef->viewLights; vLight != NULL; vLight = vLight->next ) - { - // do fogging later - if( vLight->lightShader->IsFogLight() ) - { - continue; - } - if( vLight->lightShader->IsBlendLight() ) - { - continue; - } - - if( vLight->localInteractions == NULL && vLight->globalInteractions == NULL && vLight->translucentInteractions == NULL ) - { - continue; - } - - const idMaterial* lightShader = vLight->lightShader; - renderLog.OpenBlock( lightShader->GetName() ); - - // set the depth bounds for the whole light - if( useLightDepthBounds ) - { - GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax ); - } - - // RB: shadow mapping - if( r_useShadowMapping.GetBool() ) - { - int side, sideStop; - - if( vLight->parallel ) - { - side = 0; - sideStop = r_shadowMapSplits.GetInteger() + 1; - } - else if( vLight->pointLight ) - { - if( r_shadowMapSingleSide.GetInteger() != -1 ) - { - side = r_shadowMapSingleSide.GetInteger(); - sideStop = side + 1; - } - else - { - side = 0; - sideStop = 6; - } - } - else - { - side = -1; - sideStop = 0; - } - - for( ; side < sideStop ; side++ ) - { - RB_ShadowMapPass( vLight->globalShadows, vLight, side ); - } - - // go back from light view to default camera view - RB_ResetViewportAndScissorToDefaultCamera( viewDef ); - - if( vLight->localInteractions != NULL ) - { - renderLog.OpenBlock( "Local Light Interactions" ); - RB_RenderInteractions( vLight->localInteractions, vLight, GLS_DEPTHFUNC_EQUAL, false, useLightDepthBounds ); - renderLog.CloseBlock(); - } - - if( vLight->globalInteractions != NULL ) - { - renderLog.OpenBlock( "Global Light Interactions" ); - RB_RenderInteractions( vLight->globalInteractions, vLight, GLS_DEPTHFUNC_EQUAL, false, useLightDepthBounds ); - renderLog.CloseBlock(); - } - } - else - { - // only need to clear the stencil buffer and perform stencil testing if there are shadows - const bool performStencilTest = ( vLight->globalShadows != NULL || vLight->localShadows != NULL ) && !r_useShadowMapping.GetBool(); - - // mirror flips the sense of the stencil select, and I don't want to risk accidentally breaking it - // in the normal case, so simply disable the stencil select in the mirror case - const bool useLightStencilSelect = ( r_useLightStencilSelect.GetBool() && backEnd.viewDef->isMirror == false ); - - if( performStencilTest ) - { - if( useLightStencilSelect ) - { - // write a stencil mask for the visible light bounds to hi-stencil - RB_StencilSelectLight( vLight ); - } - else - { - // always clear whole S-Cull tiles - idScreenRect rect; - rect.x1 = ( vLight->scissorRect.x1 + 0 ) & ~15; - rect.y1 = ( vLight->scissorRect.y1 + 0 ) & ~15; - rect.x2 = ( vLight->scissorRect.x2 + 15 ) & ~15; - rect.y2 = ( vLight->scissorRect.y2 + 15 ) & ~15; - - if( !backEnd.currentScissor.Equals( rect ) && r_useScissor.GetBool() ) - { - GL_Scissor( backEnd.viewDef->viewport.x1 + rect.x1, - backEnd.viewDef->viewport.y1 + rect.y1, - rect.x2 + 1 - rect.x1, - rect.y2 + 1 - rect.y1 ); - backEnd.currentScissor = rect; - } - GL_State( GLS_DEFAULT ); // make sure stencil mask passes for the clear - GL_Clear( false, false, true, STENCIL_SHADOW_TEST_VALUE, 0.0f, 0.0f, 0.0f, 0.0f, false ); - } - } - - if( vLight->globalShadows != NULL ) - { - renderLog.OpenBlock( "Global Light Shadows" ); - RB_StencilShadowPass( vLight->globalShadows, vLight ); - renderLog.CloseBlock(); - } - - if( vLight->localInteractions != NULL ) - { - renderLog.OpenBlock( "Local Light Interactions" ); - RB_RenderInteractions( vLight->localInteractions, vLight, GLS_DEPTHFUNC_EQUAL, performStencilTest, useLightDepthBounds ); - renderLog.CloseBlock(); - } - - if( vLight->localShadows != NULL ) - { - renderLog.OpenBlock( "Local Light Shadows" ); - RB_StencilShadowPass( vLight->localShadows, vLight ); - renderLog.CloseBlock(); - } - - if( vLight->globalInteractions != NULL ) - { - renderLog.OpenBlock( "Global Light Interactions" ); - RB_RenderInteractions( vLight->globalInteractions, vLight, GLS_DEPTHFUNC_EQUAL, performStencilTest, useLightDepthBounds ); - renderLog.CloseBlock(); - } - } - // RB end - - if( vLight->translucentInteractions != NULL && !r_skipTranslucent.GetBool() ) - { - renderLog.OpenBlock( "Translucent Interactions" ); - - // Disable the depth bounds test because translucent surfaces don't work with - // the depth bounds tests since they did not write depth during the depth pass. - if( useLightDepthBounds ) - { - GL_DepthBoundsTest( 0.0f, 0.0f ); - } - - // The depth buffer wasn't filled in for translucent surfaces, so they - // can never be constrained to perforated surfaces with the depthfunc equal. - - // Translucent surfaces do not receive shadows. This is a case where a - // shadow buffer solution would work but stencil shadows do not because - // stencil shadows only affect surfaces that contribute to the view depth - // buffer and translucent surfaces do not contribute to the view depth buffer. - - RB_RenderInteractions( vLight->translucentInteractions, vLight, GLS_DEPTHFUNC_LESS, false, false ); - - renderLog.CloseBlock(); - } - - renderLog.CloseBlock(); - } - - // disable stencil shadow test - GL_State( GLS_DEFAULT ); - - // unbind texture units - for( int i = 0; i < 7; i++ ) - { - GL_SelectTexture( i ); - globalImages->BindNull(); - } - GL_SelectTexture( 0 ); - - // reset depth bounds - if( useLightDepthBounds ) - { - GL_DepthBoundsTest( 0.0f, 0.0f ); - } - - renderLog.CloseBlock(); - renderLog.CloseMainBlock(); -} - -/* -============================================================================================= - -NON-INTERACTION SHADER PASSES - -============================================================================================= -*/ - -/* -===================== -RB_DrawShaderPasses - -Draw non-light dependent passes - -If we are rendering Guis, the drawSurf_t::sort value is a depth offset that can -be multiplied by guiEye for polarity and screenSeparation for scale. -===================== -*/ -static int RB_DrawShaderPasses( const drawSurf_t* const* const drawSurfs, const int numDrawSurfs, - const float guiStereoScreenOffset, const int stereoEye ) -{ - // only obey skipAmbient if we are rendering a view - if( backEnd.viewDef->viewEntitys && r_skipAmbient.GetBool() ) - { - return numDrawSurfs; - } - - renderLog.OpenBlock( "RB_DrawShaderPasses" ); - - GL_SelectTexture( 1 ); - globalImages->BindNull(); - - GL_SelectTexture( 0 ); - - backEnd.currentSpace = ( const viewEntity_t* )1; // using NULL makes /analyze think surf->space needs to be checked... - float currentGuiStereoOffset = 0.0f; - - int i = 0; - for( ; i < numDrawSurfs; i++ ) - { - const drawSurf_t* surf = drawSurfs[i]; - const idMaterial* shader = surf->material; - - if( !shader->HasAmbient() ) - { - continue; - } - - if( shader->IsPortalSky() ) - { - continue; - } - - // some deforms may disable themselves by setting numIndexes = 0 - if( surf->numIndexes == 0 ) - { - continue; - } - - if( shader->SuppressInSubview() ) - { - continue; - } - - if( backEnd.viewDef->isXraySubview && surf->space->entityDef ) - { - if( surf->space->entityDef->parms.xrayIndex != 2 ) - { - continue; - } - } - - // we need to draw the post process shaders after we have drawn the fog lights - if( shader->GetSort() >= SS_POST_PROCESS && !backEnd.currentRenderCopied ) - { - break; - } - - // if we are rendering a 3D view and the surface's eye index doesn't match - // the current view's eye index then we skip the surface - // if the stereoEye value of a surface is 0 then we need to draw it for both eyes. - const int shaderStereoEye = shader->GetStereoEye(); - const bool isEyeValid = stereoRender_swapEyes.GetBool() ? ( shaderStereoEye == stereoEye ) : ( shaderStereoEye != stereoEye ); - if( ( stereoEye != 0 ) && ( shaderStereoEye != 0 ) && ( isEyeValid ) ) - { - continue; - } - - renderLog.OpenBlock( shader->GetName() ); - - // determine the stereoDepth offset - // guiStereoScreenOffset will always be zero for 3D views, so the != - // check will never force an update due to the current sort value. - const float thisGuiStereoOffset = guiStereoScreenOffset * surf->sort; - - // change the matrix and other space related vars if needed - if( surf->space != backEnd.currentSpace || thisGuiStereoOffset != currentGuiStereoOffset ) - { - backEnd.currentSpace = surf->space; - currentGuiStereoOffset = thisGuiStereoOffset; - - const viewEntity_t* space = backEnd.currentSpace; - - if( guiStereoScreenOffset != 0.0f ) - { - RB_SetMVPWithStereoOffset( space->mvp, currentGuiStereoOffset ); - } - else - { - RB_SetMVP( space->mvp ); - } - - // set eye position in local space - idVec4 localViewOrigin( 1.0f ); - R_GlobalPointToLocal( space->modelMatrix, backEnd.viewDef->renderView.vieworg, localViewOrigin.ToVec3() ); - SetVertexParm( RENDERPARM_LOCALVIEWORIGIN, localViewOrigin.ToFloatPtr() ); - - // set model Matrix - float modelMatrixTranspose[16]; - R_MatrixTranspose( space->modelMatrix, modelMatrixTranspose ); - SetVertexParms( RENDERPARM_MODELMATRIX_X, modelMatrixTranspose, 4 ); - - // Set ModelView Matrix - float modelViewMatrixTranspose[16]; - R_MatrixTranspose( space->modelViewMatrix, modelViewMatrixTranspose ); - SetVertexParms( RENDERPARM_MODELVIEWMATRIX_X, modelViewMatrixTranspose, 4 ); - } - - // change the scissor if needed - if( !backEnd.currentScissor.Equals( surf->scissorRect ) && r_useScissor.GetBool() ) - { - GL_Scissor( backEnd.viewDef->viewport.x1 + surf->scissorRect.x1, - backEnd.viewDef->viewport.y1 + surf->scissorRect.y1, - surf->scissorRect.x2 + 1 - surf->scissorRect.x1, - surf->scissorRect.y2 + 1 - surf->scissorRect.y1 ); - backEnd.currentScissor = surf->scissorRect; - } - - // get the expressions for conditionals / color / texcoords - const float* regs = surf->shaderRegisters; - - // set face culling appropriately - if( surf->space->isGuiSurface ) - { - GL_Cull( CT_TWO_SIDED ); - } - else - { - GL_Cull( shader->GetCullType() ); - } - - uint64 surfGLState = surf->extraGLState; - - // set polygon offset if necessary - if( shader->TestMaterialFlag( MF_POLYGONOFFSET ) ) - { - GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); - surfGLState = GLS_POLYGON_OFFSET; - } - - for( int stage = 0; stage < shader->GetNumStages(); stage++ ) - { - const shaderStage_t* pStage = shader->GetStage( stage ); - - // check the enable condition - if( regs[ pStage->conditionRegister ] == 0 ) - { - continue; - } - - // skip the stages involved in lighting - if( pStage->lighting != SL_AMBIENT ) - { - continue; - } - - uint64 stageGLState = surfGLState; - if( ( surfGLState & GLS_OVERRIDE ) == 0 ) - { - stageGLState |= pStage->drawStateBits; - } - - // skip if the stage is ( GL_ZERO, GL_ONE ), which is used for some alpha masks - if( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE ) ) - { - continue; - } - - - // see if we are a new-style stage - newShaderStage_t* newStage = pStage->newStage; - if( newStage != NULL ) - { - //-------------------------- - // - // new style stages - // - //-------------------------- - if( r_skipNewAmbient.GetBool() ) - { - continue; - } - renderLog.OpenBlock( "New Shader Stage" ); - - GL_State( stageGLState ); - - // RB: CRITICAL BUGFIX: changed newStage->glslProgram to vertexProgram and fragmentProgram - // otherwise it will result in an out of bounds crash in RB_DrawElementsWithCounters - renderProgManager.BindShader( newStage->glslProgram, newStage->vertexProgram, newStage->fragmentProgram, false ); - // RB end - - for( int j = 0; j < newStage->numVertexParms; j++ ) - { - float parm[4]; - parm[0] = regs[ newStage->vertexParms[j][0] ]; - parm[1] = regs[ newStage->vertexParms[j][1] ]; - parm[2] = regs[ newStage->vertexParms[j][2] ]; - parm[3] = regs[ newStage->vertexParms[j][3] ]; - SetVertexParm( ( renderParm_t )( RENDERPARM_USER + j ), parm ); - } - - // set rpEnableSkinning if the shader has optional support for skinning - if( surf->jointCache && renderProgManager.ShaderHasOptionalSkinning() ) - { - const idVec4 skinningParm( 1.0f ); - SetVertexParm( RENDERPARM_ENABLE_SKINNING, skinningParm.ToFloatPtr() ); - } - - // bind texture units - for( int j = 0; j < newStage->numFragmentProgramImages; j++ ) - { - idImage* image = newStage->fragmentProgramImages[j]; - if( image != NULL ) - { - GL_SelectTexture( j ); - image->Bind(); - } - } - - // draw it - RB_DrawElementsWithCounters( surf ); - - // unbind texture units - for( int j = 0; j < newStage->numFragmentProgramImages; j++ ) - { - idImage* image = newStage->fragmentProgramImages[j]; - if( image != NULL ) - { - GL_SelectTexture( j ); - globalImages->BindNull(); - } - } - - // clear rpEnableSkinning if it was set - if( surf->jointCache && renderProgManager.ShaderHasOptionalSkinning() ) - { - const idVec4 skinningParm( 0.0f ); - SetVertexParm( RENDERPARM_ENABLE_SKINNING, skinningParm.ToFloatPtr() ); - } - - GL_SelectTexture( 0 ); - renderProgManager.Unbind(); - - renderLog.CloseBlock(); - continue; - } - - //-------------------------- - // - // old style stages - // - //-------------------------- - - // set the color - idVec4 color; - color[0] = regs[ pStage->color.registers[0] ]; - color[1] = regs[ pStage->color.registers[1] ]; - color[2] = regs[ pStage->color.registers[2] ]; - color[3] = regs[ pStage->color.registers[3] ]; - - // skip the entire stage if an add would be black - if( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ) - && color[0] <= 0 && color[1] <= 0 && color[2] <= 0 ) - { - continue; - } - - // skip the entire stage if a blend would be completely transparent - if( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) - && color[3] <= 0 ) - { - continue; - } - - stageVertexColor_t svc = pStage->vertexColor; - - renderLog.OpenBlock( "Old Shader Stage" ); - GL_Color( color ); - - if( surf->space->isGuiSurface ) - { - // Force gui surfaces to always be SVC_MODULATE - svc = SVC_MODULATE; - - // use special shaders for bink cinematics - if( pStage->texture.cinematic ) - { - if( ( stageGLState & GLS_OVERRIDE ) != 0 ) - { - // This is a hack... Only SWF Guis set GLS_OVERRIDE - // Old style guis do not, and we don't want them to use the new GUI renederProg - renderProgManager.BindShader_TextureVertexColor_sRGB(); - } - else - { - renderProgManager.BindShader_TextureVertexColor(); - } - } - else - { - if( ( stageGLState & GLS_OVERRIDE ) != 0 ) - { - // This is a hack... Only SWF Guis set GLS_OVERRIDE - // Old style guis do not, and we don't want them to use the new GUI renderProg - renderProgManager.BindShader_GUI(); - } - else - { - if( surf->jointCache ) - { - renderProgManager.BindShader_TextureVertexColorSkinned(); - } - else - { - if( backEnd.viewDef->is2Dgui ) - { - // RB: 2D fullscreen drawing like warp or damage blend effects - renderProgManager.BindShader_TextureVertexColor_sRGB(); - } - else - { - renderProgManager.BindShader_TextureVertexColor(); - } - } - } - } - } - else if( ( pStage->texture.texgen == TG_SCREEN ) || ( pStage->texture.texgen == TG_SCREEN2 ) ) - { - renderProgManager.BindShader_TextureTexGenVertexColor(); - } - else if( pStage->texture.cinematic ) - { - renderProgManager.BindShader_Bink(); - } - else - { - if( surf->jointCache ) - { - renderProgManager.BindShader_TextureVertexColorSkinned(); - } - else - { - renderProgManager.BindShader_TextureVertexColor(); - } - } - - RB_SetVertexColorParms( svc ); - - // bind the texture - RB_BindVariableStageImage( &pStage->texture, regs ); - - // set privatePolygonOffset if necessary - if( pStage->privatePolygonOffset ) - { - GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * pStage->privatePolygonOffset ); - stageGLState |= GLS_POLYGON_OFFSET; - } - - // set the state - GL_State( stageGLState ); - - RB_PrepareStageTexturing( pStage, surf ); - - // draw it - RB_DrawElementsWithCounters( surf ); - - RB_FinishStageTexturing( pStage, surf ); - - // unset privatePolygonOffset if necessary - if( pStage->privatePolygonOffset ) - { - GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); - } - renderLog.CloseBlock(); - } - - renderLog.CloseBlock(); - } - - GL_Cull( CT_FRONT_SIDED ); - GL_Color( 1.0f, 1.0f, 1.0f ); - - // disable stencil shadow test - GL_State( GLS_DEFAULT ); - - // unbind texture units - for( int i = 0; i < 7; i++ ) - { - GL_SelectTexture( i ); - globalImages->BindNull(); - } - GL_SelectTexture( 0 ); - - renderLog.CloseBlock(); - return i; -} - -/* -============================================================================================= - -BLEND LIGHT PROJECTION - -============================================================================================= -*/ - -/* -===================== -RB_T_BlendLight -===================== -*/ -static void RB_T_BlendLight( const drawSurf_t* drawSurfs, const viewLight_t* vLight ) -{ - backEnd.currentSpace = NULL; - - for( const drawSurf_t* drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight ) - { - if( drawSurf->scissorRect.IsEmpty() ) - { - continue; // !@# FIXME: find out why this is sometimes being hit! - // temporarily jump over the scissor and draw so the gl error callback doesn't get hit - } - - if( !backEnd.currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) - { - // change the scissor - GL_Scissor( backEnd.viewDef->viewport.x1 + drawSurf->scissorRect.x1, - backEnd.viewDef->viewport.y1 + drawSurf->scissorRect.y1, - drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1, - drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 ); - backEnd.currentScissor = drawSurf->scissorRect; - } - - if( drawSurf->space != backEnd.currentSpace ) - { - // change the matrix - RB_SetMVP( drawSurf->space->mvp ); - - // change the light projection matrix - idPlane lightProjectInCurrentSpace[4]; - for( int i = 0; i < 4; i++ ) - { - R_GlobalPlaneToLocal( drawSurf->space->modelMatrix, vLight->lightProject[i], lightProjectInCurrentSpace[i] ); - } - - SetVertexParm( RENDERPARM_TEXGEN_0_S, lightProjectInCurrentSpace[0].ToFloatPtr() ); - SetVertexParm( RENDERPARM_TEXGEN_0_T, lightProjectInCurrentSpace[1].ToFloatPtr() ); - SetVertexParm( RENDERPARM_TEXGEN_0_Q, lightProjectInCurrentSpace[2].ToFloatPtr() ); - SetVertexParm( RENDERPARM_TEXGEN_1_S, lightProjectInCurrentSpace[3].ToFloatPtr() ); // falloff - - backEnd.currentSpace = drawSurf->space; - } - - RB_DrawElementsWithCounters( drawSurf ); - } -} - -/* -===================== -RB_BlendLight - -Dual texture together the falloff and projection texture with a blend -mode to the framebuffer, instead of interacting with the surface texture -===================== -*/ -static void RB_BlendLight( const drawSurf_t* drawSurfs, const drawSurf_t* drawSurfs2, const viewLight_t* vLight ) -{ - if( drawSurfs == NULL ) - { - return; - } - if( r_skipBlendLights.GetBool() ) - { - return; - } - renderLog.OpenBlock( vLight->lightShader->GetName() ); - - const idMaterial* lightShader = vLight->lightShader; - const float* regs = vLight->shaderRegisters; - - // texture 1 will get the falloff texture - GL_SelectTexture( 1 ); - vLight->falloffImage->Bind(); - - // texture 0 will get the projected texture - GL_SelectTexture( 0 ); - - renderProgManager.BindShader_BlendLight(); - - for( int i = 0; i < lightShader->GetNumStages(); i++ ) - { - const shaderStage_t* stage = lightShader->GetStage( i ); - - if( !regs[ stage->conditionRegister ] ) - { - continue; - } - - GL_State( GLS_DEPTHMASK | stage->drawStateBits | GLS_DEPTHFUNC_EQUAL ); - - GL_SelectTexture( 0 ); - stage->texture.image->Bind(); - - if( stage->texture.hasMatrix ) - { - RB_LoadShaderTextureMatrix( regs, &stage->texture ); - } - - // get the modulate values from the light, including alpha, unlike normal lights - idVec4 lightColor; - lightColor[0] = regs[ stage->color.registers[0] ]; - lightColor[1] = regs[ stage->color.registers[1] ]; - lightColor[2] = regs[ stage->color.registers[2] ]; - lightColor[3] = regs[ stage->color.registers[3] ]; - GL_Color( lightColor ); - - RB_T_BlendLight( drawSurfs, vLight ); - RB_T_BlendLight( drawSurfs2, vLight ); - } - - GL_SelectTexture( 1 ); - globalImages->BindNull(); - - GL_SelectTexture( 0 ); - - renderProgManager.Unbind(); - renderLog.CloseBlock(); -} - -/* -========================================================================================================= - -FOG LIGHTS - -========================================================================================================= -*/ - -/* -===================== -RB_T_BasicFog -===================== -*/ -static void RB_T_BasicFog( const drawSurf_t* drawSurfs, const idPlane fogPlanes[4], const idRenderMatrix* inverseBaseLightProject ) -{ - backEnd.currentSpace = NULL; - - for( const drawSurf_t* drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight ) - { - if( drawSurf->scissorRect.IsEmpty() ) - { - continue; // !@# FIXME: find out why this is sometimes being hit! - // temporarily jump over the scissor and draw so the gl error callback doesn't get hit - } - - if( !backEnd.currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) - { - // change the scissor - GL_Scissor( backEnd.viewDef->viewport.x1 + drawSurf->scissorRect.x1, - backEnd.viewDef->viewport.y1 + drawSurf->scissorRect.y1, - drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1, - drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 ); - backEnd.currentScissor = drawSurf->scissorRect; - } - - if( drawSurf->space != backEnd.currentSpace ) - { - idPlane localFogPlanes[4]; - if( inverseBaseLightProject == NULL ) - { - RB_SetMVP( drawSurf->space->mvp ); - for( int i = 0; i < 4; i++ ) - { - R_GlobalPlaneToLocal( drawSurf->space->modelMatrix, fogPlanes[i], localFogPlanes[i] ); - } - } - else - { - idRenderMatrix invProjectMVPMatrix; - idRenderMatrix::Multiply( backEnd.viewDef->worldSpace.mvp, *inverseBaseLightProject, invProjectMVPMatrix ); - RB_SetMVP( invProjectMVPMatrix ); - for( int i = 0; i < 4; i++ ) - { - inverseBaseLightProject->InverseTransformPlane( fogPlanes[i], localFogPlanes[i], false ); - } - } - - SetVertexParm( RENDERPARM_TEXGEN_0_S, localFogPlanes[0].ToFloatPtr() ); - SetVertexParm( RENDERPARM_TEXGEN_0_T, localFogPlanes[1].ToFloatPtr() ); - SetVertexParm( RENDERPARM_TEXGEN_1_T, localFogPlanes[2].ToFloatPtr() ); - SetVertexParm( RENDERPARM_TEXGEN_1_S, localFogPlanes[3].ToFloatPtr() ); - - backEnd.currentSpace = ( inverseBaseLightProject == NULL ) ? drawSurf->space : NULL; - } - - if( drawSurf->jointCache ) - { - renderProgManager.BindShader_FogSkinned(); - } - else - { - renderProgManager.BindShader_Fog(); - } - - RB_DrawElementsWithCounters( drawSurf ); - } -} - -/* -================== -RB_FogPass -================== -*/ -static void RB_FogPass( const drawSurf_t* drawSurfs, const drawSurf_t* drawSurfs2, const viewLight_t* vLight ) -{ - renderLog.OpenBlock( vLight->lightShader->GetName() ); - - // find the current color and density of the fog - const idMaterial* lightShader = vLight->lightShader; - const float* regs = vLight->shaderRegisters; - // assume fog shaders have only a single stage - const shaderStage_t* stage = lightShader->GetStage( 0 ); - - idVec4 lightColor; - lightColor[0] = regs[ stage->color.registers[0] ]; - lightColor[1] = regs[ stage->color.registers[1] ]; - lightColor[2] = regs[ stage->color.registers[2] ]; - lightColor[3] = regs[ stage->color.registers[3] ]; - - GL_Color( lightColor ); - - // calculate the falloff planes - float a; - - // if they left the default value on, set a fog distance of 500 - if( lightColor[3] <= 1.0f ) - { - a = -0.5f / DEFAULT_FOG_DISTANCE; - } - else - { - // otherwise, distance = alpha color - a = -0.5f / lightColor[3]; - } - - // texture 0 is the falloff image - GL_SelectTexture( 0 ); - globalImages->fogImage->Bind(); - - // texture 1 is the entering plane fade correction - GL_SelectTexture( 1 ); - globalImages->fogEnterImage->Bind(); - - // S is based on the view origin - const float s = vLight->fogPlane.Distance( backEnd.viewDef->renderView.vieworg ); - - const float FOG_SCALE = 0.001f; - - idPlane fogPlanes[4]; - - // S-0 - fogPlanes[0][0] = a * backEnd.viewDef->worldSpace.modelViewMatrix[0 * 4 + 2]; - fogPlanes[0][1] = a * backEnd.viewDef->worldSpace.modelViewMatrix[1 * 4 + 2]; - fogPlanes[0][2] = a * backEnd.viewDef->worldSpace.modelViewMatrix[2 * 4 + 2]; - fogPlanes[0][3] = a * backEnd.viewDef->worldSpace.modelViewMatrix[3 * 4 + 2] + 0.5f; - - // T-0 - fogPlanes[1][0] = 0.0f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[0*4+0]; - fogPlanes[1][1] = 0.0f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[1*4+0]; - fogPlanes[1][2] = 0.0f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[2*4+0]; - fogPlanes[1][3] = 0.5f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[3*4+0] + 0.5f; - - // T-1 will get a texgen for the fade plane, which is always the "top" plane on unrotated lights - fogPlanes[2][0] = FOG_SCALE * vLight->fogPlane[0]; - fogPlanes[2][1] = FOG_SCALE * vLight->fogPlane[1]; - fogPlanes[2][2] = FOG_SCALE * vLight->fogPlane[2]; - fogPlanes[2][3] = FOG_SCALE * vLight->fogPlane[3] + FOG_ENTER; - - // S-1 - fogPlanes[3][0] = 0.0f; - fogPlanes[3][1] = 0.0f; - fogPlanes[3][2] = 0.0f; - fogPlanes[3][3] = FOG_SCALE * s + FOG_ENTER; - - // draw it - GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); - RB_T_BasicFog( drawSurfs, fogPlanes, NULL ); - RB_T_BasicFog( drawSurfs2, fogPlanes, NULL ); - - // the light frustum bounding planes aren't in the depth buffer, so use depthfunc_less instead - // of depthfunc_equal - GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_LESS ); - GL_Cull( CT_BACK_SIDED ); - - backEnd.zeroOneCubeSurface.space = &backEnd.viewDef->worldSpace; - backEnd.zeroOneCubeSurface.scissorRect = backEnd.viewDef->scissor; - RB_T_BasicFog( &backEnd.zeroOneCubeSurface, fogPlanes, &vLight->inverseBaseLightProject ); - - GL_Cull( CT_FRONT_SIDED ); - - GL_SelectTexture( 1 ); - globalImages->BindNull(); - - GL_SelectTexture( 0 ); - - renderProgManager.Unbind(); - - renderLog.CloseBlock(); -} - -/* -================== -RB_FogAllLights -================== -*/ -static void RB_FogAllLights() -{ - if( r_skipFogLights.GetBool() || r_showOverDraw.GetInteger() != 0 - || backEnd.viewDef->isXraySubview /* don't fog in xray mode*/ ) - { - return; - } - renderLog.OpenMainBlock( MRB_FOG_ALL_LIGHTS ); - renderLog.OpenBlock( "RB_FogAllLights" ); - - // force fog plane to recalculate - backEnd.currentSpace = NULL; - - for( viewLight_t* vLight = backEnd.viewDef->viewLights; vLight != NULL; vLight = vLight->next ) - { - if( vLight->lightShader->IsFogLight() ) - { - RB_FogPass( vLight->globalInteractions, vLight->localInteractions, vLight ); - } - else if( vLight->lightShader->IsBlendLight() ) - { - RB_BlendLight( vLight->globalInteractions, vLight->localInteractions, vLight ); - } - } - - renderLog.CloseBlock(); - renderLog.CloseMainBlock(); -} - -// RB begin -static void RB_CalculateAdaptation() -{ - int i; - static float image[64 * 64 * 4]; - float curTime; - float deltaTime; - float luminance; - float avgLuminance; - float maxLuminance; - double sum; - const idVec3 LUMINANCE_SRGB( 0.2125f, 0.7154f, 0.0721f ); // be careful wether this should be linear RGB or sRGB - idVec4 color; - float newAdaptation; - float newMaximum; - - if( !r_hdrAutoExposure.GetBool() ) - { - // no dynamic exposure - - backEnd.hdrKey = r_hdrKey.GetFloat(); - backEnd.hdrAverageLuminance = r_hdrMinLuminance.GetFloat(); - backEnd.hdrMaxLuminance = 1; - } - else - { - curTime = Sys_Milliseconds() / 1000.0f; - - // calculate the average scene luminance - globalFramebuffers.hdr64FBO->Bind(); - - // read back the contents - // glFinish(); - glReadPixels( 0, 0, 64, 64, GL_RGBA, GL_FLOAT, image ); - - sum = 0.0f; - maxLuminance = 0.0f; - for( i = 0; i < ( 64 * 64 ); i += 4 ) - { - color[0] = image[i * 4 + 0]; - color[1] = image[i * 4 + 1]; - color[2] = image[i * 4 + 2]; - color[3] = image[i * 4 + 3]; - - luminance = ( color.x * LUMINANCE_SRGB.x + color.y * LUMINANCE_SRGB.y + color.z * LUMINANCE_SRGB.z ) + 0.0001f; - if( luminance > maxLuminance ) - { - maxLuminance = luminance; - } - - float logLuminance = log( luminance + 1 ); - //if( logLuminance > 0 ) - { - sum += luminance; - } - } -#if 0 - sum /= ( 64.0f * 64.0f ); - avgLuminance = exp( sum ); -#else - avgLuminance = sum / ( 64.0f * 64.0f ); -#endif - - // the user's adapted luminance level is simulated by closing the gap between - // adapted luminance and current luminance by 2% every frame, based on a - // 30 fps rate. This is not an accurate model of human adaptation, which can - // take longer than half an hour. - if( backEnd.hdrTime > curTime ) - { - backEnd.hdrTime = curTime; - } - - deltaTime = curTime - backEnd.hdrTime; - - //if(r_hdrMaxLuminance->value) - { - backEnd.hdrAverageLuminance = idMath::ClampFloat( r_hdrMinLuminance.GetFloat(), r_hdrMaxLuminance.GetFloat(), backEnd.hdrAverageLuminance ); - avgLuminance = idMath::ClampFloat( r_hdrMinLuminance.GetFloat(), r_hdrMaxLuminance.GetFloat(), avgLuminance ); - - backEnd.hdrMaxLuminance = idMath::ClampFloat( r_hdrMinLuminance.GetFloat(), r_hdrMaxLuminance.GetFloat(), backEnd.hdrMaxLuminance ); - maxLuminance = idMath::ClampFloat( r_hdrMinLuminance.GetFloat(), r_hdrMaxLuminance.GetFloat(), maxLuminance ); - } - - newAdaptation = backEnd.hdrAverageLuminance + ( avgLuminance - backEnd.hdrAverageLuminance ) * ( 1.0f - powf( 0.98f, 30.0f * deltaTime ) ); - newMaximum = backEnd.hdrMaxLuminance + ( maxLuminance - backEnd.hdrMaxLuminance ) * ( 1.0f - powf( 0.98f, 30.0f * deltaTime ) ); - - if( !IsNAN( newAdaptation ) && !IsNAN( newMaximum ) ) - { -#if 1 - backEnd.hdrAverageLuminance = newAdaptation; - backEnd.hdrMaxLuminance = newMaximum; -#else - backEnd.hdrAverageLuminance = avgLuminance; - backEnd.hdrMaxLuminance = maxLuminance; -#endif - } - - backEnd.hdrTime = curTime; - - // calculate HDR image key -#if 0 - // RB: this never worked :/ - if( r_hdrAutoExposure.GetBool() ) - { - // calculation from: Perceptual Effects in Real-time Tone Mapping - Krawczyk et al. - backEnd.hdrKey = 1.03 - ( 2.0 / ( 2.0 + ( backEnd.hdrAverageLuminance + 1.0f ) ) ); - } - else -#endif - { - backEnd.hdrKey = r_hdrKey.GetFloat(); - } - } - - if( r_hdrDebug.GetBool() ) - { - idLib::Printf( "HDR luminance avg = %f, max = %f, key = %f\n", backEnd.hdrAverageLuminance, backEnd.hdrMaxLuminance, backEnd.hdrKey ); - } - - //GL_CheckErrors(); -} - - -static void RB_Tonemap( const viewDef_t* viewDef ) -{ - RENDERLOG_PRINTF( "---------- RB_Tonemap( avg = %f, max = %f, key = %f, is2Dgui = %i ) ----------\n", backEnd.hdrAverageLuminance, backEnd.hdrMaxLuminance, backEnd.hdrKey, ( int )viewDef->is2Dgui ); - - //postProcessCommand_t* cmd = ( postProcessCommand_t* )data; - //const idScreenRect& viewport = cmd->viewDef->viewport; - //globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); - - Framebuffer::Unbind(); - - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - GL_Cull( CT_TWO_SIDED ); - - int screenWidth = renderSystem->GetWidth(); - int screenHeight = renderSystem->GetHeight(); - - // set the window clipping - GL_Viewport( 0, 0, screenWidth, screenHeight ); - GL_Scissor( 0, 0, screenWidth, screenHeight ); - - GL_SelectTexture( 0 ); - -#if defined(USE_HDR_MSAA) - if( glConfig.multisamples > 0 ) - { - globalImages->currentRenderHDRImageNoMSAA->Bind(); - } - else -#endif - { - globalImages->currentRenderHDRImage->Bind(); - } - - GL_SelectTexture( 1 ); - globalImages->heatmap7Image->Bind(); - - if( r_hdrDebug.GetBool() ) - { - renderProgManager.BindShader_HDRDebug(); - } - else - { - renderProgManager.BindShader_Tonemap(); - } - - float screenCorrectionParm[4]; - if( viewDef->is2Dgui ) - { - screenCorrectionParm[0] = 2.0f; - screenCorrectionParm[1] = 1.0f; - screenCorrectionParm[2] = 1.0f; - } - else - { - if( r_hdrAutoExposure.GetBool() ) - { - float exposureOffset = Lerp( -0.01f, 0.02f, idMath::ClampFloat( 0.0, 1.0, r_exposure.GetFloat() ) ); - - screenCorrectionParm[0] = backEnd.hdrKey + exposureOffset; - screenCorrectionParm[1] = backEnd.hdrAverageLuminance; - screenCorrectionParm[2] = backEnd.hdrMaxLuminance; - screenCorrectionParm[3] = exposureOffset; - //screenCorrectionParm[3] = Lerp( -1, 5, idMath::ClampFloat( 0.0, 1.0, r_exposure.GetFloat() ) ); - } - else - { - //float exposureOffset = ( idMath::ClampFloat( 0.0, 1.0, r_exposure.GetFloat() ) * 2.0f - 1.0f ) * 0.01f; - - float exposureOffset = Lerp( -0.01f, 0.01f, idMath::ClampFloat( 0.0, 1.0, r_exposure.GetFloat() ) ); - - screenCorrectionParm[0] = 0.015f + exposureOffset; - screenCorrectionParm[1] = 0.005f; - screenCorrectionParm[2] = 1; - - // RB: this gives a nice exposure curve in Scilab when using - // log2( max( 3 + 0..10, 0.001 ) ) as input for exp2 - //float exposureOffset = r_exposure.GetFloat() * 10.0f; - //screenCorrectionParm[3] = exposureOffset; - } - } - - SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor - - // Draw - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - // unbind heatmap - globalImages->BindNull(); - - // unbind _currentRender - GL_SelectTexture( 0 ); - globalImages->BindNull(); - - renderProgManager.Unbind(); - - GL_State( GLS_DEFAULT ); - GL_Cull( CT_FRONT_SIDED ); -} - - -static void RB_Bloom( const viewDef_t* viewDef ) -{ - if( viewDef->is2Dgui || !r_useHDR.GetBool() ) - { - return; - } - - RENDERLOG_PRINTF( "---------- RB_Bloom( avg = %f, max = %f, key = %f ) ----------\n", backEnd.hdrAverageLuminance, backEnd.hdrMaxLuminance, backEnd.hdrKey ); - - // BRIGHTPASS - - //GL_CheckErrors(); - - //Framebuffer::Unbind(); - //globalFramebuffers.hdrQuarterFBO->Bind(); - - glClearColor( 0, 0, 0, 1 ); -// glClear( GL_COLOR_BUFFER_BIT ); - - GL_State( /*GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO |*/ GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - GL_Cull( CT_TWO_SIDED ); - - int screenWidth = renderSystem->GetWidth(); - int screenHeight = renderSystem->GetHeight(); - - // set the window clipping - GL_Viewport( 0, 0, screenWidth / 4, screenHeight / 4 ); - GL_Scissor( 0, 0, screenWidth / 4, screenHeight / 4 ); - - globalFramebuffers.bloomRenderFBO[ 0 ]->Bind(); - - GL_SelectTexture( 0 ); - - if( r_useHDR.GetBool() ) - { - globalImages->currentRenderHDRImage->Bind(); - - renderProgManager.BindShader_Brightpass(); - } - else - { - int x = backEnd.viewDef->viewport.x1; - int y = backEnd.viewDef->viewport.y1; - int w = backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1; - int h = backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1; - - RENDERLOG_PRINTF( "Resolve to %i x %i buffer\n", w, h ); - - // resolve the screen - globalImages->currentRenderImage->CopyFramebuffer( x, y, w, h ); - - renderProgManager.BindShader_Brightpass(); - } - - float screenCorrectionParm[4]; - screenCorrectionParm[0] = backEnd.hdrKey; - screenCorrectionParm[1] = backEnd.hdrAverageLuminance; - screenCorrectionParm[2] = backEnd.hdrMaxLuminance; - screenCorrectionParm[3] = 1.0f; - SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor - - float overbright[4]; - if( r_useHDR.GetBool() ) - { - if( r_hdrAutoExposure.GetBool() ) - { - overbright[0] = r_hdrContrastDynamicThreshold.GetFloat(); - } - else - { - overbright[0] = r_hdrContrastStaticThreshold.GetFloat(); - } - overbright[1] = r_hdrContrastOffset.GetFloat(); - overbright[2] = 0; - overbright[3] = 0; - } - else - { - overbright[0] = r_ldrContrastThreshold.GetFloat(); - overbright[1] = r_ldrContrastOffset.GetFloat(); - overbright[2] = 0; - overbright[3] = 0; - } - SetFragmentParm( RENDERPARM_OVERBRIGHT, overbright ); // rpOverbright - - // Draw - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - - // BLOOM PING PONG rendering - renderProgManager.BindShader_HDRGlareChromatic(); - - int j; - for( j = 0; j < r_hdrGlarePasses.GetInteger(); j++ ) - { - globalFramebuffers.bloomRenderFBO[( j + 1 ) % 2 ]->Bind(); - glClear( GL_COLOR_BUFFER_BIT ); - - globalImages->bloomRenderImage[j % 2]->Bind(); - - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - } - - // add filtered glare back to main context - Framebuffer::Unbind(); - - RB_ResetViewportAndScissorToDefaultCamera( viewDef ); - - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - - renderProgManager.BindShader_Screen(); - - globalImages->bloomRenderImage[( j + 1 ) % 2]->Bind(); - - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - globalImages->BindNull(); - - Framebuffer::Unbind(); - renderProgManager.Unbind(); - - GL_State( GLS_DEFAULT ); - GL_Cull( CT_FRONT_SIDED ); -} - - -static void RB_SSAO( const viewDef_t* viewDef ) -{ - if( !viewDef->viewEntitys || viewDef->is2Dgui ) - { - // 3D views only - return; - } - - if( r_useSSAO.GetInteger() <= 0 ) - { - return; - } - - // FIXME very expensive to enable this in subviews - if( viewDef->isSubview ) - { - return; - } - - RENDERLOG_PRINTF( "---------- RB_SSAO() ----------\n" ); - -#if 0 - GL_CheckErrors(); - - // clear the alpha buffer and draw only the hands + weapon into it so - // we can avoid blurring them - glClearColor( 0, 0, 0, 1 ); - GL_State( GLS_COLORMASK | GLS_DEPTHMASK ); - glClear( GL_COLOR_BUFFER_BIT ); - GL_Color( 0, 0, 0, 0 ); - - - GL_SelectTexture( 0 ); - globalImages->blackImage->Bind(); - backEnd.currentSpace = NULL; - - drawSurf_t** drawSurfs = ( drawSurf_t** )&backEnd.viewDef->drawSurfs[0]; - for( int surfNum = 0; surfNum < backEnd.viewDef->numDrawSurfs; surfNum++ ) - { - const drawSurf_t* surf = drawSurfs[ surfNum ]; - - if( !surf->space->weaponDepthHack && !surf->space->skipMotionBlur && !surf->material->HasSubview() ) - { - // Apply motion blur to this object - continue; - } - - const idMaterial* shader = surf->material; - if( shader->Coverage() == MC_TRANSLUCENT ) - { - // muzzle flash, etc - continue; - } - - // set mvp matrix - if( surf->space != backEnd.currentSpace ) - { - RB_SetMVP( surf->space->mvp ); - backEnd.currentSpace = surf->space; - } - - // this could just be a color, but we don't have a skinned color-only prog - if( surf->jointCache ) - { - renderProgManager.BindShader_TextureVertexColorSkinned(); - } - else - { - renderProgManager.BindShader_TextureVertexColor(); - } - - // draw it solid - RB_DrawElementsWithCounters( surf ); - } - GL_State( GLS_DEPTHFUNC_ALWAYS ); - - // copy off the color buffer and the depth buffer for the motion blur prog - // we use the viewport dimensions for copying the buffers in case resolution scaling is enabled. - const idScreenRect& viewport = backEnd.viewDef->viewport; - globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); - - // in stereo rendering, each eye needs to get a separate previous frame mvp - int mvpIndex = ( backEnd.viewDef->renderView.viewEyeBuffer == 1 ) ? 1 : 0; - - // derive the matrix to go from current pixels to previous frame pixels - idRenderMatrix inverseMVP; - idRenderMatrix::Inverse( backEnd.viewDef->worldSpace.mvp, inverseMVP ); - - idRenderMatrix motionMatrix; - idRenderMatrix::Multiply( backEnd.prevMVP[mvpIndex], inverseMVP, motionMatrix ); - - backEnd.prevMVP[mvpIndex] = backEnd.viewDef->worldSpace.mvp; - - RB_SetMVP( motionMatrix ); -#endif - - backEnd.currentSpace = &backEnd.viewDef->worldSpace; - RB_SetMVP( backEnd.viewDef->worldSpace.mvp ); - - const bool hdrIsActive = ( r_useHDR.GetBool() && globalFramebuffers.hdrFBO != NULL && globalFramebuffers.hdrFBO->IsBound() ); - - int screenWidth = renderSystem->GetWidth(); - int screenHeight = renderSystem->GetHeight(); - - // build hierarchical depth buffer - if( r_useHierarchicalDepthBuffer.GetBool() ) - { - renderProgManager.BindShader_AmbientOcclusionMinify(); - - glClearColor( 0, 0, 0, 1 ); - - GL_SelectTexture( 0 ); - //globalImages->currentDepthImage->Bind(); - - for( int i = 0; i < MAX_HIERARCHICAL_ZBUFFERS; i++ ) - { - int width = globalFramebuffers.csDepthFBO[i]->GetWidth(); - int height = globalFramebuffers.csDepthFBO[i]->GetHeight(); - - GL_Viewport( 0, 0, width, height ); - GL_Scissor( 0, 0, width, height ); - - globalFramebuffers.csDepthFBO[i]->Bind(); - - glClear( GL_COLOR_BUFFER_BIT ); - - if( i == 0 ) - { - renderProgManager.BindShader_AmbientOcclusionReconstructCSZ(); - - globalImages->currentDepthImage->Bind(); - } - else - { - renderProgManager.BindShader_AmbientOcclusionMinify(); - - GL_SelectTexture( 0 ); - globalImages->hierarchicalZbufferImage->Bind(); - } - - float jitterTexScale[4]; - jitterTexScale[0] = i - 1; - jitterTexScale[1] = 0; - jitterTexScale[2] = 0; - jitterTexScale[3] = 0; - SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale -#if 1 - float screenCorrectionParm[4]; - screenCorrectionParm[0] = 1.0f / width; - screenCorrectionParm[1] = 1.0f / height; - screenCorrectionParm[2] = width; - screenCorrectionParm[3] = height; - SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor -#endif - - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - } - } - - // set the window clipping - GL_Viewport( 0, 0, screenWidth, screenHeight ); - GL_Scissor( 0, 0, screenWidth, screenHeight ); - - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - GL_Cull( CT_TWO_SIDED ); - - if( r_ssaoFiltering.GetBool() ) - { - globalFramebuffers.ambientOcclusionFBO[0]->Bind(); - - glClearColor( 0, 0, 0, 0 ); - glClear( GL_COLOR_BUFFER_BIT ); - - renderProgManager.BindShader_AmbientOcclusion(); - } - else - { - if( r_ssaoDebug.GetInteger() <= 0 ) - { - GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_ALPHAMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - } - - if( hdrIsActive ) - { - globalFramebuffers.hdrFBO->Bind(); - } - else - { - Framebuffer::Unbind(); - } - - renderProgManager.BindShader_AmbientOcclusionAndOutput(); - } - - float screenCorrectionParm[4]; - screenCorrectionParm[0] = 1.0f / screenWidth; - screenCorrectionParm[1] = 1.0f / screenHeight; - screenCorrectionParm[2] = screenWidth; - screenCorrectionParm[3] = screenHeight; - SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor - -#if 0 - // RB: set unprojection matrices so we can convert zbuffer values back to camera and world spaces - idRenderMatrix modelViewMatrix; - idRenderMatrix::Transpose( *( idRenderMatrix* )backEnd.viewDef->worldSpace.modelViewMatrix, modelViewMatrix ); - idRenderMatrix cameraToWorldMatrix; - if( !idRenderMatrix::Inverse( modelViewMatrix, cameraToWorldMatrix ) ) - { - idLib::Warning( "cameraToWorldMatrix invert failed" ); - } - - SetVertexParms( RENDERPARM_MODELMATRIX_X, cameraToWorldMatrix[0], 4 ); - //SetVertexParms( RENDERPARM_MODELMATRIX_X, viewDef->unprojectionToWorldRenderMatrix[0], 4 ); -#endif - SetVertexParms( RENDERPARM_MODELMATRIX_X, viewDef->unprojectionToCameraRenderMatrix[0], 4 ); - - - float jitterTexOffset[4]; - if( r_shadowMapRandomizeJitter.GetBool() ) - { - jitterTexOffset[0] = ( rand() & 255 ) / 255.0; - jitterTexOffset[1] = ( rand() & 255 ) / 255.0; - } - else - { - jitterTexOffset[0] = 0; - jitterTexOffset[1] = 0; - } - jitterTexOffset[2] = viewDef->renderView.time[0] * 0.001f; - jitterTexOffset[3] = 0.0f; - SetFragmentParm( RENDERPARM_JITTERTEXOFFSET, jitterTexOffset ); // rpJitterTexOffset - - GL_SelectTexture( 0 ); - globalImages->currentNormalsImage->Bind(); - - GL_SelectTexture( 1 ); - if( r_useHierarchicalDepthBuffer.GetBool() ) - { - globalImages->hierarchicalZbufferImage->Bind(); - } - else - { - globalImages->currentDepthImage->Bind(); - } - - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - if( r_ssaoFiltering.GetBool() ) - { - float jitterTexScale[4]; - - // AO blur X -#if 1 - globalFramebuffers.ambientOcclusionFBO[1]->Bind(); - - renderProgManager.BindShader_AmbientOcclusionBlur(); - - // set axis parameter - jitterTexScale[0] = 1; - jitterTexScale[1] = 0; - jitterTexScale[2] = 0; - jitterTexScale[3] = 0; - SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale - - GL_SelectTexture( 2 ); - globalImages->ambientOcclusionImage[0]->Bind(); - - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); -#endif - - // AO blur Y - if( hdrIsActive ) - { - globalFramebuffers.hdrFBO->Bind(); - } - else - { - Framebuffer::Unbind(); - } - - if( r_ssaoDebug.GetInteger() <= 0 ) - { - GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - } - - renderProgManager.BindShader_AmbientOcclusionBlurAndOutput(); - - // set axis parameter - jitterTexScale[0] = 0; - jitterTexScale[1] = 1; - jitterTexScale[2] = 0; - jitterTexScale[3] = 0; - SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale - - GL_SelectTexture( 2 ); - globalImages->ambientOcclusionImage[1]->Bind(); - - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - } - - renderProgManager.Unbind(); - - GL_State( GLS_DEFAULT ); - GL_Cull( CT_FRONT_SIDED ); - - //GL_CheckErrors(); -} - -static void RB_SSGI( const viewDef_t* viewDef ) -{ - if( !viewDef->viewEntitys || viewDef->is2Dgui ) - { - // 3D views only - return; - } - - if( r_useSSGI.GetInteger() <= 0 ) - { - return; - } - - // FIXME very expensive to enable this in subviews - if( viewDef->isSubview ) - { - return; - } - - RENDERLOG_PRINTF( "---------- RB_SSGI() ----------\n" ); - - backEnd.currentSpace = &backEnd.viewDef->worldSpace; - RB_SetMVP( backEnd.viewDef->worldSpace.mvp ); - - const bool hdrIsActive = ( r_useHDR.GetBool() && globalFramebuffers.hdrFBO != NULL && globalFramebuffers.hdrFBO->IsBound() ); - - int screenWidth = renderSystem->GetWidth(); - int screenHeight = renderSystem->GetHeight(); - - // set the window clipping - GL_Viewport( 0, 0, screenWidth, screenHeight ); - GL_Scissor( 0, 0, screenWidth, screenHeight ); - - if( !hdrIsActive ) - { - const idScreenRect& viewport = viewDef->viewport; - globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); - } - - // build hierarchical depth buffer - if( r_useHierarchicalDepthBuffer.GetBool() ) - { - renderProgManager.BindShader_AmbientOcclusionMinify(); - - glClearColor( 0, 0, 0, 1 ); - - GL_SelectTexture( 0 ); - //globalImages->currentDepthImage->Bind(); - - for( int i = 0; i < MAX_HIERARCHICAL_ZBUFFERS; i++ ) - { - int width = globalFramebuffers.csDepthFBO[i]->GetWidth(); - int height = globalFramebuffers.csDepthFBO[i]->GetHeight(); - - GL_Viewport( 0, 0, width, height ); - GL_Scissor( 0, 0, width, height ); - - globalFramebuffers.csDepthFBO[i]->Bind(); - - glClear( GL_COLOR_BUFFER_BIT ); - - if( i == 0 ) - { - renderProgManager.BindShader_AmbientOcclusionReconstructCSZ(); - - globalImages->currentDepthImage->Bind(); - } - else - { - renderProgManager.BindShader_AmbientOcclusionMinify(); - - GL_SelectTexture( 0 ); - globalImages->hierarchicalZbufferImage->Bind(); - } - - float jitterTexScale[4]; - jitterTexScale[0] = i - 1; - jitterTexScale[1] = 0; - jitterTexScale[2] = 0; - jitterTexScale[3] = 0; - SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale -#if 1 - float screenCorrectionParm[4]; - screenCorrectionParm[0] = 1.0f / width; - screenCorrectionParm[1] = 1.0f / height; - screenCorrectionParm[2] = width; - screenCorrectionParm[3] = height; - SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor -#endif - - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - } - } - - // set the window clipping - GL_Viewport( 0, 0, screenWidth, screenHeight ); - GL_Scissor( 0, 0, screenWidth, screenHeight ); - - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - GL_Cull( CT_TWO_SIDED ); - - if( r_ssgiFiltering.GetBool() ) - { - globalFramebuffers.ambientOcclusionFBO[0]->Bind(); - - // FIXME remove and mix with color from previous frame - glClearColor( 0, 0, 0, 0 ); - glClear( GL_COLOR_BUFFER_BIT ); - - renderProgManager.BindShader_DeepGBufferRadiosity(); - } - else - { - if( r_ssgiDebug.GetInteger() > 0 ) - { - // replace current - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - } - else - { - // add result to main color - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - } - - if( hdrIsActive ) - { - globalFramebuffers.hdrFBO->Bind(); - } - else - { - Framebuffer::Unbind(); - } - - renderProgManager.BindShader_DeepGBufferRadiosity(); - } - - float screenCorrectionParm[4]; - screenCorrectionParm[0] = 1.0f / screenWidth; - screenCorrectionParm[1] = 1.0f / screenHeight; - screenCorrectionParm[2] = screenWidth; - screenCorrectionParm[3] = screenHeight; - SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor - -#if 0 - // RB: set unprojection matrices so we can convert zbuffer values back to camera and world spaces - idRenderMatrix modelViewMatrix; - idRenderMatrix::Transpose( *( idRenderMatrix* )backEnd.viewDef->worldSpace.modelViewMatrix, modelViewMatrix ); - idRenderMatrix cameraToWorldMatrix; - if( !idRenderMatrix::Inverse( modelViewMatrix, cameraToWorldMatrix ) ) - { - idLib::Warning( "cameraToWorldMatrix invert failed" ); - } - - SetVertexParms( RENDERPARM_MODELMATRIX_X, cameraToWorldMatrix[0], 4 ); - //SetVertexParms( RENDERPARM_MODELMATRIX_X, viewDef->unprojectionToWorldRenderMatrix[0], 4 ); -#endif - SetVertexParms( RENDERPARM_MODELMATRIX_X, viewDef->unprojectionToCameraRenderMatrix[0], 4 ); - - - float jitterTexOffset[4]; - if( r_shadowMapRandomizeJitter.GetBool() ) - { - jitterTexOffset[0] = ( rand() & 255 ) / 255.0; - jitterTexOffset[1] = ( rand() & 255 ) / 255.0; - } - else - { - jitterTexOffset[0] = 0; - jitterTexOffset[1] = 0; - } - jitterTexOffset[2] = viewDef->renderView.time[0] * 0.001f; - jitterTexOffset[3] = 0.0f; - SetFragmentParm( RENDERPARM_JITTERTEXOFFSET, jitterTexOffset ); // rpJitterTexOffset - - GL_SelectTexture( 0 ); - globalImages->currentNormalsImage->Bind(); - - GL_SelectTexture( 1 ); - if( r_useHierarchicalDepthBuffer.GetBool() ) - { - globalImages->hierarchicalZbufferImage->Bind(); - } - else - { - globalImages->currentDepthImage->Bind(); - } - - GL_SelectTexture( 2 ); - if( hdrIsActive ) - { - globalImages->currentRenderHDRImage->Bind(); - } - else - { - globalImages->currentRenderImage->Bind(); - } - - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - if( r_ssgiFiltering.GetBool() ) - { - float jitterTexScale[4]; - - // AO blur X -#if 1 - globalFramebuffers.ambientOcclusionFBO[1]->Bind(); - - renderProgManager.BindShader_DeepGBufferRadiosityBlur(); - - // set axis parameter - jitterTexScale[0] = 1; - jitterTexScale[1] = 0; - jitterTexScale[2] = 0; - jitterTexScale[3] = 0; - SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale - - GL_SelectTexture( 2 ); - globalImages->ambientOcclusionImage[0]->Bind(); - - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); -#endif - - // AO blur Y - if( hdrIsActive ) - { - globalFramebuffers.hdrFBO->Bind(); - } - else - { - Framebuffer::Unbind(); - } - - if( r_ssgiDebug.GetInteger() > 0 ) - { - // replace current - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - } - else - { - // add result to main color - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - } - - renderProgManager.BindShader_DeepGBufferRadiosityBlurAndOutput(); - - // set axis parameter - jitterTexScale[0] = 0; - jitterTexScale[1] = 1; - jitterTexScale[2] = 0; - jitterTexScale[3] = 0; - SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale - - GL_SelectTexture( 2 ); - globalImages->ambientOcclusionImage[1]->Bind(); - - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - } - - renderProgManager.Unbind(); - - GL_State( GLS_DEFAULT ); - GL_Cull( CT_FRONT_SIDED ); - - //GL_CheckErrors(); -} -// RB end - -/* -========================================================================================================= - -BACKEND COMMANDS - -========================================================================================================= -*/ - -/* -================== -RB_DrawViewInternal -================== -*/ -void RB_DrawViewInternal( const viewDef_t* viewDef, const int stereoEye ) -{ - renderLog.OpenBlock( "RB_DrawViewInternal" ); - - //------------------------------------------------- - // guis can wind up referencing purged images that need to be loaded. - // this used to be in the gui emit code, but now that it can be running - // in a separate thread, it must not try to load images, so do it here. - //------------------------------------------------- - drawSurf_t** drawSurfs = ( drawSurf_t** )&viewDef->drawSurfs[0]; - const int numDrawSurfs = viewDef->numDrawSurfs; - - for( int i = 0; i < numDrawSurfs; i++ ) - { - const drawSurf_t* ds = viewDef->drawSurfs[ i ]; - if( ds->material != NULL ) - { - const_cast( ds->material )->EnsureNotPurged(); - } - } - - //------------------------------------------------- - // RB_BeginDrawingView - // - // Any mirrored or portaled views have already been drawn, so prepare - // to actually render the visible surfaces for this view - // - // clear the z buffer, set the projection matrix, etc - //------------------------------------------------- - RB_ResetViewportAndScissorToDefaultCamera( viewDef ); - - backEnd.glState.faceCulling = -1; // force face culling to set next time - - // ensures that depth writes are enabled for the depth clear - GL_State( GLS_DEFAULT ); - - //GL_CheckErrors(); - - // RB begin - bool useHDR = r_useHDR.GetBool() && !viewDef->is2Dgui; - - // Clear the depth buffer and clear the stencil to 128 for stencil shadows as well as gui masking - GL_Clear( false, true, true, STENCIL_SHADOW_TEST_VALUE, 0.0f, 0.0f, 0.0f, 0.0f, useHDR ); - - if( useHDR ) - { - globalFramebuffers.hdrFBO->Bind(); - } - else - { - Framebuffer::Unbind(); - } - // RB end - - //GL_CheckErrors(); - - // normal face culling - GL_Cull( CT_FRONT_SIDED ); - -#if defined(USE_CORE_PROFILE) && !defined(USE_GLES2) && !defined(USE_GLES3) - // bind one global Vertex Array Object (VAO) - glBindVertexArray( glConfig.global_vao ); -#endif - - //------------------------------------ - // sets variables that can be used by all programs - //------------------------------------ - { - // - // set eye position in global space - // - float parm[4]; - parm[0] = backEnd.viewDef->renderView.vieworg[0]; - parm[1] = backEnd.viewDef->renderView.vieworg[1]; - parm[2] = backEnd.viewDef->renderView.vieworg[2]; - parm[3] = 1.0f; - - SetVertexParm( RENDERPARM_GLOBALEYEPOS, parm ); // rpGlobalEyePos - - // sets overbright to make world brighter - // This value is baked into the specularScale and diffuseScale values so - // the interaction programs don't need to perform the extra multiply, - // but any other renderprogs that want to obey the brightness value - // can reference this. - float overbright = r_lightScale.GetFloat() * 0.5f; - parm[0] = overbright; - parm[1] = overbright; - parm[2] = overbright; - parm[3] = overbright; - SetFragmentParm( RENDERPARM_OVERBRIGHT, parm ); - - // Set Projection Matrix - float projMatrixTranspose[16]; - R_MatrixTranspose( backEnd.viewDef->projectionMatrix, projMatrixTranspose ); - SetVertexParms( RENDERPARM_PROJMATRIX_X, projMatrixTranspose, 4 ); - } - - //------------------------------------------------- - // fill the depth buffer and clear color buffer to black except on subviews - //------------------------------------------------- - RB_FillDepthBufferFast( drawSurfs, numDrawSurfs ); - - //------------------------------------------------- - // FIXME, OPTIMIZE: merge this with FillDepthBufferFast like in a light prepass deferred renderer - // - // fill the geometric buffer with normals and roughness - //------------------------------------------------- - RB_AmbientPass( drawSurfs, numDrawSurfs, true ); - - //------------------------------------------------- - // fill the depth buffer and the color buffer with precomputed Q3A style lighting - //------------------------------------------------- - RB_AmbientPass( drawSurfs, numDrawSurfs, false ); - - //------------------------------------------------- - // main light renderer - //------------------------------------------------- - RB_DrawInteractions( viewDef ); - - //------------------------------------------------- - // capture the depth for the motion blur before rendering any post process surfaces that may contribute to the depth - //------------------------------------------------- - if( ( r_motionBlur.GetInteger() > 0 || r_useSSAO.GetBool() || r_useSSGI.GetBool() ) && !r_useHDR.GetBool() ) - { - const idScreenRect& viewport = backEnd.viewDef->viewport; - globalImages->currentDepthImage->CopyDepthbuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); - } - - //------------------------------------------------- - // darken the scene using the screen space ambient occlusion - //------------------------------------------------- - RB_SSAO( viewDef ); - //RB_SSGI( viewDef ); - - //------------------------------------------------- - // now draw any non-light dependent shading passes - //------------------------------------------------- - int processed = 0; - if( !r_skipShaderPasses.GetBool() ) - { - renderLog.OpenMainBlock( MRB_DRAW_SHADER_PASSES ); - float guiScreenOffset; - if( viewDef->viewEntitys != NULL ) - { - // guiScreenOffset will be 0 in non-gui views - guiScreenOffset = 0.0f; - } - else - { - guiScreenOffset = stereoEye * viewDef->renderView.stereoScreenSeparation; - } - processed = RB_DrawShaderPasses( drawSurfs, numDrawSurfs, guiScreenOffset, stereoEye ); - renderLog.CloseMainBlock(); - } - - //------------------------------------------------- - // use direct light and emissive light contributions to add indirect screen space light - //------------------------------------------------- - //RB_SSGI( viewDef ); - - //------------------------------------------------- - // fog and blend lights, drawn after emissive surfaces - // so they are properly dimmed down - //------------------------------------------------- - RB_FogAllLights(); - - //------------------------------------------------- - // now draw any screen warping post-process effects using _currentRender - //------------------------------------------------- - if( processed < numDrawSurfs && !r_skipPostProcess.GetBool() ) - { - int x = backEnd.viewDef->viewport.x1; - int y = backEnd.viewDef->viewport.y1; - int w = backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1; - int h = backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1; - - RENDERLOG_PRINTF( "Resolve to %i x %i buffer\n", w, h ); - - GL_SelectTexture( 0 ); - - // resolve the screen - globalImages->currentRenderImage->CopyFramebuffer( x, y, w, h ); - backEnd.currentRenderCopied = true; - - // RENDERPARM_SCREENCORRECTIONFACTOR amd RENDERPARM_WINDOWCOORD overlap - // diffuseScale and specularScale - - // screen power of two correction factor (no longer relevant now) - float screenCorrectionParm[4]; - screenCorrectionParm[0] = 1.0f; - screenCorrectionParm[1] = 1.0f; - screenCorrectionParm[2] = 0.0f; - screenCorrectionParm[3] = 1.0f; - SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor - - // window coord to 0.0 to 1.0 conversion - float windowCoordParm[4]; - windowCoordParm[0] = 1.0f / w; - windowCoordParm[1] = 1.0f / h; - windowCoordParm[2] = 0.0f; - windowCoordParm[3] = 1.0f; - SetFragmentParm( RENDERPARM_WINDOWCOORD, windowCoordParm ); // rpWindowCoord - - // render the remaining surfaces - renderLog.OpenMainBlock( MRB_DRAW_SHADER_PASSES_POST ); - RB_DrawShaderPasses( drawSurfs + processed, numDrawSurfs - processed, 0.0f /* definitely not a gui */, stereoEye ); - renderLog.CloseMainBlock(); - } - - //------------------------------------------------- - // render debug tools - //------------------------------------------------- - RB_RenderDebugTools( drawSurfs, numDrawSurfs ); - - // RB: convert back from HDR to LDR range - if( useHDR ) - { - /* - int x = backEnd.viewDef->viewport.x1; - int y = backEnd.viewDef->viewport.y1; - int w = backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1; - int h = backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1; - - GL_Viewport( viewDef->viewport.x1, - viewDef->viewport.y1, - viewDef->viewport.x2 + 1 - viewDef->viewport.x1, - viewDef->viewport.y2 + 1 - viewDef->viewport.y1 ); - */ - - /* - glBindFramebuffer( GL_READ_FRAMEBUFFER, globalFramebuffers.hdrFBO->GetFramebuffer() ); - glBindFramebuffer( GL_DRAW_FRAMEBUFFER, globalFramebuffers.hdrQuarterFBO->GetFramebuffer() ); - glBlitFramebuffer( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), - 0, 0, renderSystem->GetWidth() * 0.25f, renderSystem->GetHeight() * 0.25f, - GL_COLOR_BUFFER_BIT, - GL_LINEAR ); - */ - -#if defined(USE_HDR_MSAA) - if( glConfig.multisamples > 0 ) - { - glBindFramebuffer( GL_READ_FRAMEBUFFER, globalFramebuffers.hdrFBO->GetFramebuffer() ); - glBindFramebuffer( GL_DRAW_FRAMEBUFFER, globalFramebuffers.hdrNonMSAAFBO->GetFramebuffer() ); - glBlitFramebuffer( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), - 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), - GL_COLOR_BUFFER_BIT, - GL_LINEAR ); - - // TODO resolve to 1x1 - glBindFramebuffer( GL_READ_FRAMEBUFFER_EXT, globalFramebuffers.hdrNonMSAAFBO->GetFramebuffer() ); - glBindFramebuffer( GL_DRAW_FRAMEBUFFER_EXT, globalFramebuffers.hdr64FBO->GetFramebuffer() ); - glBlitFramebuffer( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), - 0, 0, 64, 64, - GL_COLOR_BUFFER_BIT, - GL_LINEAR ); - } - else -#endif - { - glBindFramebuffer( GL_READ_FRAMEBUFFER_EXT, globalFramebuffers.hdrFBO->GetFramebuffer() ); - glBindFramebuffer( GL_DRAW_FRAMEBUFFER_EXT, globalFramebuffers.hdr64FBO->GetFramebuffer() ); - glBlitFramebuffer( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), - 0, 0, 64, 64, - GL_COLOR_BUFFER_BIT, - GL_LINEAR ); - } - - RB_CalculateAdaptation(); - - RB_Tonemap( viewDef ); - } - - RB_Bloom( viewDef ); - // RB end - - renderLog.CloseBlock(); -} - -/* -================== -RB_MotionBlur - -Experimental feature -================== -*/ -void RB_MotionBlur() -{ - if( !backEnd.viewDef->viewEntitys ) - { - // 3D views only - return; - } - if( r_motionBlur.GetInteger() <= 0 ) - { - return; - } - if( backEnd.viewDef->isSubview ) - { - return; - } - - GL_CheckErrors(); - - // clear the alpha buffer and draw only the hands + weapon into it so - // we can avoid blurring them - glClearColor( 0, 0, 0, 1 ); - GL_State( GLS_COLORMASK | GLS_DEPTHMASK ); - glClear( GL_COLOR_BUFFER_BIT ); - GL_Color( 0, 0, 0, 0 ); - GL_SelectTexture( 0 ); - globalImages->blackImage->Bind(); - backEnd.currentSpace = NULL; - - drawSurf_t** drawSurfs = ( drawSurf_t** )&backEnd.viewDef->drawSurfs[0]; - for( int surfNum = 0; surfNum < backEnd.viewDef->numDrawSurfs; surfNum++ ) - { - const drawSurf_t* surf = drawSurfs[ surfNum ]; - - if( !surf->space->weaponDepthHack && !surf->space->skipMotionBlur && !surf->material->HasSubview() ) - { - // Apply motion blur to this object - continue; - } - - const idMaterial* shader = surf->material; - if( shader->Coverage() == MC_TRANSLUCENT ) - { - // muzzle flash, etc - continue; - } - - // set mvp matrix - if( surf->space != backEnd.currentSpace ) - { - RB_SetMVP( surf->space->mvp ); - backEnd.currentSpace = surf->space; - } - - // this could just be a color, but we don't have a skinned color-only prog - if( surf->jointCache ) - { - renderProgManager.BindShader_TextureVertexColorSkinned(); - } - else - { - renderProgManager.BindShader_TextureVertexColor(); - } - - // draw it solid - RB_DrawElementsWithCounters( surf ); - } - GL_State( GLS_DEPTHFUNC_ALWAYS ); - - // copy off the color buffer and the depth buffer for the motion blur prog - // we use the viewport dimensions for copying the buffers in case resolution scaling is enabled. - const idScreenRect& viewport = backEnd.viewDef->viewport; - globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); - - // in stereo rendering, each eye needs to get a separate previous frame mvp - int mvpIndex = ( backEnd.viewDef->renderView.viewEyeBuffer == 1 ) ? 1 : 0; - - // derive the matrix to go from current pixels to previous frame pixels - idRenderMatrix inverseMVP; - idRenderMatrix::Inverse( backEnd.viewDef->worldSpace.mvp, inverseMVP ); - - idRenderMatrix motionMatrix; - idRenderMatrix::Multiply( backEnd.prevMVP[mvpIndex], inverseMVP, motionMatrix ); - - backEnd.prevMVP[mvpIndex] = backEnd.viewDef->worldSpace.mvp; - - RB_SetMVP( motionMatrix ); - - GL_State( GLS_DEPTHFUNC_ALWAYS ); - GL_Cull( CT_TWO_SIDED ); - - renderProgManager.BindShader_MotionBlur(); - - // let the fragment program know how many samples we are going to use - idVec4 samples( ( float )( 1 << r_motionBlur.GetInteger() ) ); - SetFragmentParm( RENDERPARM_OVERBRIGHT, samples.ToFloatPtr() ); - - GL_SelectTexture( 0 ); - globalImages->currentRenderImage->Bind(); - GL_SelectTexture( 1 ); - globalImages->currentDepthImage->Bind(); - - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - GL_CheckErrors(); -} - -/* -================== -RB_DrawView - -StereoEye will always be 0 in mono modes, or -1 / 1 in stereo modes. -If the view is a GUI view that is repeated for both eyes, the viewDef.stereoEye value -is 0, so the stereoEye parameter is not always the same as that. -================== -*/ -void RB_DrawView( const void* data, const int stereoEye ) -{ - const drawSurfsCommand_t* cmd = ( const drawSurfsCommand_t* )data; - - backEnd.viewDef = cmd->viewDef; - - // we will need to do a new copyTexSubImage of the screen - // when a SS_POST_PROCESS material is used - backEnd.currentRenderCopied = false; - - // if there aren't any drawsurfs, do nothing - if( !backEnd.viewDef->numDrawSurfs ) - { - return; - } - - // skip render bypasses everything that has models, assuming - // them to be 3D views, but leaves 2D rendering visible - if( r_skipRender.GetBool() && backEnd.viewDef->viewEntitys ) - { - return; - } - - // skip render context sets the wgl context to NULL, - // which should factor out the API cost, under the assumption - // that all gl calls just return if the context isn't valid - - // RB: not really needed - //if( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) - //{ - // GLimp_DeactivateContext(); - //} - // RB end - - backEnd.pc.c_surfaces += backEnd.viewDef->numDrawSurfs; - - RB_ShowOverdraw(); - - // render the scene - RB_DrawViewInternal( cmd->viewDef, stereoEye ); - - RB_MotionBlur(); - - // restore the context for 2D drawing if we were stubbing it out - // RB: not really needed - //if( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) - //{ - // GLimp_ActivateContext(); - // GL_SetDefaultState(); - //} - // RB end - - // optionally draw a box colored based on the eye number - if( r_drawEyeColor.GetBool() ) - { - const idScreenRect& r = backEnd.viewDef->viewport; - GL_Scissor( ( r.x1 + r.x2 ) / 2, ( r.y1 + r.y2 ) / 2, 32, 32 ); - switch( stereoEye ) - { - case -1: - GL_Clear( true, false, false, 0, 1.0f, 0.0f, 0.0f, 1.0f ); - break; - case 1: - GL_Clear( true, false, false, 0, 0.0f, 1.0f, 0.0f, 1.0f ); - break; - default: - GL_Clear( true, false, false, 0, 0.5f, 0.5f, 0.5f, 1.0f ); - break; - } - } -} - -/* -================== -RB_CopyRender - -Copy part of the current framebuffer to an image -================== -*/ -void RB_CopyRender( const void* data ) -{ - const copyRenderCommand_t* cmd = ( const copyRenderCommand_t* )data; - - if( r_skipCopyTexture.GetBool() ) - { - return; - } - - RENDERLOG_PRINTF( "***************** RB_CopyRender *****************\n" ); - - if( cmd->image ) - { - cmd->image->CopyFramebuffer( cmd->x, cmd->y, cmd->imageWidth, cmd->imageHeight ); - } - - if( cmd->clearColorAfterCopy ) - { - GL_Clear( true, false, false, STENCIL_SHADOW_TEST_VALUE, 0, 0, 0, 0 ); - } -} - -/* -================== -RB_PostProcess - -================== -*/ -extern idCVar rs_enable; -void RB_PostProcess( const void* data ) -{ - - // only do the post process step if resolution scaling is enabled. Prevents the unnecessary copying of the framebuffer and - // corresponding full screen quad pass. - if( rs_enable.GetInteger() == 0 && !r_useFilmicPostProcessEffects.GetBool() && r_antiAliasing.GetInteger() == 0 ) - { - return; - } - - if( ( r_ssaoDebug.GetInteger() > 0 ) || ( r_ssgiDebug.GetInteger() > 0 ) ) - { - return; - } - - RENDERLOG_PRINTF( "---------- RB_PostProcess() ----------\n" ); - - // resolve the scaled rendering to a temporary texture - postProcessCommand_t* cmd = ( postProcessCommand_t* )data; - const idScreenRect& viewport = cmd->viewDef->viewport; - - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - GL_Cull( CT_TWO_SIDED ); - - int screenWidth = renderSystem->GetWidth(); - int screenHeight = renderSystem->GetHeight(); - - // set the window clipping - GL_Viewport( 0, 0, screenWidth, screenHeight ); - GL_Scissor( 0, 0, screenWidth, screenHeight ); - - // SMAA - int aaMode = r_antiAliasing.GetInteger(); - if( aaMode == ANTI_ALIASING_SMAA_1X ) - { - /* - * The shader has three passes, chained together as follows: - * - * |input|------------------· - * v | - * [ SMAA*EdgeDetection ] | - * v | - * |edgesTex| | - * v | - * [ SMAABlendingWeightCalculation ] | - * v | - * |blendTex| | - * v | - * [ SMAANeighborhoodBlending ] <------· - * v - * |output| - */ - - globalImages->smaaInputImage->CopyFramebuffer( 0, 0, screenWidth, screenHeight ); - - // set SMAA_RT_METRICS = rpScreenCorrectionFactor - float screenCorrectionParm[4]; - screenCorrectionParm[0] = 1.0f / screenWidth; - screenCorrectionParm[1] = 1.0f / screenHeight; - screenCorrectionParm[2] = screenWidth; - screenCorrectionParm[3] = screenHeight; - SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor - - globalFramebuffers.smaaEdgesFBO->Bind(); - - glClearColor( 0, 0, 0, 0 ); - glClear( GL_COLOR_BUFFER_BIT ); - - GL_SelectTexture( 0 ); - globalImages->smaaInputImage->Bind(); - - renderProgManager.BindShader_SMAA_EdgeDetection(); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - -#if 1 - //globalImages->smaaEdgesImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); - - globalFramebuffers.smaaBlendFBO->Bind(); - //Framebuffer::Unbind(); - - glClear( GL_COLOR_BUFFER_BIT ); - - GL_SelectTexture( 0 ); - globalImages->smaaEdgesImage->Bind(); - - GL_SelectTexture( 1 ); - globalImages->smaaAreaImage->Bind(); - - GL_SelectTexture( 2 ); - globalImages->smaaSearchImage->Bind(); - - renderProgManager.BindShader_SMAA_BlendingWeightCalculation(); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - - Framebuffer::Unbind(); -#endif - -#if 1 - globalImages->BindNull(); - - //GL_SelectTexture( 0 ); - //globalImages->smaaBlendImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); - - GL_SelectTexture( 0 ); - globalImages->smaaInputImage->Bind(); - - GL_SelectTexture( 1 ); - globalImages->smaaBlendImage->Bind(); - - renderProgManager.BindShader_SMAA_NeighborhoodBlending(); - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); -#endif - } - -#if 1 - if( r_useFilmicPostProcessEffects.GetBool() ) - { - globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() ); - - GL_SelectTexture( 0 ); - globalImages->currentRenderImage->Bind(); - - GL_SelectTexture( 1 ); - globalImages->grainImage1->Bind(); - - renderProgManager.BindShader_PostProcess(); - - const static int GRAIN_SIZE = 128; - - // screen power of two correction factor - float screenCorrectionParm[4]; - screenCorrectionParm[0] = 1.0f / GRAIN_SIZE; - screenCorrectionParm[1] = 1.0f / GRAIN_SIZE; - screenCorrectionParm[2] = 1.0f; - screenCorrectionParm[3] = 1.0f; - SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor - - float jitterTexOffset[4]; - if( r_shadowMapRandomizeJitter.GetBool() ) - { - jitterTexOffset[0] = ( rand() & 255 ) / 255.0; - jitterTexOffset[1] = ( rand() & 255 ) / 255.0; - } - else - { - jitterTexOffset[0] = 0; - jitterTexOffset[1] = 0; - } - jitterTexOffset[2] = 0.0f; - jitterTexOffset[3] = 0.0f; - SetFragmentParm( RENDERPARM_JITTERTEXOFFSET, jitterTexOffset ); // rpJitterTexOffset - - // Draw - RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); - } -#endif - - GL_SelectTexture( 2 ); - globalImages->BindNull(); - - GL_SelectTexture( 1 ); - globalImages->BindNull(); - - GL_SelectTexture( 0 ); - globalImages->BindNull(); - - renderProgManager.Unbind(); - - renderLog.CloseBlock(); -} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_backend_rendertools.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_backend_rendertools.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_backend_rendertools.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_backend_rendertools.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,3289 +0,0 @@ -/* -=========================================================================== - -Doom 3 BFG Edition GPL Source Code -Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. -Copyright (C) 2014-2016 Robert Beckebans -Copyright (C) 2014-2016 Kot in Action Creative Artel - -This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). - -Doom 3 BFG Edition Source Code 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. - -Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . - -In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#pragma hdrstop -#include "precompiled.h" - -#include "tr_local.h" -#include "simplex.h" // line font definition - -idCVar r_showCenterOfProjection( "r_showCenterOfProjection", "0", CVAR_RENDERER | CVAR_BOOL, "Draw a cross to show the center of projection" ); -idCVar r_showLines( "r_showLines", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = draw alternate horizontal lines, 2 = draw alternate vertical lines" ); - - - -#define MAX_DEBUG_LINES 16384 - -typedef struct debugLine_s -{ - idVec4 rgb; - idVec3 start; - idVec3 end; - bool depthTest; - int lifeTime; -} debugLine_t; - -debugLine_t rb_debugLines[ MAX_DEBUG_LINES ]; -int rb_numDebugLines = 0; -int rb_debugLineTime = 0; - -#define MAX_DEBUG_TEXT 512 - -typedef struct debugText_s -{ - idStr text; - idVec3 origin; - float scale; - idVec4 color; - idMat3 viewAxis; - int align; - int lifeTime; - bool depthTest; -} debugText_t; - -debugText_t rb_debugText[ MAX_DEBUG_TEXT ]; -int rb_numDebugText = 0; -int rb_debugTextTime = 0; - -#define MAX_DEBUG_POLYGONS 8192 - -typedef struct debugPolygon_s -{ - idVec4 rgb; - idWinding winding; - bool depthTest; - int lifeTime; -} debugPolygon_t; - -debugPolygon_t rb_debugPolygons[ MAX_DEBUG_POLYGONS ]; -int rb_numDebugPolygons = 0; -int rb_debugPolygonTime = 0; - -static void RB_DrawText( const char* text, const idVec3& origin, float scale, const idVec4& color, const idMat3& viewAxis, const int align ); - -void RB_SetMVP( const idRenderMatrix& mvp ); - -/* -================ -RB_DrawBounds -================ -*/ -void RB_DrawBounds( const idBounds& bounds ) -{ - if( bounds.IsCleared() ) - { - return; - } - glBegin( GL_LINE_LOOP ); - glVertex3f( bounds[0][0], bounds[0][1], bounds[0][2] ); - glVertex3f( bounds[0][0], bounds[1][1], bounds[0][2] ); - glVertex3f( bounds[1][0], bounds[1][1], bounds[0][2] ); - glVertex3f( bounds[1][0], bounds[0][1], bounds[0][2] ); - glEnd(); - glBegin( GL_LINE_LOOP ); - glVertex3f( bounds[0][0], bounds[0][1], bounds[1][2] ); - glVertex3f( bounds[0][0], bounds[1][1], bounds[1][2] ); - glVertex3f( bounds[1][0], bounds[1][1], bounds[1][2] ); - glVertex3f( bounds[1][0], bounds[0][1], bounds[1][2] ); - glEnd(); - - glBegin( GL_LINES ); - glVertex3f( bounds[0][0], bounds[0][1], bounds[0][2] ); - glVertex3f( bounds[0][0], bounds[0][1], bounds[1][2] ); - - glVertex3f( bounds[0][0], bounds[1][1], bounds[0][2] ); - glVertex3f( bounds[0][0], bounds[1][1], bounds[1][2] ); - - glVertex3f( bounds[1][0], bounds[0][1], bounds[0][2] ); - glVertex3f( bounds[1][0], bounds[0][1], bounds[1][2] ); - - glVertex3f( bounds[1][0], bounds[1][1], bounds[0][2] ); - glVertex3f( bounds[1][0], bounds[1][1], bounds[1][2] ); - glEnd(); -} - - -/* -================ -RB_SimpleSurfaceSetup -================ -*/ -static void RB_SimpleSurfaceSetup( const drawSurf_t* drawSurf ) -{ - // change the matrix if needed - if( drawSurf->space != backEnd.currentSpace ) - { - // RB begin - RB_SetMVP( drawSurf->space->mvp ); - //qglLoadMatrixf( drawSurf->space->modelViewMatrix ); - // RB end - backEnd.currentSpace = drawSurf->space; - } - - // change the scissor if needed - if( !backEnd.currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) - { - GL_Scissor( backEnd.viewDef->viewport.x1 + drawSurf->scissorRect.x1, - backEnd.viewDef->viewport.y1 + drawSurf->scissorRect.y1, - drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1, - drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 ); - backEnd.currentScissor = drawSurf->scissorRect; - } -} - -/* -================ -RB_SimpleWorldSetup -================ -*/ -static void RB_SimpleWorldSetup() -{ - backEnd.currentSpace = &backEnd.viewDef->worldSpace; - - // RB begin - //qglLoadMatrixf( backEnd.viewDef->worldSpace.modelViewMatrix ); - RB_SetMVP( backEnd.viewDef->worldSpace.mvp ); - // RB end - - GL_Scissor( backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1, - backEnd.viewDef->scissor.x2 + 1 - backEnd.viewDef->scissor.x1, - backEnd.viewDef->scissor.y2 + 1 - backEnd.viewDef->scissor.y1 ); - backEnd.currentScissor = backEnd.viewDef->scissor; -} - -/* -================= -RB_PolygonClear - -This will cover the entire screen with normal rasterization. -Texturing is disabled, but the existing glColor, glDepthMask, -glColorMask, and the enabled state of depth buffering and -stenciling will matter. -================= -*/ -void RB_PolygonClear() -{ - glPushMatrix(); - glPushAttrib( GL_ALL_ATTRIB_BITS ); - glLoadIdentity(); - glDisable( GL_TEXTURE_2D ); - glDisable( GL_DEPTH_TEST ); - glDisable( GL_CULL_FACE ); - glDisable( GL_SCISSOR_TEST ); - glBegin( GL_POLYGON ); - glVertex3f( -20, -20, -10 ); - glVertex3f( 20, -20, -10 ); - glVertex3f( 20, 20, -10 ); - glVertex3f( -20, 20, -10 ); - glEnd(); - glPopAttrib(); - glPopMatrix(); -} - -/* -==================== -RB_ShowDestinationAlpha -==================== -*/ -void RB_ShowDestinationAlpha() -{ - GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ); - GL_Color( 1, 1, 1 ); - RB_PolygonClear(); -} - -/* -=================== -RB_ScanStencilBuffer - -Debugging tool to see what values are in the stencil buffer -=================== -*/ -void RB_ScanStencilBuffer() -{ - int counts[256]; - int i; - byte* stencilReadback; - - memset( counts, 0, sizeof( counts ) ); - - stencilReadback = ( byte* )R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight(), TAG_RENDER_TOOLS ); - glReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); - - for( i = 0; i < renderSystem->GetWidth() * renderSystem->GetHeight(); i++ ) - { - counts[ stencilReadback[i] ]++; - } - - R_StaticFree( stencilReadback ); - - // print some stats (not supposed to do from back end in SMP...) - common->Printf( "stencil values:\n" ); - for( i = 0; i < 255; i++ ) - { - if( counts[i] ) - { - common->Printf( "%i: %i\n", i, counts[i] ); - } - } -} - - -/* -=================== -RB_CountStencilBuffer - -Print an overdraw count based on stencil index values -=================== -*/ -static void RB_CountStencilBuffer() -{ - int count; - int i; - byte* stencilReadback; - - - stencilReadback = ( byte* )R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight(), TAG_RENDER_TOOLS ); - glReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); - - count = 0; - for( i = 0; i < renderSystem->GetWidth() * renderSystem->GetHeight(); i++ ) - { - count += stencilReadback[i]; - } - - R_StaticFree( stencilReadback ); - - // print some stats (not supposed to do from back end in SMP...) - common->Printf( "overdraw: %5.1f\n", ( float )count / ( renderSystem->GetWidth() * renderSystem->GetHeight() ) ); -} - -/* -=================== -R_ColorByStencilBuffer - -Sets the screen colors based on the contents of the -stencil buffer. Stencil of 0 = black, 1 = red, 2 = green, -3 = blue, ..., 7+ = white -=================== -*/ -static void R_ColorByStencilBuffer() -{ - int i; - static idVec3 colors[8] = - { - idVec3( 0, 0, 0 ), - idVec3( 1, 0, 0 ), - idVec3( 0, 1, 0 ), - idVec3( 0, 0, 1 ), - idVec3( 0, 1, 1 ), - idVec3( 1, 0, 1 ), - idVec3( 1, 1, 0 ), - idVec3( 1, 1, 1 ), - }; - - // clear color buffer to white (>6 passes) - GL_Clear( true, false, false, 0, 1.0f, 1.0f, 1.0f, 1.0f ); - - // now draw color for each stencil value - glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); - for( i = 0; i < 6; i++ ) - { - GL_Color( colors[i] ); - renderProgManager.BindShader_Color(); - glStencilFunc( GL_EQUAL, i, 255 ); - RB_PolygonClear(); - } - - glStencilFunc( GL_ALWAYS, 0, 255 ); -} - -//====================================================================== - -/* -================== -RB_ShowOverdraw -================== -*/ -void RB_ShowOverdraw() -{ - const idMaterial* material; - int i; - drawSurf_t** drawSurfs; - const drawSurf_t* surf; - int numDrawSurfs; - viewLight_t* vLight; - - if( r_showOverDraw.GetInteger() == 0 ) - { - return; - } - - material = declManager->FindMaterial( "textures/common/overdrawtest", false ); - if( material == NULL ) - { - return; - } - - drawSurfs = backEnd.viewDef->drawSurfs; - numDrawSurfs = backEnd.viewDef->numDrawSurfs; - - int interactions = 0; - for( vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next ) - { - for( surf = vLight->localInteractions; surf; surf = surf->nextOnLight ) - { - interactions++; - } - for( surf = vLight->globalInteractions; surf; surf = surf->nextOnLight ) - { - interactions++; - } - } - - // FIXME: can't frame alloc from the renderer back-end - drawSurf_t** newDrawSurfs = ( drawSurf_t** )R_FrameAlloc( numDrawSurfs + interactions * sizeof( newDrawSurfs[0] ), FRAME_ALLOC_DRAW_SURFACE_POINTER ); - - for( i = 0; i < numDrawSurfs; i++ ) - { - surf = drawSurfs[i]; - if( surf->material ) - { - const_cast( surf )->material = material; - } - newDrawSurfs[i] = const_cast( surf ); - } - - for( vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next ) - { - for( surf = vLight->localInteractions; surf; surf = surf->nextOnLight ) - { - const_cast( surf )->material = material; - newDrawSurfs[i++] = const_cast( surf ); - } - for( surf = vLight->globalInteractions; surf; surf = surf->nextOnLight ) - { - const_cast( surf )->material = material; - newDrawSurfs[i++] = const_cast( surf ); - } - vLight->localInteractions = NULL; - vLight->globalInteractions = NULL; - } - - switch( r_showOverDraw.GetInteger() ) - { - case 1: // geometry overdraw - const_cast( backEnd.viewDef )->drawSurfs = newDrawSurfs; - const_cast( backEnd.viewDef )->numDrawSurfs = numDrawSurfs; - break; - case 2: // light interaction overdraw - const_cast( backEnd.viewDef )->drawSurfs = &newDrawSurfs[numDrawSurfs]; - const_cast( backEnd.viewDef )->numDrawSurfs = interactions; - break; - case 3: // geometry + light interaction overdraw - const_cast( backEnd.viewDef )->drawSurfs = newDrawSurfs; - const_cast( backEnd.viewDef )->numDrawSurfs += interactions; - break; - } -} - -/* -=================== -RB_ShowIntensity - -Debugging tool to see how much dynamic range a scene is using. -The greatest of the rgb values at each pixel will be used, with -the resulting color shading from red at 0 to green at 128 to blue at 255 -=================== -*/ -static void RB_ShowIntensity() -{ - byte* colorReadback; - int i, j, c; - - if( !r_showIntensity.GetBool() ) - { - return; - } - - colorReadback = ( byte* )R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight() * 4, TAG_RENDER_TOOLS ); - glReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_RGBA, GL_UNSIGNED_BYTE, colorReadback ); - - c = renderSystem->GetWidth() * renderSystem->GetHeight() * 4; - for( i = 0; i < c; i += 4 ) - { - j = colorReadback[i]; - if( colorReadback[i + 1] > j ) - { - j = colorReadback[i + 1]; - } - if( colorReadback[i + 2] > j ) - { - j = colorReadback[i + 2]; - } - if( j < 128 ) - { - colorReadback[i + 0] = 2 * ( 128 - j ); - colorReadback[i + 1] = 2 * j; - colorReadback[i + 2] = 0; - } - else - { - colorReadback[i + 0] = 0; - colorReadback[i + 1] = 2 * ( 255 - j ); - colorReadback[i + 2] = 2 * ( j - 128 ); - } - } - - // draw it back to the screen - glLoadIdentity(); - glMatrixMode( GL_PROJECTION ); - GL_State( GLS_DEPTHFUNC_ALWAYS ); - glPushMatrix(); - glLoadIdentity(); - glOrtho( 0, 1, 0, 1, -1, 1 ); - glRasterPos2f( 0, 0 ); - glPopMatrix(); - GL_Color( 1, 1, 1 ); - globalImages->BindNull(); - glMatrixMode( GL_MODELVIEW ); - - glDrawPixels( renderSystem->GetWidth(), renderSystem->GetHeight(), GL_RGBA , GL_UNSIGNED_BYTE, colorReadback ); - - R_StaticFree( colorReadback ); -} - - -/* -=================== -RB_ShowDepthBuffer - -Draw the depth buffer as colors -=================== -*/ -static void RB_ShowDepthBuffer() -{ - void* depthReadback; - - if( !r_showDepth.GetBool() ) - { - return; - } - - glPushMatrix(); - glLoadIdentity(); - glMatrixMode( GL_PROJECTION ); - glPushMatrix(); - glLoadIdentity(); - glOrtho( 0, 1, 0, 1, -1, 1 ); - glRasterPos2f( 0, 0 ); - glPopMatrix(); - glMatrixMode( GL_MODELVIEW ); - glPopMatrix(); - - GL_State( GLS_DEPTHFUNC_ALWAYS ); - GL_Color( 1, 1, 1 ); - globalImages->BindNull(); - - depthReadback = R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight() * 4, TAG_RENDER_TOOLS ); - memset( depthReadback, 0, renderSystem->GetWidth() * renderSystem->GetHeight() * 4 ); - - glReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_DEPTH_COMPONENT , GL_FLOAT, depthReadback ); - -#if 0 - for( i = 0; i < renderSystem->GetWidth() * renderSystem->GetHeight(); i++ ) - { - ( ( byte* )depthReadback )[i * 4] = - ( ( byte* )depthReadback )[i * 4 + 1] = - ( ( byte* )depthReadback )[i * 4 + 2] = 255 * ( ( float* )depthReadback )[i]; - ( ( byte* )depthReadback )[i * 4 + 3] = 1; - } -#endif - - glDrawPixels( renderSystem->GetWidth(), renderSystem->GetHeight(), GL_RGBA , GL_UNSIGNED_BYTE, depthReadback ); - R_StaticFree( depthReadback ); -} - -/* -================= -RB_ShowLightCount - -This is a debugging tool that will draw each surface with a color -based on how many lights are effecting it -================= -*/ -static void RB_ShowLightCount() -{ - int i; - const drawSurf_t* surf; - const viewLight_t* vLight; - - if( !r_showLightCount.GetBool() ) - { - return; - } - - RB_SimpleWorldSetup(); - - GL_Clear( false, false, true, 0, 0.0f, 0.0f, 0.0f, 0.0f ); - - // optionally count everything through walls - if( r_showLightCount.GetInteger() >= 2 ) - { - GL_State( GLS_DEPTHFUNC_EQUAL | GLS_STENCIL_OP_FAIL_KEEP | GLS_STENCIL_OP_ZFAIL_INCR | GLS_STENCIL_OP_PASS_INCR ); - } - else - { - GL_State( GLS_DEPTHFUNC_EQUAL | GLS_STENCIL_OP_FAIL_KEEP | GLS_STENCIL_OP_ZFAIL_KEEP | GLS_STENCIL_OP_PASS_INCR ); - } - - globalImages->defaultImage->Bind(); - - for( vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next ) - { - for( i = 0; i < 2; i++ ) - { - for( surf = i ? vLight->localInteractions : vLight->globalInteractions; surf; surf = ( drawSurf_t* )surf->nextOnLight ) - { - RB_SimpleSurfaceSetup( surf ); - RB_DrawElementsWithCounters( surf ); - } - } - } - - // display the results - R_ColorByStencilBuffer(); - - if( r_showLightCount.GetInteger() > 2 ) - { - RB_CountStencilBuffer(); - } -} - -#if 0 -/* -=============== -RB_SetWeaponDepthHack -=============== -*/ -static void RB_SetWeaponDepthHack() -{ -} - -/* -=============== -RB_SetModelDepthHack -=============== -*/ -static void RB_SetModelDepthHack( float depth ) -{ -} - -/* -=============== -RB_EnterWeaponDepthHack -=============== -*/ -static void RB_EnterWeaponDepthHack() -{ - float matrix[16]; - - memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) ); - - const float modelDepthHack = 0.25f; - matrix[2] *= modelDepthHack; - matrix[6] *= modelDepthHack; - matrix[10] *= modelDepthHack; - matrix[14] *= modelDepthHack; - - glMatrixMode( GL_PROJECTION ); - glLoadMatrixf( matrix ); - glMatrixMode( GL_MODELVIEW ); -} - -/* -=============== -RB_EnterModelDepthHack -=============== -*/ -static void RB_EnterModelDepthHack( float depth ) -{ - float matrix[16]; - - memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) ); - - matrix[14] -= depth; - - glMatrixMode( GL_PROJECTION ); - glLoadMatrixf( matrix ); - glMatrixMode( GL_MODELVIEW ); -} - -/* -=============== -RB_LeaveDepthHack -=============== -*/ -static void RB_LeaveDepthHack() -{ - glMatrixMode( GL_PROJECTION ); - glLoadMatrixf( backEnd.viewDef->projectionMatrix ); - glMatrixMode( GL_MODELVIEW ); -} - -/* -============= -RB_LoadMatrixWithBypass - -does a glLoadMatrixf after optionally applying the low-latency bypass matrix -============= -*/ -static void RB_LoadMatrixWithBypass( const float m[16] ) -{ - glLoadMatrixf( m ); -} - -#endif -/* -==================== -RB_RenderDrawSurfListWithFunction - -The triangle functions can check backEnd.currentSpace != surf->space -to see if they need to perform any new matrix setup. The modelview -matrix will already have been loaded, and backEnd.currentSpace will -be updated after the triangle function completes. -==================== -*/ -static void RB_RenderDrawSurfListWithFunction( drawSurf_t** drawSurfs, int numDrawSurfs, void ( *triFunc_ )( const drawSurf_t* ) ) -{ - backEnd.currentSpace = NULL; - - for( int i = 0 ; i < numDrawSurfs ; i++ ) - { - const drawSurf_t* drawSurf = drawSurfs[i]; - if( drawSurf == NULL ) - { - continue; - } - - assert( drawSurf->space != NULL ); - - // RB begin -#if 1 - if( drawSurf->space != backEnd.currentSpace ) - { - backEnd.currentSpace = drawSurf->space; - - RB_SetMVP( drawSurf->space->mvp ); - } -#else - - if( drawSurf->space != NULL ) // is it ever NULL? Do we need to check? - { - // Set these values ahead of time so we don't have to reconstruct the matrices on the consoles - if( drawSurf->space->weaponDepthHack ) - { - RB_SetWeaponDepthHack(); - } - - if( drawSurf->space->modelDepthHack != 0.0f ) - { - RB_SetModelDepthHack( drawSurf->space->modelDepthHack ); - } - - // change the matrix if needed - if( drawSurf->space != backEnd.currentSpace ) - { - RB_LoadMatrixWithBypass( drawSurf->space->modelViewMatrix ); - } - - if( drawSurf->space->weaponDepthHack ) - { - RB_EnterWeaponDepthHack(); - } - - if( drawSurf->space->modelDepthHack != 0.0f ) - { - RB_EnterModelDepthHack( drawSurf->space->modelDepthHack ); - } - } -#endif - - if( drawSurf->jointCache ) - { - renderProgManager.BindShader_ColorSkinned(); - } - else - { - renderProgManager.BindShader_Color(); - } - // RB end - - // change the scissor if needed - if( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) - { - backEnd.currentScissor = drawSurf->scissorRect; - GL_Scissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); - } - - // render it - triFunc_( drawSurf ); - - // RB begin - /*if( drawSurf->space != NULL && ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) ) - { - RB_LeaveDepthHack(); - }*/ - // RB end - - backEnd.currentSpace = drawSurf->space; - } -} - -/* -================= -RB_ShowSilhouette - -Blacks out all edges, then adds color for each edge that a shadow -plane extends from, allowing you to see doubled edges - -FIXME: not thread safe! -================= -*/ -static void RB_ShowSilhouette() -{ - int i; - const drawSurf_t* surf; - const viewLight_t* vLight; - - if( !r_showSilhouette.GetBool() ) - { - return; - } - - // clear all triangle edges to black - globalImages->BindNull(); - - // RB begin - renderProgManager.BindShader_Color(); - // RB end - - GL_Color( 0, 0, 0 ); - - GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE ); - - GL_Cull( CT_TWO_SIDED ); - - RB_RenderDrawSurfListWithFunction( backEnd.viewDef->drawSurfs, backEnd.viewDef->numDrawSurfs, - RB_DrawElementsWithCounters ); - - - // now blend in edges that cast silhouettes - RB_SimpleWorldSetup(); - GL_Color( 0.5, 0, 0 ); - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - for( vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next ) - { - for( i = 0; i < 2; i++ ) - { - for( surf = i ? vLight->localShadows : vLight->globalShadows - ; surf; surf = ( drawSurf_t* )surf->nextOnLight ) - { - RB_SimpleSurfaceSetup( surf ); - - const srfTriangles_t* tri = surf->frontEndGeo; - - idVertexBuffer vertexBuffer; - if( !vertexCache.GetVertexBuffer( tri->shadowCache, &vertexBuffer ) ) - { - continue; - } - - // RB: 64 bit fixes, changed GLuint to GLintptr - glBindBuffer( GL_ARRAY_BUFFER, ( GLintptr )vertexBuffer.GetAPIObject() ); - GLintptr vertOffset = vertexBuffer.GetOffset(); - // RB end - - glVertexPointer( 3, GL_FLOAT, sizeof( idShadowVert ), ( void* )vertOffset ); - glBegin( GL_LINES ); - - for( int j = 0; j < tri->numIndexes; j += 3 ) - { - int i1 = tri->indexes[j + 0]; - int i2 = tri->indexes[j + 1]; - int i3 = tri->indexes[j + 2]; - - if( ( i1 & 1 ) + ( i2 & 1 ) + ( i3 & 1 ) == 1 ) - { - if( ( i1 & 1 ) + ( i2 & 1 ) == 0 ) - { - glArrayElement( i1 ); - glArrayElement( i2 ); - } - else if( ( i1 & 1 ) + ( i3 & 1 ) == 0 ) - { - glArrayElement( i1 ); - glArrayElement( i3 ); - } - } - } - glEnd(); - - } - } - } - - GL_State( GLS_DEFAULT ); - GL_Color( 1, 1, 1 ); - GL_Cull( CT_FRONT_SIDED ); -} - -/* -===================== -RB_ShowTris - -Debugging tool -===================== -*/ -static void RB_ShowTris( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - - modelTrace_t mt; - idVec3 end; - - if( r_showTris.GetInteger() == 0 ) - { - return; - } - - idVec4 color( 1, 1, 1, 1 ); - - GL_PolygonOffset( -1.0f, -2.0f ); - - switch( r_showTris.GetInteger() ) - { - case 1: // only draw visible ones - GL_State( GLS_DEPTHMASK | GLS_ALPHAMASK | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET ); - break; - case 2: // draw all front facing - case 3: // draw all - GL_State( GLS_DEPTHMASK | GLS_ALPHAMASK | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET | GLS_DEPTHFUNC_ALWAYS ); - break; - case 4: // only draw visible ones with blended lines - GL_State( GLS_DEPTHMASK | GLS_ALPHAMASK | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - color[3] = 0.4f; - break; - } - - if( r_showTris.GetInteger() == 3 ) - { - GL_Cull( CT_TWO_SIDED ); - } - - GL_Color( color ); - - RB_RenderDrawSurfListWithFunction( drawSurfs, numDrawSurfs, RB_DrawElementsWithCounters ); - - if( r_showTris.GetInteger() == 3 ) - { - GL_Cull( CT_FRONT_SIDED ); - } -} - -/* -===================== -RB_ShowSurfaceInfo - -Debugging tool -===================== -*/ - - -static idStr surfModelName, surfMatName; -static idVec3 surfPoint; -static bool surfTraced = false; - - -void idRenderSystemLocal::OnFrame() -{ - // Do tracing at a safe time to avoid threading issues. - modelTrace_t mt; - idVec3 start, end; - - surfTraced = false; - - if( !r_showSurfaceInfo.GetBool() ) - { - return; - } - - if( tr.primaryView == NULL ) - { - return; - } - - // start far enough away that we don't hit the player model - start = tr.primaryView->renderView.vieworg + tr.primaryView->renderView.viewaxis[0] * 32; - end = start + tr.primaryView->renderView.viewaxis[0] * 1000.0f; - if( !tr.primaryWorld->Trace( mt, start, end, 0.0f, false ) ) - { - return; - } - - surfPoint = mt.point; - surfModelName = mt.entity->hModel->Name(); - surfMatName = mt.material->GetName(); - surfTraced = true; -} - - -static void RB_ShowSurfaceInfo( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - if( !r_showSurfaceInfo.GetBool() || !surfTraced ) - { - return; - } - - // globalImages->BindNull(); - // qglDisable( GL_TEXTURE_2D ); - - RB_SimpleWorldSetup(); - - // foresthale 2014-05-02: don't use a shader for tools - //renderProgManager.BindShader_TextureVertexColor(); - GL_SelectTexture( 0 ); - globalImages->whiteImage->Bind(); - - RB_SetVertexColorParms( SVC_MODULATE ); - // foresthale 2014-05-02: don't use a shader for tools - //renderProgManager.CommitUniforms(); - - GL_Color( 1, 1, 1 ); - - static float scale = -1; - static float bias = -2; - - GL_PolygonOffset( scale, bias ); - GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET ); - - // idVec3 trans[3]; - // float matrix[16]; - - // transform the object verts into global space - // R_AxisToModelMatrix( mt.entity->axis, mt.entity->origin, matrix ); - - tr.primaryWorld->DrawText( surfModelName, surfPoint + tr.primaryView->renderView.viewaxis[2] * 12, - 0.35f, colorRed, tr.primaryView->renderView.viewaxis ); - tr.primaryWorld->DrawText( surfMatName, surfPoint, - 0.35f, colorBlue, tr.primaryView->renderView.viewaxis ); -} - -/* -===================== -RB_ShowViewEntitys - -Debugging tool -===================== -*/ -static void RB_ShowViewEntitys( viewEntity_t* vModels ) -{ - if( !r_showViewEntitys.GetBool() ) - { - return; - } - - if( r_showViewEntitys.GetInteger() >= 2 ) - { - common->Printf( "view entities: " ); - for( const viewEntity_t* vModel = vModels; vModel; vModel = vModel->next ) - { - if( vModel->entityDef->IsDirectlyVisible() ) - { - common->Printf( "<%i> ", vModel->entityDef->index ); - } - else - { - common->Printf( "%i ", vModel->entityDef->index ); - } - } - common->Printf( "\n" ); - } - - globalImages->BindNull(); - - renderProgManager.BindShader_Color(); - - GL_Color( 1, 1, 1 ); - GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE ); - GL_Cull( CT_TWO_SIDED ); - - for( const viewEntity_t* vModel = vModels; vModel; vModel = vModel->next ) - { - idBounds b; - - //glLoadMatrixf( vModel->modelViewMatrix ); - - const idRenderEntityLocal* edef = vModel->entityDef; - if( !edef ) - { - continue; - } - - // draw the model bounds in white if directly visible, - // or, blue if it is only-for-sahdow - idVec4 color; - if( edef->IsDirectlyVisible() ) - { - color.Set( 1, 1, 1, 1 ); - } - else - { - color.Set( 0, 0, 1, 1 ); - } - GL_Color( color[0], color[1], color[2] ); - RB_DrawBounds( edef->localReferenceBounds ); - - // transform the upper bounds corner into global space - if( r_showViewEntitys.GetInteger() >= 2 ) - { - idVec3 corner; - R_LocalPointToGlobal( vModel->modelMatrix, edef->localReferenceBounds[1], corner ); - - tr.primaryWorld->DrawText( - va( "%i:%s", edef->index, edef->parms.hModel->Name() ), - corner, - 0.25f, color, - tr.primaryView->renderView.viewaxis ); - } - - // draw the actual bounds in yellow if different - if( r_showViewEntitys.GetInteger() >= 3 ) - { - GL_Color( 1, 1, 0 ); - // FIXME: cannot instantiate a dynamic model from the renderer back-end - idRenderModel* model = R_EntityDefDynamicModel( vModel->entityDef ); - if( !model ) - { - continue; // particles won't instantiate without a current view - } - b = model->Bounds( &vModel->entityDef->parms ); - if( b != vModel->entityDef->localReferenceBounds ) - { - RB_DrawBounds( b ); - } - } - } -} - -/* -===================== -RB_ShowTexturePolarity - -Shade triangle red if they have a positive texture area -green if they have a negative texture area, or blue if degenerate area -===================== -*/ -static void RB_ShowTexturePolarity( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - int i, j; - drawSurf_t* drawSurf; - const srfTriangles_t* tri; - - if( !r_showTexturePolarity.GetBool() ) - { - return; - } - globalImages->BindNull(); - - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - - GL_Color( 1, 1, 1 ); - - for( i = 0; i < numDrawSurfs; i++ ) - { - drawSurf = drawSurfs[i]; - tri = drawSurf->frontEndGeo; - if( tri == NULL || tri->verts == NULL ) - { - continue; - } - - RB_SimpleSurfaceSetup( drawSurf ); - - glBegin( GL_TRIANGLES ); - for( j = 0; j < tri->numIndexes; j += 3 ) - { - idDrawVert* a, *b, *c; - float d0[5], d1[5]; - float area; - - a = tri->verts + tri->indexes[j]; - b = tri->verts + tri->indexes[j + 1]; - c = tri->verts + tri->indexes[j + 2]; - - const idVec2 aST = a->GetTexCoord(); - const idVec2 bST = b->GetTexCoord(); - const idVec2 cST = c->GetTexCoord(); - - d0[3] = bST[0] - aST[0]; - d0[4] = bST[1] - aST[1]; - - d1[3] = cST[0] - aST[0]; - d1[4] = cST[1] - aST[1]; - - area = d0[3] * d1[4] - d0[4] * d1[3]; - - if( idMath::Fabs( area ) < 0.0001 ) - { - GL_Color( 0, 0, 1, 0.5 ); - } - else if( area < 0 ) - { - GL_Color( 1, 0, 0, 0.5 ); - } - else - { - GL_Color( 0, 1, 0, 0.5 ); - } - glVertex3fv( a->xyz.ToFloatPtr() ); - glVertex3fv( b->xyz.ToFloatPtr() ); - glVertex3fv( c->xyz.ToFloatPtr() ); - } - glEnd(); - } - - GL_State( GLS_DEFAULT ); -} - -/* -===================== -RB_ShowUnsmoothedTangents - -Shade materials that are using unsmoothed tangents -===================== -*/ -static void RB_ShowUnsmoothedTangents( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - int i, j; - drawSurf_t* drawSurf; - const srfTriangles_t* tri; - - if( !r_showUnsmoothedTangents.GetBool() ) - { - return; - } - globalImages->BindNull(); - - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - - GL_Color( 0, 1, 0, 0.5 ); - - for( i = 0; i < numDrawSurfs; i++ ) - { - drawSurf = drawSurfs[i]; - - if( !drawSurf->material->UseUnsmoothedTangents() ) - { - continue; - } - - RB_SimpleSurfaceSetup( drawSurf ); - - tri = drawSurf->frontEndGeo; - if( tri == NULL || tri->verts == NULL ) - { - continue; - } - - glBegin( GL_TRIANGLES ); - for( j = 0; j < tri->numIndexes; j += 3 ) - { - idDrawVert* a, *b, *c; - - a = tri->verts + tri->indexes[j]; - b = tri->verts + tri->indexes[j + 1]; - c = tri->verts + tri->indexes[j + 2]; - - glVertex3fv( a->xyz.ToFloatPtr() ); - glVertex3fv( b->xyz.ToFloatPtr() ); - glVertex3fv( c->xyz.ToFloatPtr() ); - } - glEnd(); - } - - GL_State( GLS_DEFAULT ); -} - -/* -===================== -RB_ShowTangentSpace - -Shade a triangle by the RGB colors of its tangent space -1 = tangents[0] -2 = tangents[1] -3 = normal -===================== -*/ -static void RB_ShowTangentSpace( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - int i, j; - drawSurf_t* drawSurf; - const srfTriangles_t* tri; - - if( !r_showTangentSpace.GetInteger() ) - { - return; - } - globalImages->BindNull(); - - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - - for( i = 0; i < numDrawSurfs; i++ ) - { - drawSurf = drawSurfs[i]; - - RB_SimpleSurfaceSetup( drawSurf ); - - tri = drawSurf->frontEndGeo; - if( tri == NULL || tri->verts == NULL ) - { - continue; - } - - glBegin( GL_TRIANGLES ); - for( j = 0; j < tri->numIndexes; j++ ) - { - const idDrawVert* v; - - v = &tri->verts[tri->indexes[j]]; - - if( r_showTangentSpace.GetInteger() == 1 ) - { - const idVec3 vertexTangent = v->GetTangent(); - GL_Color( 0.5 + 0.5 * vertexTangent[0], 0.5 + 0.5 * vertexTangent[1], - 0.5 + 0.5 * vertexTangent[2], 0.5 ); - } - else if( r_showTangentSpace.GetInteger() == 2 ) - { - const idVec3 vertexBiTangent = v->GetBiTangent(); - GL_Color( 0.5 + 0.5 * vertexBiTangent[0], 0.5 + 0.5 * vertexBiTangent[1], - 0.5 + 0.5 * vertexBiTangent[2], 0.5 ); - } - else - { - const idVec3 vertexNormal = v->GetNormal(); - GL_Color( 0.5 + 0.5 * vertexNormal[0], 0.5 + 0.5 * vertexNormal[1], - 0.5 + 0.5 * vertexNormal[2], 0.5 ); - } - glVertex3fv( v->xyz.ToFloatPtr() ); - } - glEnd(); - } - - GL_State( GLS_DEFAULT ); -} - -/* -===================== -RB_ShowVertexColor - -Draw each triangle with the solid vertex colors -===================== -*/ -static void RB_ShowVertexColor( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - int i, j; - drawSurf_t* drawSurf; - const srfTriangles_t* tri; - - if( !r_showVertexColor.GetBool() ) - { - return; - } - globalImages->BindNull(); - - // RB begin - renderProgManager.BindShader_VertexColor(); - - GL_State( GLS_DEPTHFUNC_LESS ); - - for( i = 0; i < numDrawSurfs; i++ ) - { - drawSurf = drawSurfs[i]; - - RB_SimpleSurfaceSetup( drawSurf ); - - tri = drawSurf->frontEndGeo; - if( tri == NULL || tri->verts == NULL ) - { - continue; - } - - renderProgManager.CommitUniforms(); - - glBegin( GL_TRIANGLES ); - for( j = 0; j < tri->numIndexes; j++ ) - { - const idDrawVert* v; - - v = &tri->verts[tri->indexes[j]]; - glColor4ubv( v->color ); - glVertex3fv( v->xyz.ToFloatPtr() ); - } - glEnd(); - } - - // RB end - - GL_State( GLS_DEFAULT ); -} - -/* -===================== -RB_ShowNormals - -Debugging tool -===================== -*/ -static void RB_ShowNormals( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - int i, j; - drawSurf_t* drawSurf; - idVec3 end; - const srfTriangles_t* tri; - float size; - bool showNumbers; - idVec3 pos; - - if( r_showNormals.GetFloat() == 0.0f ) - { - return; - } - - globalImages->BindNull(); - - if( !r_debugLineDepthTest.GetBool() ) - { - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS ); - } - else - { - GL_State( GLS_POLYMODE_LINE ); - } - - size = r_showNormals.GetFloat(); - if( size < 0.0f ) - { - size = -size; - showNumbers = true; - } - else - { - showNumbers = false; - } - - for( i = 0; i < numDrawSurfs; i++ ) - { - drawSurf = drawSurfs[i]; - - RB_SimpleSurfaceSetup( drawSurf ); - - tri = drawSurf->frontEndGeo; - if( tri == NULL || tri->verts == NULL ) - { - continue; - } - - // RB begin - renderProgManager.BindShader_VertexColor(); - - glBegin( GL_LINES ); - for( j = 0; j < tri->numVerts; j++ ) - { - const idVec3 normal = tri->verts[j].GetNormal(); - const idVec3 tangent = tri->verts[j].GetTangent(); - const idVec3 bitangent = tri->verts[j].GetBiTangent(); - - glColor3f( 0, 0, 1 ); - glVertex3fv( tri->verts[j].xyz.ToFloatPtr() ); - VectorMA( tri->verts[j].xyz, size, normal, end ); - glVertex3fv( end.ToFloatPtr() ); - - glColor3f( 1, 0, 0 ); - glVertex3fv( tri->verts[j].xyz.ToFloatPtr() ); - VectorMA( tri->verts[j].xyz, size, tangent, end ); - glVertex3fv( end.ToFloatPtr() ); - - glColor3f( 0, 1, 0 ); - glVertex3fv( tri->verts[j].xyz.ToFloatPtr() ); - VectorMA( tri->verts[j].xyz, size, bitangent, end ); - glVertex3fv( end.ToFloatPtr() ); - } - glEnd(); - - // RB end - } - - if( showNumbers ) - { - RB_SimpleWorldSetup(); - for( i = 0; i < numDrawSurfs; i++ ) - { - drawSurf = drawSurfs[i]; - tri = drawSurf->frontEndGeo; - if( tri == NULL || tri->verts == NULL ) - { - continue; - } - - for( j = 0; j < tri->numVerts; j++ ) - { - const idVec3 normal = tri->verts[j].GetNormal(); - const idVec3 tangent = tri->verts[j].GetTangent(); - R_LocalPointToGlobal( drawSurf->space->modelMatrix, tri->verts[j].xyz + tangent + normal * 0.2f, pos ); - RB_DrawText( va( "%d", j ), pos, 0.01f, colorWhite, backEnd.viewDef->renderView.viewaxis, 1 ); - } - - for( j = 0; j < tri->numIndexes; j += 3 ) - { - const idVec3 normal = tri->verts[ tri->indexes[ j + 0 ] ].GetNormal(); - R_LocalPointToGlobal( drawSurf->space->modelMatrix, ( tri->verts[ tri->indexes[ j + 0 ] ].xyz + tri->verts[ tri->indexes[ j + 1 ] ].xyz + tri->verts[ tri->indexes[ j + 2 ] ].xyz ) * ( 1.0f / 3.0f ) + normal * 0.2f, pos ); - RB_DrawText( va( "%d", j / 3 ), pos, 0.01f, colorCyan, backEnd.viewDef->renderView.viewaxis, 1 ); - } - } - } -} - -#if 0 // compiler warning - -/* -===================== -RB_ShowNormals - -Debugging tool -===================== -*/ -static void RB_AltShowNormals( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - if( r_showNormals.GetFloat() == 0.0f ) - { - return; - } - - globalImages->BindNull(); - - GL_State( GLS_DEPTHFUNC_ALWAYS ); - - for( int i = 0; i < numDrawSurfs; i++ ) - { - drawSurf_t* drawSurf = drawSurfs[i]; - - RB_SimpleSurfaceSetup( drawSurf ); - - const srfTriangles_t* tri = drawSurf->geo; - - glBegin( GL_LINES ); - for( int j = 0; j < tri->numIndexes; j += 3 ) - { - const idDrawVert* v[3] = - { - &tri->verts[tri->indexes[j + 0]], - &tri->verts[tri->indexes[j + 1]], - &tri->verts[tri->indexes[j + 2]] - } - - const idPlane plane( v[0]->xyz, v[1]->xyz, v[2]->xyz ); - - // make the midpoint slightly above the triangle - const idVec3 mid = ( v[0]->xyz + v[1]->xyz + v[2]->xyz ) * ( 1.0f / 3.0f ) + 0.1f * plane.Normal(); - - for( int k = 0; k < 3; k++ ) - { - const idVec3 pos = ( mid + v[k]->xyz * 3.0f ) * 0.25f; - idVec3 end; - - GL_Color( 0, 0, 1 ); - glVertex3fv( pos.ToFloatPtr() ); - VectorMA( pos, r_showNormals.GetFloat(), v[k]->normal, end ); - glVertex3fv( end.ToFloatPtr() ); - - GL_Color( 1, 0, 0 ); - glVertex3fv( pos.ToFloatPtr() ); - VectorMA( pos, r_showNormals.GetFloat(), v[k]->tangents[0], end ); - glVertex3fv( end.ToFloatPtr() ); - - GL_Color( 0, 1, 0 ); - glVertex3fv( pos.ToFloatPtr() ); - VectorMA( pos, r_showNormals.GetFloat(), v[k]->tangents[1], end ); - glVertex3fv( end.ToFloatPtr() ); - - GL_Color( 1, 1, 1 ); - glVertex3fv( pos.ToFloatPtr() ); - glVertex3fv( v[k]->xyz.ToFloatPtr() ); - } - } - glEnd(); - } -} - -#endif - -/* -===================== -RB_ShowTextureVectors - -Draw texture vectors in the center of each triangle -===================== -*/ -static void RB_ShowTextureVectors( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - if( r_showTextureVectors.GetFloat() == 0.0f ) - { - return; - } - - GL_State( GLS_DEPTHFUNC_LESS ); - - globalImages->BindNull(); - - for( int i = 0; i < numDrawSurfs; i++ ) - { - drawSurf_t* drawSurf = drawSurfs[i]; - - const srfTriangles_t* tri = drawSurf->frontEndGeo; - - if( tri == NULL || tri->verts == NULL ) - { - continue; - } - - RB_SimpleSurfaceSetup( drawSurf ); - - // draw non-shared edges in yellow - glBegin( GL_LINES ); - - for( int j = 0; j < tri->numIndexes; j += 3 ) - { - float d0[5], d1[5]; - idVec3 temp; - idVec3 tangents[2]; - - const idDrawVert* a = &tri->verts[tri->indexes[j + 0]]; - const idDrawVert* b = &tri->verts[tri->indexes[j + 1]]; - const idDrawVert* c = &tri->verts[tri->indexes[j + 2]]; - - const idPlane plane( a->xyz, b->xyz, c->xyz ); - - // make the midpoint slightly above the triangle - const idVec3 mid = ( a->xyz + b->xyz + c->xyz ) * ( 1.0f / 3.0f ) + 0.1f * plane.Normal(); - - // calculate the texture vectors - const idVec2 aST = a->GetTexCoord(); - const idVec2 bST = b->GetTexCoord(); - const idVec2 cST = c->GetTexCoord(); - - d0[0] = b->xyz[0] - a->xyz[0]; - d0[1] = b->xyz[1] - a->xyz[1]; - d0[2] = b->xyz[2] - a->xyz[2]; - d0[3] = bST[0] - aST[0]; - d0[4] = bST[1] - aST[1]; - - d1[0] = c->xyz[0] - a->xyz[0]; - d1[1] = c->xyz[1] - a->xyz[1]; - d1[2] = c->xyz[2] - a->xyz[2]; - d1[3] = cST[0] - aST[0]; - d1[4] = cST[1] - aST[1]; - - const float area = d0[3] * d1[4] - d0[4] * d1[3]; - if( area == 0 ) - { - continue; - } - const float inva = 1.0f / area; - - temp[0] = ( d0[0] * d1[4] - d0[4] * d1[0] ) * inva; - temp[1] = ( d0[1] * d1[4] - d0[4] * d1[1] ) * inva; - temp[2] = ( d0[2] * d1[4] - d0[4] * d1[2] ) * inva; - temp.Normalize(); - tangents[0] = temp; - - temp[0] = ( d0[3] * d1[0] - d0[0] * d1[3] ) * inva; - temp[1] = ( d0[3] * d1[1] - d0[1] * d1[3] ) * inva; - temp[2] = ( d0[3] * d1[2] - d0[2] * d1[3] ) * inva; - temp.Normalize(); - tangents[1] = temp; - - // draw the tangents - tangents[0] = mid + tangents[0] * r_showTextureVectors.GetFloat(); - tangents[1] = mid + tangents[1] * r_showTextureVectors.GetFloat(); - - GL_Color( 1, 0, 0 ); - glVertex3fv( mid.ToFloatPtr() ); - glVertex3fv( tangents[0].ToFloatPtr() ); - - GL_Color( 0, 1, 0 ); - glVertex3fv( mid.ToFloatPtr() ); - glVertex3fv( tangents[1].ToFloatPtr() ); - } - - glEnd(); - } -} - -/* -===================== -RB_ShowDominantTris - -Draw lines from each vertex to the dominant triangle center -===================== -*/ -static void RB_ShowDominantTris( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - int i, j; - drawSurf_t* drawSurf; - const srfTriangles_t* tri; - - if( !r_showDominantTri.GetBool() ) - { - return; - } - - GL_State( GLS_DEPTHFUNC_LESS ); - - GL_PolygonOffset( -1, -2 ); - glEnable( GL_POLYGON_OFFSET_LINE ); - - globalImages->BindNull(); - - for( i = 0; i < numDrawSurfs; i++ ) - { - drawSurf = drawSurfs[i]; - - tri = drawSurf->frontEndGeo; - - if( tri == NULL || tri->verts == NULL ) - { - continue; - } - if( !tri->dominantTris ) - { - continue; - } - RB_SimpleSurfaceSetup( drawSurf ); - - GL_Color( 1, 1, 0 ); - glBegin( GL_LINES ); - - for( j = 0; j < tri->numVerts; j++ ) - { - const idDrawVert* a, *b, *c; - idVec3 mid; - - // find the midpoint of the dominant tri - - a = &tri->verts[j]; - b = &tri->verts[tri->dominantTris[j].v2]; - c = &tri->verts[tri->dominantTris[j].v3]; - - mid = ( a->xyz + b->xyz + c->xyz ) * ( 1.0f / 3.0f ); - - glVertex3fv( mid.ToFloatPtr() ); - glVertex3fv( a->xyz.ToFloatPtr() ); - } - - glEnd(); - } - glDisable( GL_POLYGON_OFFSET_LINE ); -} - -/* -===================== -RB_ShowEdges - -Debugging tool -===================== -*/ -static void RB_ShowEdges( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - int i, j, k, m, n, o; - drawSurf_t* drawSurf; - const srfTriangles_t* tri; - const silEdge_t* edge; - int danglePlane; - - if( !r_showEdges.GetBool() ) - { - return; - } - - globalImages->BindNull(); - - GL_State( GLS_DEPTHFUNC_ALWAYS ); - - for( i = 0; i < numDrawSurfs; i++ ) - { - drawSurf = drawSurfs[i]; - - tri = drawSurf->frontEndGeo; - - idDrawVert* ac = ( idDrawVert* )tri->verts; - if( !ac ) - { - continue; - } - - RB_SimpleSurfaceSetup( drawSurf ); - - // draw non-shared edges in yellow - GL_Color( 1, 1, 0 ); - glBegin( GL_LINES ); - - for( j = 0; j < tri->numIndexes; j += 3 ) - { - for( k = 0; k < 3; k++ ) - { - int l, i1, i2; - l = ( k == 2 ) ? 0 : k + 1; - i1 = tri->indexes[j + k]; - i2 = tri->indexes[j + l]; - - // if these are used backwards, the edge is shared - for( m = 0; m < tri->numIndexes; m += 3 ) - { - for( n = 0; n < 3; n++ ) - { - o = ( n == 2 ) ? 0 : n + 1; - if( tri->indexes[m + n] == i2 && tri->indexes[m + o] == i1 ) - { - break; - } - } - if( n != 3 ) - { - break; - } - } - - // if we didn't find a backwards listing, draw it in yellow - if( m == tri->numIndexes ) - { - glVertex3fv( ac[ i1 ].xyz.ToFloatPtr() ); - glVertex3fv( ac[ i2 ].xyz.ToFloatPtr() ); - } - - } - } - - glEnd(); - - // draw dangling sil edges in red - if( !tri->silEdges ) - { - continue; - } - - // the plane number after all real planes - // is the dangling edge - danglePlane = tri->numIndexes / 3; - - GL_Color( 1, 0, 0 ); - - glBegin( GL_LINES ); - for( j = 0; j < tri->numSilEdges; j++ ) - { - edge = tri->silEdges + j; - - if( edge->p1 != danglePlane && edge->p2 != danglePlane ) - { - continue; - } - - glVertex3fv( ac[ edge->v1 ].xyz.ToFloatPtr() ); - glVertex3fv( ac[ edge->v2 ].xyz.ToFloatPtr() ); - } - glEnd(); - } -} - -/* -============== -RB_ShowLights - -Visualize all light volumes used in the current scene -r_showLights 1 : just print volumes numbers, highlighting ones covering the view -r_showLights 2 : also draw planes of each volume -r_showLights 3 : also draw edges of each volume -============== -*/ -static void RB_ShowLights() -{ - if( !r_showLights.GetInteger() ) - { - return; - } - - GL_State( GLS_DEFAULT ); - - globalImages->BindNull(); - - renderProgManager.BindShader_Color(); - - GL_Cull( CT_TWO_SIDED ); - - common->Printf( "volumes: " ); // FIXME: not in back end! - - int count = 0; - for( viewLight_t* vLight = backEnd.viewDef->viewLights; vLight != NULL; vLight = vLight->next ) - { - count++; - - // depth buffered planes - if( r_showLights.GetInteger() >= 2 ) - { - GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK ); - - // RB: show different light types - if( vLight->parallel ) - { - GL_Color( 1.0f, 0.0f, 0.0f, 0.25f ); - } - else if( vLight->pointLight ) - { - GL_Color( 0.0f, 0.0f, 1.0f, 0.25f ); - } - else - { - GL_Color( 0.0f, 1.0f, 0.0f, 0.25f ); - } - // RB end - - idRenderMatrix invProjectMVPMatrix; - idRenderMatrix::Multiply( backEnd.viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix ); - RB_SetMVP( invProjectMVPMatrix ); - RB_DrawElementsWithCounters( &backEnd.zeroOneCubeSurface ); - } - - // non-hidden lines - if( r_showLights.GetInteger() >= 3 ) - { - GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE | GLS_DEPTHMASK ); - GL_Color( 1.0f, 1.0f, 1.0f ); - idRenderMatrix invProjectMVPMatrix; - idRenderMatrix::Multiply( backEnd.viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix ); - RB_SetMVP( invProjectMVPMatrix ); - RB_DrawElementsWithCounters( &backEnd.zeroOneCubeSurface ); - } - - common->Printf( "%i ", vLight->lightDef->index ); - } - - common->Printf( " = %i total\n", count ); -} - -// RB begin -static void RB_ShowShadowMapLODs() -{ - if( !r_showShadowMapLODs.GetInteger() ) - { - return; - } - - GL_State( GLS_DEFAULT ); - - globalImages->BindNull(); - - renderProgManager.BindShader_Color(); - - GL_Cull( CT_TWO_SIDED ); - - common->Printf( "volumes: " ); // FIXME: not in back end! - - int count = 0; - for( viewLight_t* vLight = backEnd.viewDef->viewLights; vLight != NULL; vLight = vLight->next ) - { - if( !vLight->lightDef->LightCastsShadows() ) - { - continue; - } - - count++; - - // depth buffered planes - if( r_showShadowMapLODs.GetInteger() >= 1 ) - { - GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK ); - - idVec4 c; - if( vLight->shadowLOD == 0 ) - { - c = colorRed; - } - else if( vLight->shadowLOD == 1 ) - { - c = colorGreen; - } - else if( vLight->shadowLOD == 2 ) - { - c = colorBlue; - } - else if( vLight->shadowLOD == 3 ) - { - c = colorYellow; - } - else if( vLight->shadowLOD == 4 ) - { - c = colorMagenta; - } - else if( vLight->shadowLOD == 5 ) - { - c = colorCyan; - } - else - { - c = colorMdGrey; - } - - c[3] = 0.25f; - GL_Color( c ); - - idRenderMatrix invProjectMVPMatrix; - idRenderMatrix::Multiply( backEnd.viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix ); - RB_SetMVP( invProjectMVPMatrix ); - RB_DrawElementsWithCounters( &backEnd.zeroOneCubeSurface ); - } - - // non-hidden lines - if( r_showShadowMapLODs.GetInteger() >= 2 ) - { - GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE | GLS_DEPTHMASK ); - GL_Color( 1.0f, 1.0f, 1.0f ); - idRenderMatrix invProjectMVPMatrix; - idRenderMatrix::Multiply( backEnd.viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix ); - RB_SetMVP( invProjectMVPMatrix ); - RB_DrawElementsWithCounters( &backEnd.zeroOneCubeSurface ); - } - - common->Printf( "%i ", vLight->lightDef->index ); - } - - common->Printf( " = %i total\n", count ); -} -// RB end - -/* -===================== -RB_ShowPortals - -Debugging tool, won't work correctly with SMP or when mirrors are present -===================== -*/ -static void RB_ShowPortals() -{ - if( !r_showPortals.GetBool() ) - { - return; - } - - // all portals are expressed in world coordinates - RB_SimpleWorldSetup(); - - globalImages->BindNull(); - renderProgManager.BindShader_Color(); - GL_State( GLS_DEPTHFUNC_ALWAYS ); - - ( ( idRenderWorldLocal* )backEnd.viewDef->renderWorld )->ShowPortals(); -} - -/* -================ -RB_ClearDebugText -================ -*/ -void RB_ClearDebugText( int time ) -{ - int i; - int num; - debugText_t* text; - - rb_debugTextTime = time; - - if( !time ) - { - // free up our strings - text = rb_debugText; - for( i = 0; i < MAX_DEBUG_TEXT; i++, text++ ) - { - text->text.Clear(); - } - rb_numDebugText = 0; - return; - } - - // copy any text that still needs to be drawn - num = 0; - text = rb_debugText; - for( i = 0; i < rb_numDebugText; i++, text++ ) - { - if( text->lifeTime > time ) - { - if( num != i ) - { - rb_debugText[ num ] = *text; - } - num++; - } - } - rb_numDebugText = num; -} - -/* -================ -RB_AddDebugText -================ -*/ -void RB_AddDebugText( const char* text, const idVec3& origin, float scale, const idVec4& color, const idMat3& viewAxis, const int align, const int lifetime, const bool depthTest ) -{ - debugText_t* debugText; - - if( rb_numDebugText < MAX_DEBUG_TEXT ) - { - debugText = &rb_debugText[ rb_numDebugText++ ]; - debugText->text = text; - debugText->origin = origin; - debugText->scale = scale; - debugText->color = color; - debugText->viewAxis = viewAxis; - debugText->align = align; - debugText->lifeTime = rb_debugTextTime + lifetime; - debugText->depthTest = depthTest; - } -} - -/* -================ -RB_DrawTextLength - - returns the length of the given text -================ -*/ -float RB_DrawTextLength( const char* text, float scale, int len ) -{ - int i, num, index, charIndex; - float spacing, textLen = 0.0f; - - if( text && *text ) - { - if( !len ) - { - len = strlen( text ); - } - for( i = 0; i < len; i++ ) - { - charIndex = text[i] - 32; - if( charIndex < 0 || charIndex > NUM_SIMPLEX_CHARS ) - { - continue; - } - num = simplex[charIndex][0] * 2; - spacing = simplex[charIndex][1]; - index = 2; - - while( index - 2 < num ) - { - if( simplex[charIndex][index] < 0 ) - { - index++; - continue; - } - index += 2; - if( simplex[charIndex][index] < 0 ) - { - index++; - continue; - } - } - textLen += spacing * scale; - } - } - return textLen; -} - -/* -================ -RB_DrawText - - oriented on the viewaxis - align can be 0-left, 1-center (default), 2-right -================ -*/ -static void RB_DrawText( const char* text, const idVec3& origin, float scale, const idVec4& color, const idMat3& viewAxis, const int align ) -{ - renderProgManager.BindShader_Color(); - - // RB begin - GL_Color( color[0], color[1], color[2], 1 /*color[3]*/ ); - renderProgManager.CommitUniforms(); - // RB end - - int i, j, len, num, index, charIndex, line; - float textLen = 1.0f, spacing = 1.0f; - idVec3 org, p1, p2; - - if( text && *text ) - { - glBegin( GL_LINES ); - - if( text[0] == '\n' ) - { - line = 1; - } - else - { - line = 0; - } - - len = strlen( text ); - for( i = 0; i < len; i++ ) - { - - if( i == 0 || text[i] == '\n' ) - { - org = origin - viewAxis[2] * ( line * 36.0f * scale ); - if( align != 0 ) - { - for( j = 1; i + j <= len; j++ ) - { - if( i + j == len || text[i + j] == '\n' ) - { - textLen = RB_DrawTextLength( text + i, scale, j ); - break; - } - } - if( align == 2 ) - { - // right - org += viewAxis[1] * textLen; - } - else - { - // center - org += viewAxis[1] * ( textLen * 0.5f ); - } - } - line++; - } - - charIndex = text[i] - 32; - if( charIndex < 0 || charIndex > NUM_SIMPLEX_CHARS ) - { - continue; - } - num = simplex[charIndex][0] * 2; - spacing = simplex[charIndex][1]; - index = 2; - - while( index - 2 < num ) - { - if( simplex[charIndex][index] < 0 ) - { - index++; - continue; - } - p1 = org + scale * simplex[charIndex][index] * -viewAxis[1] + scale * simplex[charIndex][index + 1] * viewAxis[2]; - index += 2; - if( simplex[charIndex][index] < 0 ) - { - index++; - continue; - } - p2 = org + scale * simplex[charIndex][index] * -viewAxis[1] + scale * simplex[charIndex][index + 1] * viewAxis[2]; - - glVertex3fv( p1.ToFloatPtr() ); - glVertex3fv( p2.ToFloatPtr() ); - } - org -= viewAxis[1] * ( spacing * scale ); - } - - glEnd(); - } -} - -/* -================ -RB_ShowDebugText -================ -*/ -void RB_ShowDebugText() -{ - int i; - int width; - debugText_t* text; - - if( !rb_numDebugText ) - { - return; - } - - // all lines are expressed in world coordinates - RB_SimpleWorldSetup(); - - globalImages->BindNull(); - - width = r_debugLineWidth.GetInteger(); - if( width < 1 ) - { - width = 1; - } - else if( width > 10 ) - { - width = 10; - } - - // draw lines - glLineWidth( width ); - - - if( !r_debugLineDepthTest.GetBool() ) - { - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS ); - } - else - { - GL_State( GLS_POLYMODE_LINE ); - } - - text = rb_debugText; - for( i = 0; i < rb_numDebugText; i++, text++ ) - { - if( !text->depthTest ) - { - RB_DrawText( text->text, text->origin, text->scale, text->color, text->viewAxis, text->align ); - } - } - - if( !r_debugLineDepthTest.GetBool() ) - { - GL_State( GLS_POLYMODE_LINE ); - } - - text = rb_debugText; - for( i = 0; i < rb_numDebugText; i++, text++ ) - { - if( text->depthTest ) - { - RB_DrawText( text->text, text->origin, text->scale, text->color, text->viewAxis, text->align ); - } - } - - glLineWidth( 1 ); -} - -/* -================ -RB_ClearDebugLines -================ -*/ -void RB_ClearDebugLines( int time ) -{ - int i; - int num; - debugLine_t* line; - - rb_debugLineTime = time; - - if( !time ) - { - rb_numDebugLines = 0; - return; - } - - // copy any lines that still need to be drawn - num = 0; - line = rb_debugLines; - for( i = 0; i < rb_numDebugLines; i++, line++ ) - { - if( line->lifeTime > time ) - { - if( num != i ) - { - rb_debugLines[ num ] = *line; - } - num++; - } - } - rb_numDebugLines = num; -} - -/* -================ -RB_AddDebugLine -================ -*/ -void RB_AddDebugLine( const idVec4& color, const idVec3& start, const idVec3& end, const int lifeTime, const bool depthTest ) -{ - debugLine_t* line; - - if( rb_numDebugLines < MAX_DEBUG_LINES ) - { - line = &rb_debugLines[ rb_numDebugLines++ ]; - line->rgb = color; - line->start = start; - line->end = end; - line->depthTest = depthTest; - line->lifeTime = rb_debugLineTime + lifeTime; - } -} - -/* -================ -RB_ShowDebugLines -================ -*/ -void RB_ShowDebugLines() -{ - int i; - int width; - debugLine_t* line; - - if( !rb_numDebugLines ) - { - return; - } - - // all lines are expressed in world coordinates - RB_SimpleWorldSetup(); - - // RB begin - renderProgManager.BindShader_VertexColor(); - renderProgManager.CommitUniforms(); - // RB end - - globalImages->BindNull(); - - width = r_debugLineWidth.GetInteger(); - if( width < 1 ) - { - width = 1; - } - else if( width > 10 ) - { - width = 10; - } - - // draw lines - glLineWidth( width ); - - if( !r_debugLineDepthTest.GetBool() ) - { - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS ); - } - else - { - GL_State( GLS_POLYMODE_LINE ); - } - - glBegin( GL_LINES ); - - line = rb_debugLines; - for( i = 0; i < rb_numDebugLines; i++, line++ ) - { - if( !line->depthTest ) - { - glColor3fv( line->rgb.ToFloatPtr() ); - glVertex3fv( line->start.ToFloatPtr() ); - glVertex3fv( line->end.ToFloatPtr() ); - } - } - glEnd(); - - if( !r_debugLineDepthTest.GetBool() ) - { - GL_State( GLS_POLYMODE_LINE ); - } - - glBegin( GL_LINES ); - - line = rb_debugLines; - for( i = 0; i < rb_numDebugLines; i++, line++ ) - { - if( line->depthTest ) - { - glColor4fv( line->rgb.ToFloatPtr() ); - glVertex3fv( line->start.ToFloatPtr() ); - glVertex3fv( line->end.ToFloatPtr() ); - } - } - - glEnd(); - - glLineWidth( 1 ); - GL_State( GLS_DEFAULT ); -} - -/* -================ -RB_ClearDebugPolygons -================ -*/ -void RB_ClearDebugPolygons( int time ) -{ - int i; - int num; - debugPolygon_t* poly; - - rb_debugPolygonTime = time; - - if( !time ) - { - rb_numDebugPolygons = 0; - return; - } - - // copy any polygons that still need to be drawn - num = 0; - - poly = rb_debugPolygons; - for( i = 0; i < rb_numDebugPolygons; i++, poly++ ) - { - if( poly->lifeTime > time ) - { - if( num != i ) - { - rb_debugPolygons[ num ] = *poly; - } - num++; - } - } - rb_numDebugPolygons = num; -} - -/* -================ -RB_AddDebugPolygon -================ -*/ -void RB_AddDebugPolygon( const idVec4& color, const idWinding& winding, const int lifeTime, const bool depthTest ) -{ - debugPolygon_t* poly; - - if( rb_numDebugPolygons < MAX_DEBUG_POLYGONS ) - { - poly = &rb_debugPolygons[ rb_numDebugPolygons++ ]; - poly->rgb = color; - poly->winding = winding; - poly->depthTest = depthTest; - poly->lifeTime = rb_debugPolygonTime + lifeTime; - } -} - -/* -================ -RB_ShowDebugPolygons -================ -*/ -void RB_ShowDebugPolygons() -{ - int i, j; - debugPolygon_t* poly; - - if( !rb_numDebugPolygons ) - { - return; - } - - // all lines are expressed in world coordinates - RB_SimpleWorldSetup(); - - // RB begin - renderProgManager.BindShader_VertexColor(); - renderProgManager.CommitUniforms(); - // RB end - - globalImages->BindNull(); - - if( r_debugPolygonFilled.GetBool() ) - { - GL_State( GLS_POLYGON_OFFSET | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK ); - GL_PolygonOffset( -1, -2 ); - } - else - { - GL_State( GLS_POLYGON_OFFSET | GLS_POLYMODE_LINE ); - GL_PolygonOffset( -1, -2 ); - } - - poly = rb_debugPolygons; - for( i = 0; i < rb_numDebugPolygons; i++, poly++ ) - { -// if ( !poly->depthTest ) { - - glColor4fv( poly->rgb.ToFloatPtr() ); - - glBegin( GL_POLYGON ); - - for( j = 0; j < poly->winding.GetNumPoints(); j++ ) - { - glVertex3fv( poly->winding[j].ToFloatPtr() ); - } - - glEnd(); -// } - } - - GL_State( GLS_DEFAULT ); - - if( r_debugPolygonFilled.GetBool() ) - { - glDisable( GL_POLYGON_OFFSET_FILL ); - } - else - { - glDisable( GL_POLYGON_OFFSET_LINE ); - } - - GL_State( GLS_DEFAULT ); -} - -/* -================ -RB_ShowCenterOfProjection -================ -*/ -void RB_ShowCenterOfProjection() -{ - if( !r_showCenterOfProjection.GetBool() ) - { - return; - } - - const int w = backEnd.viewDef->scissor.GetWidth(); - const int h = backEnd.viewDef->scissor.GetHeight(); - glClearColor( 1, 0, 0, 1 ); - for( float f = 0.0f ; f <= 1.0f ; f += 0.125f ) - { - glScissor( w * f - 1 , 0, 3, h ); - glClear( GL_COLOR_BUFFER_BIT ); - glScissor( 0, h * f - 1 , w, 3 ); - glClear( GL_COLOR_BUFFER_BIT ); - } - glClearColor( 0, 1, 0, 1 ); - float f = 0.5f; - glScissor( w * f - 1 , 0, 3, h ); - glClear( GL_COLOR_BUFFER_BIT ); - glScissor( 0, h * f - 1 , w, 3 ); - glClear( GL_COLOR_BUFFER_BIT ); - - glScissor( 0, 0, w, h ); -} - -/* -================ -RB_ShowLines - -Draw exact pixel lines to check pixel center sampling -================ -*/ -void RB_ShowLines() -{ - if( !r_showLines.GetBool() ) - { - return; - } - - glEnable( GL_SCISSOR_TEST ); - if( backEnd.viewDef->renderView.viewEyeBuffer == 0 ) - { - glClearColor( 1, 0, 0, 1 ); - } - else if( backEnd.viewDef->renderView.viewEyeBuffer == 1 ) - { - glClearColor( 0, 1, 0, 1 ); - } - else - { - glClearColor( 0, 0, 1, 1 ); - } - - const int start = ( r_showLines.GetInteger() > 2 ); // 1,3 = horizontal, 2,4 = vertical - if( r_showLines.GetInteger() == 1 || r_showLines.GetInteger() == 3 ) - { - for( int i = start ; i < tr.GetHeight() ; i += 2 ) - { - glScissor( 0, i, tr.GetWidth(), 1 ); - glClear( GL_COLOR_BUFFER_BIT ); - } - } - else - { - for( int i = start ; i < tr.GetWidth() ; i += 2 ) - { - glScissor( i, 0, 1, tr.GetHeight() ); - glClear( GL_COLOR_BUFFER_BIT ); - } - } -} - - -/* -================ -RB_TestGamma -================ -*/ -#define G_WIDTH 512 -#define G_HEIGHT 512 -#define BAR_HEIGHT 64 - -void RB_TestGamma() -{ - byte image[G_HEIGHT][G_WIDTH][4]; - int i, j; - int c, comp; - int v, dither; - int mask, y; - - if( r_testGamma.GetInteger() <= 0 ) - { - return; - } - - v = r_testGamma.GetInteger(); - if( v <= 1 || v >= 196 ) - { - v = 128; - } - - memset( image, 0, sizeof( image ) ); - - for( mask = 0; mask < 8; mask++ ) - { - y = mask * BAR_HEIGHT; - for( c = 0; c < 4; c++ ) - { - v = c * 64 + 32; - // solid color - for( i = 0; i < BAR_HEIGHT / 2; i++ ) - { - for( j = 0; j < G_WIDTH / 4; j++ ) - { - for( comp = 0; comp < 3; comp++ ) - { - if( mask & ( 1 << comp ) ) - { - image[y + i][c * G_WIDTH / 4 + j][comp] = v; - } - } - } - // dithered color - for( j = 0; j < G_WIDTH / 4; j++ ) - { - if( ( i ^ j ) & 1 ) - { - dither = c * 64; - } - else - { - dither = c * 64 + 63; - } - for( comp = 0; comp < 3; comp++ ) - { - if( mask & ( 1 << comp ) ) - { - image[y + BAR_HEIGHT / 2 + i][c * G_WIDTH / 4 + j][comp] = dither; - } - } - } - } - } - } - - // draw geometrically increasing steps in the bottom row - y = 0 * BAR_HEIGHT; - float scale = 1; - for( c = 0; c < 4; c++ ) - { - v = ( int )( 64 * scale ); - if( v < 0 ) - { - v = 0; - } - else if( v > 255 ) - { - v = 255; - } - scale = scale * 1.5; - for( i = 0; i < BAR_HEIGHT; i++ ) - { - for( j = 0; j < G_WIDTH / 4; j++ ) - { - image[y + i][c * G_WIDTH / 4 + j][0] = v; - image[y + i][c * G_WIDTH / 4 + j][1] = v; - image[y + i][c * G_WIDTH / 4 + j][2] = v; - } - } - } - - glLoadIdentity(); - - glMatrixMode( GL_PROJECTION ); - GL_State( GLS_DEPTHFUNC_ALWAYS ); - GL_Color( 1, 1, 1 ); - glPushMatrix(); - glLoadIdentity(); - glDisable( GL_TEXTURE_2D ); - glOrtho( 0, 1, 0, 1, -1, 1 ); - glRasterPos2f( 0.01f, 0.01f ); - glDrawPixels( G_WIDTH, G_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, image ); - glPopMatrix(); - glEnable( GL_TEXTURE_2D ); - glMatrixMode( GL_MODELVIEW ); -} - - -/* -================== -RB_TestGammaBias -================== -*/ -static void RB_TestGammaBias() -{ - byte image[G_HEIGHT][G_WIDTH][4]; - - if( r_testGammaBias.GetInteger() <= 0 ) - { - return; - } - - int y = 0; - for( int bias = -40; bias < 40; bias += 10, y += BAR_HEIGHT ) - { - float scale = 1; - for( int c = 0; c < 4; c++ ) - { - int v = ( int )( 64 * scale + bias ); - scale = scale * 1.5; - if( v < 0 ) - { - v = 0; - } - else if( v > 255 ) - { - v = 255; - } - for( int i = 0; i < BAR_HEIGHT; i++ ) - { - for( int j = 0; j < G_WIDTH / 4; j++ ) - { - image[y + i][c * G_WIDTH / 4 + j][0] = v; - image[y + i][c * G_WIDTH / 4 + j][1] = v; - image[y + i][c * G_WIDTH / 4 + j][2] = v; - } - } - } - } - - glLoadIdentity(); - glMatrixMode( GL_PROJECTION ); - GL_State( GLS_DEPTHFUNC_ALWAYS ); - GL_Color( 1, 1, 1 ); - glPushMatrix(); - glLoadIdentity(); - glDisable( GL_TEXTURE_2D ); - glOrtho( 0, 1, 0, 1, -1, 1 ); - glRasterPos2f( 0.01f, 0.01f ); - glDrawPixels( G_WIDTH, G_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, image ); - glPopMatrix(); - glEnable( GL_TEXTURE_2D ); - glMatrixMode( GL_MODELVIEW ); -} - -/* -================ -RB_TestImage - -Display a single image over most of the screen -================ -*/ -void RB_TestImage() -{ - idImage* image = NULL; - idImage* imageCr = NULL; - idImage* imageCb = NULL; - int max; - float w, h; - - image = tr.testImage; - if( !image ) - { - return; - } - - if( tr.testVideo ) - { - cinData_t cin; - - cin = tr.testVideo->ImageForTime( backEnd.viewDef->renderView.time[1] - tr.testVideoStartTime ); - if( cin.imageY != NULL ) - { - image = cin.imageY; - imageCr = cin.imageCr; - imageCb = cin.imageCb; - } - else - { - tr.testImage = NULL; - return; - } - w = 0.25; - h = 0.25; - } - else - { - max = image->GetUploadWidth() > image->GetUploadHeight() ? image->GetUploadWidth() : image->GetUploadHeight(); - - w = 0.25 * image->GetUploadWidth() / max; - h = 0.25 * image->GetUploadHeight() / max; - - w *= ( float )renderSystem->GetHeight() / renderSystem->GetWidth(); - } - - // Set State - GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - - // Set Parms - float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; - float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f }; - renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_S, texS ); - renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_T, texT ); - - float texGenEnabled[4] = { 0, 0, 0, 0 }; - renderProgManager.SetRenderParm( RENDERPARM_TEXGEN_0_ENABLED, texGenEnabled ); - - // not really necessary but just for clarity - const float screenWidth = 1.0f; - const float screenHeight = 1.0f; - const float halfScreenWidth = screenWidth * 0.5f; - const float halfScreenHeight = screenHeight * 0.5f; - - float scale[16] = { 0 }; - scale[0] = w; // scale - scale[5] = h; // scale - scale[12] = halfScreenWidth - ( halfScreenWidth * w ); // translate - scale[13] = halfScreenHeight - ( halfScreenHeight * h ); // translate - scale[10] = 1.0f; - scale[15] = 1.0f; - - float ortho[16] = { 0 }; - ortho[0] = 2.0f / screenWidth; - ortho[5] = -2.0f / screenHeight; - ortho[10] = -2.0f; - ortho[12] = -1.0f; - ortho[13] = 1.0f; - ortho[14] = -1.0f; - ortho[15] = 1.0f; - - float finalOrtho[16]; - R_MatrixMultiply( scale, ortho, finalOrtho ); - - float projMatrixTranspose[16]; - R_MatrixTranspose( finalOrtho, projMatrixTranspose ); - renderProgManager.SetRenderParms( RENDERPARM_MVPMATRIX_X, projMatrixTranspose, 4 ); - -// glMatrixMode( GL_PROJECTION ); -// glLoadMatrixf( finalOrtho ); -// glMatrixMode( GL_MODELVIEW ); -// glLoadIdentity(); - - // Set Color - GL_Color( 1, 1, 1, 1 ); - - // Bind the Texture - if( ( imageCr != NULL ) && ( imageCb != NULL ) ) - { - GL_SelectTexture( 0 ); - image->Bind(); - GL_SelectTexture( 1 ); - imageCr->Bind(); - GL_SelectTexture( 2 ); - imageCb->Bind(); - renderProgManager.BindShader_Bink(); - } - else - { - GL_SelectTexture( 0 ); - image->Bind(); - // Set Shader - renderProgManager.BindShader_Texture(); - } - - // Draw! - RB_DrawElementsWithCounters( &backEnd.testImageSurface ); -} - -// RB begin -void RB_ShowShadowMaps() -{ - idImage* image = NULL; - int max; - float w, h; - - if( !r_showShadowMaps.GetBool() ) - return; - - image = globalImages->shadowImage[0]; - if( !image ) - { - return; - } - - // Set State - GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - - // Set Parms - float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; - float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f }; - renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_S, texS ); - renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_T, texT ); - - float texGenEnabled[4] = { 0, 0, 0, 0 }; - renderProgManager.SetRenderParm( RENDERPARM_TEXGEN_0_ENABLED, texGenEnabled ); - - for( int i = 0; i < ( r_shadowMapSplits.GetInteger() + 1 ); i++ ) - { - max = image->GetUploadWidth() > image->GetUploadHeight() ? image->GetUploadWidth() : image->GetUploadHeight(); - - w = 0.25 * image->GetUploadWidth() / max; - h = 0.25 * image->GetUploadHeight() / max; - - w *= ( float )renderSystem->GetHeight() / renderSystem->GetWidth(); - - // not really necessary but just for clarity - const float screenWidth = 1.0f; - const float screenHeight = 1.0f; - const float halfScreenWidth = screenWidth * 0.5f; - const float halfScreenHeight = screenHeight * 0.5f; - - float scale[16] = { 0 }; - scale[0] = w; // scale - scale[5] = h; // scale - scale[12] = ( halfScreenWidth * w * 2.1f * i ); // translate - scale[13] = halfScreenHeight + ( halfScreenHeight * h ); // translate - scale[10] = 1.0f; - scale[15] = 1.0f; - - float ortho[16] = { 0 }; - ortho[0] = 2.0f / screenWidth; - ortho[5] = -2.0f / screenHeight; - ortho[10] = -2.0f; - ortho[12] = -1.0f; - ortho[13] = 1.0f; - ortho[14] = -1.0f; - ortho[15] = 1.0f; - - float finalOrtho[16]; - R_MatrixMultiply( scale, ortho, finalOrtho ); - - float projMatrixTranspose[16]; - R_MatrixTranspose( finalOrtho, projMatrixTranspose ); - renderProgManager.SetRenderParms( RENDERPARM_MVPMATRIX_X, projMatrixTranspose, 4 ); - - float screenCorrectionParm[4]; - screenCorrectionParm[0] = i; - screenCorrectionParm[1] = 0.0f; - screenCorrectionParm[2] = 0.0f; - screenCorrectionParm[3] = 1.0f; - renderProgManager.SetRenderParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor - - // glMatrixMode( GL_PROJECTION ); - // glLoadMatrixf( finalOrtho ); - // glMatrixMode( GL_MODELVIEW ); - // glLoadIdentity(); - - // Set Color - GL_Color( 1, 1, 1, 1 ); - - GL_SelectTexture( 0 ); - image->Bind(); - glTexParameteri( GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_NONE ); - - - renderProgManager.BindShader_DebugShadowMap(); - - RB_DrawElementsWithCounters( &backEnd.testImageSurface ); - } - - glTexParameteri( GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE ); -} -// RB end - -/* -================= -RB_DrawExpandedTriangles -================= -*/ -void RB_DrawExpandedTriangles( const srfTriangles_t* tri, const float radius, const idVec3& vieworg ) -{ - int i, j, k; - idVec3 dir[6], normal, point; - - for( i = 0; i < tri->numIndexes; i += 3 ) - { - - idVec3 p[3] = { tri->verts[ tri->indexes[ i + 0 ] ].xyz, tri->verts[ tri->indexes[ i + 1 ] ].xyz, tri->verts[ tri->indexes[ i + 2 ] ].xyz }; - - dir[0] = p[0] - p[1]; - dir[1] = p[1] - p[2]; - dir[2] = p[2] - p[0]; - - normal = dir[0].Cross( dir[1] ); - - if( normal * p[0] < normal * vieworg ) - { - continue; - } - - dir[0] = normal.Cross( dir[0] ); - dir[1] = normal.Cross( dir[1] ); - dir[2] = normal.Cross( dir[2] ); - - dir[0].Normalize(); - dir[1].Normalize(); - dir[2].Normalize(); - - glBegin( GL_LINE_LOOP ); - - for( j = 0; j < 3; j++ ) - { - k = ( j + 1 ) % 3; - - dir[4] = ( dir[j] + dir[k] ) * 0.5f; - dir[4].Normalize(); - - dir[3] = ( dir[j] + dir[4] ) * 0.5f; - dir[3].Normalize(); - - dir[5] = ( dir[4] + dir[k] ) * 0.5f; - dir[5].Normalize(); - - point = p[k] + dir[j] * radius; - glVertex3f( point[0], point[1], point[2] ); - - point = p[k] + dir[3] * radius; - glVertex3f( point[0], point[1], point[2] ); - - point = p[k] + dir[4] * radius; - glVertex3f( point[0], point[1], point[2] ); - - point = p[k] + dir[5] * radius; - glVertex3f( point[0], point[1], point[2] ); - - point = p[k] + dir[k] * radius; - glVertex3f( point[0], point[1], point[2] ); - } - - glEnd(); - } -} - -/* -================ -RB_ShowTrace - -Debug visualization - -FIXME: not thread safe! -================ -*/ -void RB_ShowTrace( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - int i; - const srfTriangles_t* tri; - const drawSurf_t* surf; - idVec3 start, end; - idVec3 localStart, localEnd; - localTrace_t hit; - float radius; - - if( r_showTrace.GetInteger() == 0 ) - { - return; - } - - if( r_showTrace.GetInteger() == 2 ) - { - radius = 5.0f; - } - else - { - radius = 0.0f; - } - - // determine the points of the trace - start = backEnd.viewDef->renderView.vieworg; - end = start + 4000 * backEnd.viewDef->renderView.viewaxis[0]; - - // check and draw the surfaces - globalImages->whiteImage->Bind(); - - // find how many are ambient - for( i = 0; i < numDrawSurfs; i++ ) - { - surf = drawSurfs[i]; - tri = surf->frontEndGeo; - - if( tri == NULL || tri->verts == NULL ) - { - continue; - } - - // transform the points into local space - R_GlobalPointToLocal( surf->space->modelMatrix, start, localStart ); - R_GlobalPointToLocal( surf->space->modelMatrix, end, localEnd ); - - // check the bounding box - if( !tri->bounds.Expand( radius ).LineIntersection( localStart, localEnd ) ) - { - continue; - } - - glLoadMatrixf( surf->space->modelViewMatrix ); - - // highlight the surface - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - - GL_Color( 1, 0, 0, 0.25 ); - RB_DrawElementsWithCounters( surf ); - - // draw the bounding box - GL_State( GLS_DEPTHFUNC_ALWAYS ); - - GL_Color( 1, 1, 1, 1 ); - RB_DrawBounds( tri->bounds ); - - if( radius != 0.0f ) - { - // draw the expanded triangles - GL_Color( 0.5f, 0.5f, 1.0f, 1.0f ); - RB_DrawExpandedTriangles( tri, radius, localStart ); - } - - // check the exact surfaces - hit = R_LocalTrace( localStart, localEnd, radius, tri ); - if( hit.fraction < 1.0 ) - { - GL_Color( 1, 1, 1, 1 ); - RB_DrawBounds( idBounds( hit.point ).Expand( 1 ) ); - } - } -} - -/* -================= -RB_RenderDebugTools -================= -*/ -void RB_RenderDebugTools( drawSurf_t** drawSurfs, int numDrawSurfs ) -{ - // don't do much if this was a 2D rendering - if( !backEnd.viewDef->viewEntitys ) - { - RB_TestImage(); - RB_ShowLines(); - return; - } - - renderLog.OpenMainBlock( MRB_DRAW_DEBUG_TOOLS ); - RENDERLOG_PRINTF( "---------- RB_RenderDebugTools ----------\n" ); - - GL_State( GLS_DEFAULT ); - - GL_Scissor( backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1, - backEnd.viewDef->scissor.x2 + 1 - backEnd.viewDef->scissor.x1, - backEnd.viewDef->scissor.y2 + 1 - backEnd.viewDef->scissor.y1 ); - backEnd.currentScissor = backEnd.viewDef->scissor; - - RB_ShowLightCount(); - RB_ShowTexturePolarity( drawSurfs, numDrawSurfs ); - RB_ShowTangentSpace( drawSurfs, numDrawSurfs ); - RB_ShowVertexColor( drawSurfs, numDrawSurfs ); - RB_ShowTris( drawSurfs, numDrawSurfs ); - RB_ShowUnsmoothedTangents( drawSurfs, numDrawSurfs ); - RB_ShowSurfaceInfo( drawSurfs, numDrawSurfs ); - RB_ShowEdges( drawSurfs, numDrawSurfs ); - RB_ShowNormals( drawSurfs, numDrawSurfs ); - RB_ShowViewEntitys( backEnd.viewDef->viewEntitys ); - RB_ShowLights(); - // RB begin - RB_ShowShadowMapLODs(); - RB_ShowShadowMaps(); - // RB end - - RB_ShowTextureVectors( drawSurfs, numDrawSurfs ); - RB_ShowDominantTris( drawSurfs, numDrawSurfs ); - if( r_testGamma.GetInteger() > 0 ) // test here so stack check isn't so damn slow on debug builds - { - RB_TestGamma(); - } - if( r_testGammaBias.GetInteger() > 0 ) - { - RB_TestGammaBias(); - } - RB_TestImage(); - RB_ShowPortals(); - RB_ShowSilhouette(); - RB_ShowDepthBuffer(); - RB_ShowIntensity(); - RB_ShowCenterOfProjection(); - RB_ShowLines(); - RB_ShowDebugLines(); - RB_ShowDebugText(); - RB_ShowDebugPolygons(); - RB_ShowTrace( drawSurfs, numDrawSurfs ); - - renderLog.CloseMainBlock(); -} - -/* -================= -RB_ShutdownDebugTools -================= -*/ -void RB_ShutdownDebugTools() -{ - for( int i = 0; i < MAX_DEBUG_POLYGONS; i++ ) - { - rb_debugPolygons[i].winding.Clear(); - } -} diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_addlights.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_addlights.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_addlights.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_addlights.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" extern idCVar r_useAreasConnectedForShadowCulling; extern idCVar r_useParallelAddShadows; @@ -673,7 +673,7 @@ } int end = Sys_Microseconds(); - backEnd.pc.shadowMicroSec += end - start; + tr.backend.pc.shadowMicroSec += end - start; } } diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_addmodels.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_addmodels.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_addmodels.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_addmodels.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" idCVar r_skipStaticShadows( "r_skipStaticShadows", "0", CVAR_RENDERER | CVAR_BOOL, "skip static shadows" ); @@ -1402,7 +1402,7 @@ } int end = Sys_Microseconds(); - backEnd.pc.shadowMicroSec += end - start; + tr.backend.pc.shadowMicroSec += end - start; } } diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_deform.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_deform.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_deform.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_deform.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" /* diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_guisurf.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_guisurf.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_guisurf.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_guisurf.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" /* diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_main.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_main.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_main.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_main.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" /* ========================================================================================== diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_subview.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_subview.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_frontend_subview.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_frontend_subview.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" /* diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_local.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_local.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_local.h 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_local.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1545 +0,0 @@ -/* -=========================================================================== - -Doom 3 BFG Edition GPL Source Code -Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. -Copyright (C) 2012-2016 Robert Beckebans -Copyright (C) 2014-2016 Kot in Action Creative Artel - -This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). - -Doom 3 BFG Edition Source Code 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. - -Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see . - -In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __TR_LOCAL_H__ -#define __TR_LOCAL_H__ - -#include "precompiled.h" - -#include "GLState.h" -#include "ScreenRect.h" -#include "ImageOpts.h" -#include "Image.h" -#include "Font.h" -#include "Framebuffer.h" - -// everything that is needed by the backend needs -// to be double buffered to allow it to run in -// parallel on a dual cpu machine -const int SMP_FRAMES = 1; - -// maximum texture units -const int MAX_PROG_TEXTURE_PARMS = 16; - -const int FALLOFF_TEXTURE_SIZE = 64; - -const float DEFAULT_FOG_DISTANCE = 500.0f; - -// picky to get the bilerp correct at terminator -const int FOG_ENTER_SIZE = 64; -const float FOG_ENTER = ( FOG_ENTER_SIZE + 1.0f ) / ( FOG_ENTER_SIZE * 2 ); - -enum demoCommand_t -{ - DC_BAD, - DC_RENDERVIEW, - DC_UPDATE_ENTITYDEF, - DC_DELETE_ENTITYDEF, - DC_UPDATE_LIGHTDEF, - DC_DELETE_LIGHTDEF, - DC_LOADMAP, - DC_CROP_RENDER, - DC_UNCROP_RENDER, - DC_CAPTURE_RENDER, - DC_END_FRAME, - DC_DEFINE_MODEL, - DC_SET_PORTAL_STATE, - DC_UPDATE_SOUNDOCCLUSION, - DC_GUI_MODEL, - DC_UPDATE_DECAL, - DC_DELETE_DECAL, - DC_UPDATE_OVERLAY, - DC_DELETE_OVERLAY, - DC_CACHE_SKINS, - DC_CACHE_PARTICLES, - DC_CACHE_MATERIALS, -}; - -/* -============================================================================== - -SURFACES - -============================================================================== -*/ - -#include "ModelDecal.h" -#include "ModelOverlay.h" -#include "Interaction.h" - -class idRenderWorldLocal; -struct viewEntity_t; -struct viewLight_t; - -// drawSurf_t structures command the back end to render surfaces -// a given srfTriangles_t may be used with multiple viewEntity_t, -// as when viewed in a subview or multiple viewport render, or -// with multiple shaders when skinned, or, possibly with multiple -// lights, although currently each lighting interaction creates -// unique srfTriangles_t -// drawSurf_t are always allocated and freed every frame, they are never cached - -struct drawSurf_t -{ - const srfTriangles_t* frontEndGeo; // don't use on the back end, it may be updated by the front end! - int numIndexes; - vertCacheHandle_t indexCache; // triIndex_t - vertCacheHandle_t ambientCache; // idDrawVert - vertCacheHandle_t shadowCache; // idShadowVert / idShadowVertSkinned - vertCacheHandle_t jointCache; // idJointMat - const viewEntity_t* space; - const idMaterial* material; // may be NULL for shadow volumes - uint64 extraGLState; // Extra GL state |'d with material->stage[].drawStateBits - float sort; // material->sort, modified by gui / entity sort offsets - const float* shaderRegisters; // evaluated and adjusted for referenceShaders - drawSurf_t* nextOnLight; // viewLight chains - drawSurf_t** linkChain; // defer linking to lights to a serial section to avoid a mutex - idScreenRect scissorRect; // for scissor clipping, local inside renderView viewport - int renderZFail; - volatile shadowVolumeState_t shadowVolumeState; -}; - -// areas have references to hold all the lights and entities in them -struct areaReference_t -{ - areaReference_t* areaNext; // chain in the area - areaReference_t* areaPrev; - areaReference_t* ownerNext; // chain on either the entityDef or lightDef - idRenderEntityLocal* entity; // only one of entity / light will be non-NULL - idRenderLightLocal* light; // only one of entity / light will be non-NULL - struct portalArea_s* area; // so owners can find all the areas they are in -}; - - -// idRenderLight should become the new public interface replacing the qhandle_t to light defs in the idRenderWorld interface -class idRenderLight -{ -public: - virtual ~idRenderLight() {} - - virtual void FreeRenderLight() = 0; - virtual void UpdateRenderLight( const renderLight_t* re, bool forceUpdate = false ) = 0; - virtual void GetRenderLight( renderLight_t* re ) = 0; - virtual void ForceUpdate() = 0; - virtual int GetIndex() = 0; -}; - - -// idRenderEntity should become the new public interface replacing the qhandle_t to entity defs in the idRenderWorld interface -class idRenderEntity -{ -public: - virtual ~idRenderEntity() {} - - virtual void FreeRenderEntity() = 0; - virtual void UpdateRenderEntity( const renderEntity_t* re, bool forceUpdate = false ) = 0; - virtual void GetRenderEntity( renderEntity_t* re ) = 0; - virtual void ForceUpdate() = 0; - virtual int GetIndex() = 0; - - // overlays are extra polygons that deform with animating models for blood and damage marks - virtual void ProjectOverlay( const idPlane localTextureAxis[2], const idMaterial* material ) = 0; - virtual void RemoveDecals() = 0; -}; - - -class idRenderLightLocal : public idRenderLight -{ -public: - idRenderLightLocal(); - - virtual void FreeRenderLight(); - virtual void UpdateRenderLight( const renderLight_t* re, bool forceUpdate = false ); - virtual void GetRenderLight( renderLight_t* re ); - virtual void ForceUpdate(); - virtual int GetIndex(); - - bool LightCastsShadows() const - { - return parms.forceShadows || ( !parms.noShadows && lightShader->LightCastsShadows() ); - } - - renderLight_t parms; // specification - - bool lightHasMoved; // the light has changed its position since it was - // first added, so the prelight model is not valid - idRenderWorldLocal* world; - int index; // in world lightdefs - - int areaNum; // if not -1, we may be able to cull all the light's - // interactions if !viewDef->connectedAreas[areaNum] - - int lastModifiedFrameNum; // to determine if it is constantly changing, - // and should go in the dynamic frame memory, or kept - // in the cached memory - bool archived; // for demo writing - - - // derived information - idPlane lightProject[4]; // old style light projection where Z and W are flipped and projected lights lightProject[3] is divided by ( zNear + zFar ) - idRenderMatrix baseLightProject; // global xyz1 to projected light strq - idRenderMatrix inverseBaseLightProject;// transforms the zero-to-one cube to exactly cover the light in world space - - const idMaterial* lightShader; // guaranteed to be valid, even if parms.shader isn't - idImage* falloffImage; - - idVec3 globalLightOrigin; // accounting for lightCenter and parallel - idBounds globalLightBounds; - - int viewCount; // if == tr.viewCount, the light is on the viewDef->viewLights list - viewLight_t* viewLight; - - areaReference_t* references; // each area the light is present in will have a lightRef - idInteraction* firstInteraction; // doubly linked list - idInteraction* lastInteraction; - - struct doublePortal_s* foggedPortals; -}; - - -class idRenderEntityLocal : public idRenderEntity -{ -public: - idRenderEntityLocal(); - - virtual void FreeRenderEntity(); - virtual void UpdateRenderEntity( const renderEntity_t* re, bool forceUpdate = false ); - virtual void GetRenderEntity( renderEntity_t* re ); - virtual void ForceUpdate(); - virtual int GetIndex(); - - // overlays are extra polygons that deform with animating models for blood and damage marks - virtual void ProjectOverlay( const idPlane localTextureAxis[2], const idMaterial* material ); - virtual void RemoveDecals(); - - bool IsDirectlyVisible() const; - void ReadFromDemoFile( class idDemoFile* f ); - void WriteToDemoFile( class idDemoFile* f ) const; - renderEntity_t parms; - - float modelMatrix[16]; // this is just a rearrangement of parms.axis and parms.origin - idRenderMatrix modelRenderMatrix; - idRenderMatrix inverseBaseModelProject;// transforms the unit cube to exactly cover the model in world space - - idRenderWorldLocal* world; - int index; // in world entityDefs - - int lastModifiedFrameNum; // to determine if it is constantly changing, - // and should go in the dynamic frame memory, or kept - // in the cached memory - bool archived; // for demo writing - - idRenderModel* dynamicModel; // if parms.model->IsDynamicModel(), this is the generated data - int dynamicModelFrameCount; // continuously animating dynamic models will recreate - // dynamicModel if this doesn't == tr.viewCount - idRenderModel* cachedDynamicModel; - - - // the local bounds used to place entityRefs, either from parms for dynamic entities, or a model bounds - idBounds localReferenceBounds; - - // axis aligned bounding box in world space, derived from refernceBounds and - // modelMatrix in R_CreateEntityRefs() - idBounds globalReferenceBounds; - - // a viewEntity_t is created whenever a idRenderEntityLocal is considered for inclusion - // in a given view, even if it turns out to not be visible - int viewCount; // if tr.viewCount == viewCount, viewEntity is valid, - // but the entity may still be off screen - viewEntity_t* viewEntity; // in frame temporary memory - - idRenderModelDecal* decals; // decals that have been projected on this model - idRenderModelOverlay* overlays; // blood overlays on animated models - - areaReference_t* entityRefs; // chain of all references - idInteraction* firstInteraction; // doubly linked list - idInteraction* lastInteraction; - - bool needsPortalSky; -}; - -struct shadowOnlyEntity_t -{ - shadowOnlyEntity_t* next; - idRenderEntityLocal* edef; -}; - -// viewLights are allocated on the frame temporary stack memory -// a viewLight contains everything that the back end needs out of an idRenderLightLocal, -// which the front end may be modifying simultaniously if running in SMP mode. -// a viewLight may exist even without any surfaces, and may be relevent for fogging, -// but should never exist if its volume does not intersect the view frustum -struct viewLight_t -{ - viewLight_t* next; - - // back end should NOT reference the lightDef, because it can change when running SMP - idRenderLightLocal* lightDef; - - // for scissor clipping, local inside renderView viewport - // scissorRect.Empty() is true if the viewEntity_t was never actually - // seen through any portals - idScreenRect scissorRect; - - // R_AddSingleLight() determined that the light isn't actually needed - bool removeFromList; - - // R_AddSingleLight builds this list of entities that need to be added - // to the viewEntities list because they potentially cast shadows into - // the view, even though the aren't directly visible - shadowOnlyEntity_t* shadowOnlyViewEntities; - - enum interactionState_t - { - INTERACTION_UNCHECKED, - INTERACTION_NO, - INTERACTION_YES - }; - byte* entityInteractionState; // [numEntities] - - idVec3 globalLightOrigin; // global light origin used by backend - idPlane lightProject[4]; // light project used by backend - idPlane fogPlane; // fog plane for backend fog volume rendering - // RB: added for shadow mapping - idRenderMatrix baseLightProject; // global xyz1 to projected light strq - bool pointLight; // otherwise a projection light (should probably invert the sense of this, because points are way more common) - bool parallel; // lightCenter gives the direction to the light at infinity - idVec3 lightCenter; // offset the lighting direction for shading and - int shadowLOD; // level of detail for shadowmap selection - // RB end - idRenderMatrix inverseBaseLightProject; // the matrix for deforming the 'zeroOneCubeModel' to exactly cover the light volume in world space - const idMaterial* lightShader; // light shader used by backend - const float* shaderRegisters; // shader registers used by backend - idImage* falloffImage; // falloff image used by backend - - drawSurf_t* globalShadows; // shadow everything - drawSurf_t* localInteractions; // don't get local shadows - drawSurf_t* localShadows; // don't shadow local surfaces - drawSurf_t* globalInteractions; // get shadows from everything - drawSurf_t* translucentInteractions; // translucent interactions don't get shadows - - // R_AddSingleLight will build a chain of parameters here to setup shadow volumes - preLightShadowVolumeParms_t* preLightShadowVolumes; -}; - -// a viewEntity is created whenever a idRenderEntityLocal is considered for inclusion -// in the current view, but it may still turn out to be culled. -// viewEntity are allocated on the frame temporary stack memory -// a viewEntity contains everything that the back end needs out of a idRenderEntityLocal, -// which the front end may be modifying simultaneously if running in SMP mode. -// A single entityDef can generate multiple viewEntity_t in a single frame, as when seen in a mirror -struct viewEntity_t -{ - viewEntity_t* next; - - // back end should NOT reference the entityDef, because it can change when running SMP - idRenderEntityLocal* entityDef; - - // for scissor clipping, local inside renderView viewport - // scissorRect.Empty() is true if the viewEntity_t was never actually - // seen through any portals, but was created for shadow casting. - // a viewEntity can have a non-empty scissorRect, meaning that an area - // that it is in is visible, and still not be visible. - idScreenRect scissorRect; - - bool isGuiSurface; // force two sided and vertex colors regardless of material setting - - bool skipMotionBlur; - - bool weaponDepthHack; - float modelDepthHack; - - float modelMatrix[16]; // local coords to global coords - float modelViewMatrix[16]; // local coords to eye coords - - idRenderMatrix mvp; - - // parallelAddModels will build a chain of surfaces here that will need to - // be linked to the lights or added to the drawsurf list in a serial code section - drawSurf_t* drawSurfs; - - // R_AddSingleModel will build a chain of parameters here to setup shadow volumes - staticShadowVolumeParms_t* staticShadowVolumes; - dynamicShadowVolumeParms_t* dynamicShadowVolumes; -}; - - -const int MAX_CLIP_PLANES = 1; // we may expand this to six for some subview issues - -// RB: added multiple subfrustums for cascaded shadow mapping -enum frustumPlanes_t -{ - FRUSTUM_PLANE_LEFT, - FRUSTUM_PLANE_RIGHT, - FRUSTUM_PLANE_BOTTOM, - FRUSTUM_PLANE_TOP, - FRUSTUM_PLANE_NEAR, - FRUSTUM_PLANE_FAR, - FRUSTUM_PLANES = 6, - FRUSTUM_CLIPALL = 1 | 2 | 4 | 8 | 16 | 32 -}; - -enum -{ - FRUSTUM_PRIMARY, - FRUSTUM_CASCADE1, - FRUSTUM_CASCADE2, - FRUSTUM_CASCADE3, - FRUSTUM_CASCADE4, - FRUSTUM_CASCADE5, - MAX_FRUSTUMS, -}; - -typedef idPlane frustum_t[FRUSTUM_PLANES]; -// RB end - -// viewDefs are allocated on the frame temporary stack memory -struct viewDef_t -{ - // specified in the call to DrawScene() - renderView_t renderView; - - float projectionMatrix[16]; - idRenderMatrix projectionRenderMatrix; // tech5 version of projectionMatrix - - // RB begin - float unprojectionToCameraMatrix[16]; - idRenderMatrix unprojectionToCameraRenderMatrix; - - float unprojectionToWorldMatrix[16]; - idRenderMatrix unprojectionToWorldRenderMatrix; - // RB end - - viewEntity_t worldSpace; - - idRenderWorldLocal* renderWorld; - - idVec3 initialViewAreaOrigin; - // Used to find the portalArea that view flooding will take place from. - // for a normal view, the initialViewOrigin will be renderView.viewOrg, - // but a mirror may put the projection origin outside - // of any valid area, or in an unconnected area of the map, so the view - // area must be based on a point just off the surface of the mirror / subview. - // It may be possible to get a failed portal pass if the plane of the - // mirror intersects a portal, and the initialViewAreaOrigin is on - // a different side than the renderView.viewOrg is. - - bool isSubview; // true if this view is not the main view - bool isMirror; // the portal is a mirror, invert the face culling - bool isXraySubview; - - bool isEditor; - bool is2Dgui; - - int numClipPlanes; // mirrors will often use a single clip plane - idPlane clipPlanes[MAX_CLIP_PLANES]; // in world space, the positive side - // of the plane is the visible side - idScreenRect viewport; // in real pixels and proper Y flip - - idScreenRect scissor; - // for scissor clipping, local inside renderView viewport - // subviews may only be rendering part of the main view - // these are real physical pixel values, possibly scaled and offset from the - // renderView x/y/width/height - - viewDef_t* superView; // never go into an infinite subview loop - const drawSurf_t* subviewSurface; - - // drawSurfs are the visible surfaces of the viewEntities, sorted - // by the material sort parameter - drawSurf_t** drawSurfs; // we don't use an idList for this, because - int numDrawSurfs; // it is allocated in frame temporary memory - int maxDrawSurfs; // may be resized - - viewLight_t* viewLights; // chain of all viewLights effecting view - viewEntity_t* viewEntitys; // chain of all viewEntities effecting view, including off screen ones casting shadows - // we use viewEntities as a check to see if a given view consists solely - // of 2D rendering, which we can optimize in certain ways. A 2D view will - // not have any viewEntities - - // RB begin - frustum_t frustums[MAX_FRUSTUMS]; // positive sides face outward, [4] is the front clip plane - float frustumSplitDistances[MAX_FRUSTUMS]; - idRenderMatrix frustumMVPs[MAX_FRUSTUMS]; - // RB end - - int areaNum; // -1 = not in a valid area - - // An array in frame temporary memory that lists if an area can be reached without - // crossing a closed door. This is used to avoid drawing interactions - // when the light is behind a closed door. - bool* connectedAreas; -}; - - -// complex light / surface interactions are broken up into multiple passes of a -// simple interaction shader -struct drawInteraction_t -{ - const drawSurf_t* surf; - - idImage* bumpImage; - idImage* diffuseImage; - idImage* specularImage; - - idVec4 diffuseColor; // may have a light color baked into it - idVec4 specularColor; // may have a light color baked into it - stageVertexColor_t vertexColor; // applies to both diffuse and specular - - int ambientLight; // use tr.ambientNormalMap instead of normalization cube map - - // these are loaded into the vertex program - idVec4 bumpMatrix[2]; - idVec4 diffuseMatrix[2]; - idVec4 specularMatrix[2]; -}; - -/* -============================================================= - -RENDERER BACK END COMMAND QUEUE - -TR_CMDS - -============================================================= -*/ - -enum renderCommand_t -{ - RC_NOP, - RC_DRAW_VIEW_3D, // may be at a reduced resolution, will be upsampled before 2D GUIs - RC_DRAW_VIEW_GUI, // not resolution scaled - RC_SET_BUFFER, - RC_COPY_RENDER, - RC_POST_PROCESS, -}; - -struct emptyCommand_t -{ - renderCommand_t commandId; - renderCommand_t* next; -}; - -struct setBufferCommand_t -{ - renderCommand_t commandId; - renderCommand_t* next; - GLenum buffer; -}; - -struct drawSurfsCommand_t -{ - renderCommand_t commandId; - renderCommand_t* next; - viewDef_t* viewDef; -}; - -struct copyRenderCommand_t -{ - renderCommand_t commandId; - renderCommand_t* next; - int x; - int y; - int imageWidth; - int imageHeight; - idImage* image; - int cubeFace; // when copying to a cubeMap - bool clearColorAfterCopy; -}; - -struct postProcessCommand_t -{ - renderCommand_t commandId; - renderCommand_t* next; - viewDef_t* viewDef; -}; - -//======================================================================= - -// this is the inital allocation for max number of drawsurfs -// in a given view, but it will automatically grow if needed -const int INITIAL_DRAWSURFS = 2048; - -enum frameAllocType_t -{ - FRAME_ALLOC_VIEW_DEF, - FRAME_ALLOC_VIEW_ENTITY, - FRAME_ALLOC_VIEW_LIGHT, - FRAME_ALLOC_SURFACE_TRIANGLES, - FRAME_ALLOC_DRAW_SURFACE, - FRAME_ALLOC_INTERACTION_STATE, - FRAME_ALLOC_SHADOW_ONLY_ENTITY, - FRAME_ALLOC_SHADOW_VOLUME_PARMS, - FRAME_ALLOC_SHADER_REGISTER, - FRAME_ALLOC_DRAW_SURFACE_POINTER, - FRAME_ALLOC_DRAW_COMMAND, - FRAME_ALLOC_UNKNOWN, - FRAME_ALLOC_MAX -}; - -// all of the information needed by the back end must be -// contained in a idFrameData. This entire structure is -// duplicated so the front and back end can run in parallel -// on an SMP machine. -class idFrameData -{ -public: - idSysInterlockedInteger frameMemoryAllocated; - idSysInterlockedInteger frameMemoryUsed; - byte* frameMemory; - - int highWaterAllocated; // max used on any frame - int highWaterUsed; - - // the currently building command list commands can be inserted - // at the front if needed, as required for dynamically generated textures - emptyCommand_t* cmdHead; // may be of other command type based on commandId - emptyCommand_t* cmdTail; -}; - -extern idFrameData* frameData; - -//======================================================================= - -void R_AddDrawViewCmd( viewDef_t* parms, bool guiOnly ); -void R_AddDrawPostProcess( viewDef_t* parms ); - -void R_ReloadGuis_f( const idCmdArgs& args ); -void R_ListGuis_f( const idCmdArgs& args ); - -void* R_GetCommandBuffer( int bytes ); - -// this allows a global override of all materials -bool R_GlobalShaderOverride( const idMaterial** shader ); - -// this does various checks before calling the idDeclSkin -const idMaterial* R_RemapShaderBySkin( const idMaterial* shader, const idDeclSkin* customSkin, const idMaterial* customShader ); - - -//==================================================== - - -/* -** performanceCounters_t -*/ -struct performanceCounters_t -{ - int c_box_cull_in; - int c_box_cull_out; - int c_createInteractions; // number of calls to idInteraction::CreateInteraction - int c_createShadowVolumes; - int c_generateMd5; - int c_entityDefCallbacks; - int c_alloc; // counts for R_StaticAllc/R_StaticFree - int c_free; - int c_visibleViewEntities; - int c_shadowViewEntities; - int c_viewLights; - int c_numViews; // number of total views rendered - int c_deformedSurfaces; // idMD5Mesh::GenerateSurface - int c_deformedVerts; // idMD5Mesh::GenerateSurface - int c_deformedIndexes; // idMD5Mesh::GenerateSurface - int c_tangentIndexes; // R_DeriveTangents() - int c_entityUpdates; - int c_lightUpdates; - int c_entityReferences; - int c_lightReferences; - int c_guiSurfs; - int frontEndMicroSec; // sum of time in all RE_RenderScene's in a frame -}; - - -struct tmu_t -{ - unsigned int current2DMap; - unsigned int current2DArray; - unsigned int currentCubeMap; -}; - - -const int MAX_MULTITEXTURE_UNITS = 8; - -enum vertexLayoutType_t -{ - LAYOUT_UNKNOWN = 0, - LAYOUT_DRAW_VERT, - LAYOUT_DRAW_SHADOW_VERT, - LAYOUT_DRAW_SHADOW_VERT_SKINNED -}; - -struct glstate_t -{ - tmu_t tmu[MAX_MULTITEXTURE_UNITS]; - - int currenttmu; - - int faceCulling; - - vertexLayoutType_t vertexLayout; - - // RB: 64 bit fixes, changed unsigned int to uintptr_t - uintptr_t currentVertexBuffer; - uintptr_t currentIndexBuffer; - - Framebuffer* currentFramebuffer; - // RB end - - float polyOfsScale; - float polyOfsBias; - - uint64 glStateBits; -}; - -struct backEndCounters_t -{ - int c_surfaces; - int c_shaders; - - int c_drawElements; - int c_drawIndexes; - - int c_shadowElements; - int c_shadowIndexes; - - int c_copyFrameBuffer; - - float c_overDraw; - - int totalMicroSec; // total microseconds for backend run - int shadowMicroSec; -}; - -// all state modified by the back end is separated -// from the front end state -struct backEndState_t -{ - const viewDef_t* viewDef; - backEndCounters_t pc; - - const viewEntity_t* currentSpace; // for detecting when a matrix must change - idScreenRect currentScissor; // for scissor clipping, local inside renderView viewport - glstate_t glState; // for OpenGL state deltas - - bool currentRenderCopied; // true if any material has already referenced _currentRender - - idRenderMatrix prevMVP[2]; // world MVP from previous frame for motion blur, per-eye - - // RB begin - idRenderMatrix shadowV[6]; // shadow depth view matrix - idRenderMatrix shadowP[6]; // shadow depth projection matrix - - float hdrAverageLuminance; - float hdrMaxLuminance; - float hdrTime; - float hdrKey; - // RB end - - // surfaces used for code-based drawing - drawSurf_t unitSquareSurface; - drawSurf_t zeroOneCubeSurface; - drawSurf_t testImageSurface; -}; - -class idParallelJobList; - -const int MAX_GUI_SURFACES = 1024; // default size of the drawSurfs list for guis, will -// be automatically expanded as needed - -static const int MAX_RENDER_CROPS = 8; - -/* -** Most renderer globals are defined here. -** backend functions should never modify any of these fields, -** but may read fields that aren't dynamically modified -** by the frontend. -*/ -class idRenderSystemLocal : public idRenderSystem -{ -public: - // external functions - virtual void Init(); - virtual void Shutdown(); - virtual void ResetGuiModels(); - virtual void InitOpenGL(); - virtual void ShutdownOpenGL(); - virtual bool IsOpenGLRunning() const; - virtual bool IsFullScreen() const; - virtual stereo3DMode_t GetStereo3DMode() const; - virtual bool HasQuadBufferSupport() const; - virtual bool IsStereoScopicRenderingSupported() const; - virtual stereo3DMode_t GetStereoScopicRenderingMode() const; - virtual void EnableStereoScopicRendering( const stereo3DMode_t mode ) const; - virtual int GetWidth() const; - virtual int GetHeight() const; - virtual int GetVirtualWidth() const; - virtual int GetVirtualHeight() const; - virtual float GetPixelAspect() const; - virtual float GetPhysicalScreenWidthInCentimeters() const; - virtual idRenderWorld* AllocRenderWorld(); - virtual void FreeRenderWorld( idRenderWorld* rw ); - virtual void BeginLevelLoad(); - virtual void EndLevelLoad(); - virtual void LoadLevelImages(); - virtual void Preload( const idPreloadManifest& manifest, const char* mapName ); - virtual void BeginAutomaticBackgroundSwaps( autoRenderIconType_t icon = AUTORENDER_DEFAULTICON ); - virtual void EndAutomaticBackgroundSwaps(); - virtual bool AreAutomaticBackgroundSwapsRunning( autoRenderIconType_t* usingAlternateIcon = NULL ) const; - - virtual idFont* RegisterFont( const char* fontName ); - virtual void ResetFonts(); - virtual void PrintMemInfo( MemInfo_t* mi ); - - virtual void SetColor( const idVec4& color ); - virtual uint32 GetColor(); - virtual void SetGLState( const uint64 glState ) ; - virtual void DrawFilled( const idVec4& color, float x, float y, float w, float h ); - virtual void DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial* material ); - virtual void DrawStretchPic( const idVec4& topLeft, const idVec4& topRight, const idVec4& bottomRight, const idVec4& bottomLeft, const idMaterial* material ); - virtual void DrawStretchTri( const idVec2& p1, const idVec2& p2, const idVec2& p3, const idVec2& t1, const idVec2& t2, const idVec2& t3, const idMaterial* material ); - virtual idDrawVert* AllocTris( int numVerts, const triIndex_t* indexes, int numIndexes, const idMaterial* material, const stereoDepthType_t stereoType = STEREO_DEPTH_TYPE_NONE ); - virtual void DrawSmallChar( int x, int y, int ch ); - virtual void DrawSmallStringExt( int x, int y, const char* string, const idVec4& setColor, bool forceColor ); - virtual void DrawBigChar( int x, int y, int ch ); - virtual void DrawBigStringExt( int x, int y, const char* string, const idVec4& setColor, bool forceColor ); - - virtual void WriteDemoPics(); - virtual void WriteEndFrame(); - virtual void DrawDemoPics(); - virtual const emptyCommand_t* SwapCommandBuffers( uint64* frontEndMicroSec, uint64* backEndMicroSec, uint64* shadowMicroSec, uint64* gpuMicroSec ); - - virtual void SwapCommandBuffers_FinishRendering( uint64* frontEndMicroSec, uint64* backEndMicroSec, uint64* shadowMicroSec, uint64* gpuMicroSec ); - virtual const emptyCommand_t* SwapCommandBuffers_FinishCommandBuffers(); - - virtual void RenderCommandBuffers( const emptyCommand_t* commandBuffers ); - virtual void TakeScreenshot( int width, int height, const char* fileName, int downSample, renderView_t* ref, int exten ); - virtual void CropRenderSize( int width, int height ); - virtual void CaptureRenderToImage( const char* imageName, bool clearColorAfterCopy = false ); - virtual void CaptureRenderToFile( const char* fileName, bool fixAlpha ); - virtual void UnCrop(); - virtual bool UploadImage( const char* imageName, const byte* data, int width, int height ); - - - -public: - // internal functions - idRenderSystemLocal(); - ~idRenderSystemLocal(); - - void UpdateStereo3DMode(); - - void Clear(); - void GetCroppedViewport( idScreenRect* viewport ); - void PerformResolutionScaling( int& newWidth, int& newHeight ); - int GetFrameCount() const - { - return frameCount; - }; - - void OnFrame(); - -public: - // renderer globals - bool registered; // cleared at shutdown, set at InitOpenGL - - bool takingScreenshot; - - int frameCount; // incremented every frame - int viewCount; // incremented every view (twice a scene if subviewed) - // and every R_MarkFragments call - - float frameShaderTime; // shader time for all non-world 2D rendering - - idVec4 ambientLightVector; // used for "ambient bump mapping" - - idListworlds; - - idRenderWorldLocal* primaryWorld; - renderView_t primaryRenderView; - viewDef_t* primaryView; - // many console commands need to know which world they should operate on - - const idMaterial* whiteMaterial; - const idMaterial* charSetMaterial; - const idMaterial* defaultPointLight; - const idMaterial* defaultProjectedLight; - const idMaterial* defaultMaterial; - idImage* testImage; - idCinematic* testVideo; - int testVideoStartTime; - - idImage* ambientCubeImage; // hack for testing dependent ambient lighting - - viewDef_t* viewDef; - - performanceCounters_t pc; // performance counters - - viewEntity_t identitySpace; // can use if we don't know viewDef->worldSpace is valid - - idScreenRect renderCrops[MAX_RENDER_CROPS]; - int currentRenderCrop; - - // GUI drawing variables for surface creation - int guiRecursionLevel; // to prevent infinite overruns - uint32 currentColorNativeBytesOrder; - uint64 currentGLState; - class idGuiModel* guiModel; - - idList fonts; - - unsigned short gammaTable[256]; // brightness / gamma modify this - - srfTriangles_t* unitSquareTriangles; - srfTriangles_t* zeroOneCubeTriangles; - srfTriangles_t* testImageTriangles; - - // these are allocated at buffer swap time, but - // the back end should only use the ones in the backEnd stucture, - // which are copied over from the frame that was just swapped. - drawSurf_t unitSquareSurface_; - drawSurf_t zeroOneCubeSurface_; - drawSurf_t testImageSurface_; - - idParallelJobList* frontEndJobList; - - unsigned timerQueryId; // for GL_TIME_ELAPSED_EXT queries -}; - -extern backEndState_t backEnd; -extern idRenderSystemLocal tr; -extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared during ref re-init - -// -// cvars -// -extern idCVar r_debugContext; // enable various levels of context debug -extern idCVar r_glDriver; // "opengl32", etc -extern idCVar r_skipIntelWorkarounds; // skip work arounds for Intel driver bugs -extern idCVar r_vidMode; // video mode number -extern idCVar r_displayRefresh; // optional display refresh rate option for vid mode -extern idCVar r_fullscreen; // 0 = windowed, 1 = full screen -extern idCVar r_antiAliasing; // anti aliasing mode, SMAA, TXAA, MSAA etc. - -extern idCVar r_znear; // near Z clip plane - -extern idCVar r_swapInterval; // changes wglSwapIntarval -extern idCVar r_offsetFactor; // polygon offset parameter -extern idCVar r_offsetUnits; // polygon offset parameter -extern idCVar r_singleTriangle; // only draw a single triangle per primitive -extern idCVar r_logFile; // number of frames to emit GL logs -extern idCVar r_clear; // force screen clear every frame -extern idCVar r_subviewOnly; // 1 = don't render main view, allowing subviews to be debugged -extern idCVar r_lightScale; // all light intensities are multiplied by this, which is normally 3 -extern idCVar r_flareSize; // scale the flare deforms from the material def - -extern idCVar r_gamma; // changes gamma tables -extern idCVar r_brightness; // changes gamma tables - -extern idCVar r_checkBounds; // compare all surface bounds with precalculated ones -extern idCVar r_maxAnisotropicFiltering; // texture filtering parameter -extern idCVar r_useTrilinearFiltering; // Extra quality filtering -extern idCVar r_lodBias; // lod bias - -extern idCVar r_useLightPortalFlow; // 1 = do a more precise area reference determination -extern idCVar r_useShadowSurfaceScissor; // 1 = scissor shadows by the scissor rect of the interaction surfaces -extern idCVar r_useConstantMaterials; // 1 = use pre-calculated material registers if possible -extern idCVar r_useNodeCommonChildren; // stop pushing reference bounds early when possible -extern idCVar r_useSilRemap; // 1 = consider verts with the same XYZ, but different ST the same for shadows -extern idCVar r_useLightPortalCulling; // 0 = none, 1 = box, 2 = exact clip of polyhedron faces, 3 MVP to plane culling -extern idCVar r_useLightAreaCulling; // 0 = off, 1 = on -extern idCVar r_useLightScissors; // 1 = use custom scissor rectangle for each light -extern idCVar r_useEntityPortalCulling; // 0 = none, 1 = box -extern idCVar r_skipPrelightShadows; // 1 = skip the dmap generated static shadow volumes -extern idCVar r_useCachedDynamicModels; // 1 = cache snapshots of dynamic models -extern idCVar r_useScissor; // 1 = scissor clip as portals and lights are processed -extern idCVar r_usePortals; // 1 = use portals to perform area culling, otherwise draw everything -extern idCVar r_useStateCaching; // avoid redundant state changes in GL_*() calls -extern idCVar r_useEntityCallbacks; // if 0, issue the callback immediately at update time, rather than defering -extern idCVar r_lightAllBackFaces; // light all the back faces, even when they would be shadowed -extern idCVar r_useLightDepthBounds; // use depth bounds test on lights to reduce both shadow and interaction fill -extern idCVar r_useShadowDepthBounds; // use depth bounds test on individual shadows to reduce shadow fill -// RB begin -extern idCVar r_useShadowMapping; // use shadow mapping instead of stencil shadows -extern idCVar r_useHalfLambertLighting; // use Half-Lambert lighting instead of classic Lambert -extern idCVar r_useHDR; -extern idCVar r_useSRGB; -// RB end - -extern idCVar r_skipStaticInteractions; // skip interactions created at level load -extern idCVar r_skipDynamicInteractions; // skip interactions created after level load -extern idCVar r_skipPostProcess; // skip all post-process renderings -extern idCVar r_skipSuppress; // ignore the per-view suppressions -extern idCVar r_skipInteractions; // skip all light/surface interaction drawing -extern idCVar r_skipFrontEnd; // bypasses all front end work, but 2D gui rendering still draws -extern idCVar r_skipBackEnd; // don't draw anything -extern idCVar r_skipCopyTexture; // do all rendering, but don't actually copyTexSubImage2D -extern idCVar r_skipRender; // skip 3D rendering, but pass 2D -extern idCVar r_skipRenderContext; // NULL the rendering context during backend 3D rendering -extern idCVar r_skipTranslucent; // skip the translucent interaction rendering -extern idCVar r_skipAmbient; // bypasses all non-interaction drawing -extern idCVar r_skipNewAmbient; // bypasses all vertex/fragment program ambients -extern idCVar r_skipBlendLights; // skip all blend lights -extern idCVar r_skipFogLights; // skip all fog lights -extern idCVar r_skipSubviews; // 1 = don't render any mirrors / cameras / etc -extern idCVar r_skipGuiShaders; // 1 = don't render any gui elements on surfaces -extern idCVar r_skipParticles; // 1 = don't render any particles -extern idCVar r_skipUpdates; // 1 = don't accept any entity or light updates, making everything static -extern idCVar r_skipDeforms; // leave all deform materials in their original state -extern idCVar r_skipDynamicTextures; // don't dynamically create textures -extern idCVar r_skipBump; // uses a flat surface instead of the bump map -extern idCVar r_skipSpecular; // use black for specular -extern idCVar r_skipDiffuse; // use black for diffuse -extern idCVar r_skipDecals; // skip decal surfaces -extern idCVar r_skipOverlays; // skip overlay surfaces -extern idCVar r_skipShadows; // disable shadows - -extern idCVar r_ignoreGLErrors; - -extern idCVar r_screenFraction; // for testing fill rate, the resolution of the entire screen can be changed -extern idCVar r_showUnsmoothedTangents; // highlight geometry rendered with unsmoothed tangents -extern idCVar r_showSilhouette; // highlight edges that are casting shadow planes -extern idCVar r_showVertexColor; // draws all triangles with the solid vertex color -extern idCVar r_showUpdates; // report entity and light updates and ref counts -extern idCVar r_showDemo; // report reads and writes to the demo file -extern idCVar r_showDynamic; // report stats on dynamic surface generation -extern idCVar r_showIntensity; // draw the screen colors based on intensity, red = 0, green = 128, blue = 255 -extern idCVar r_showTrace; // show the intersection of an eye trace with the world -extern idCVar r_showDepth; // display the contents of the depth buffer and the depth range -extern idCVar r_showTris; // enables wireframe rendering of the world -extern idCVar r_showSurfaceInfo; // show surface material name under crosshair -extern idCVar r_showNormals; // draws wireframe normals -extern idCVar r_showEdges; // draw the sil edges -extern idCVar r_showViewEntitys; // displays the bounding boxes of all view models and optionally the index -extern idCVar r_showTexturePolarity; // shade triangles by texture area polarity -extern idCVar r_showTangentSpace; // shade triangles by tangent space -extern idCVar r_showDominantTri; // draw lines from vertexes to center of dominant triangles -extern idCVar r_showTextureVectors; // draw each triangles texture (tangent) vectors -extern idCVar r_showLights; // 1 = print light info, 2 = also draw volumes -extern idCVar r_showLightCount; // colors surfaces based on light count -extern idCVar r_showShadows; // visualize the stencil shadow volumes -extern idCVar r_showLightScissors; // show light scissor rectangles -extern idCVar r_showMemory; // print frame memory utilization -extern idCVar r_showCull; // report sphere and box culling stats -extern idCVar r_showAddModel; // report stats from tr_addModel -extern idCVar r_showSurfaces; // report surface/light/shadow counts -extern idCVar r_showPrimitives; // report vertex/index/draw counts -extern idCVar r_showPortals; // draw portal outlines in color based on passed / not passed -extern idCVar r_showSkel; // draw the skeleton when model animates -extern idCVar r_showOverDraw; // show overdraw -// RB begin -extern idCVar r_showShadowMaps; -extern idCVar r_showShadowMapLODs; -// RB end -extern idCVar r_jointNameScale; // size of joint names when r_showskel is set to 1 -extern idCVar r_jointNameOffset; // offset of joint names when r_showskel is set to 1 - -extern idCVar r_testGamma; // draw a grid pattern to test gamma levels -extern idCVar r_testGammaBias; // draw a grid pattern to test gamma levels - -extern idCVar r_singleLight; // suppress all but one light -extern idCVar r_singleEntity; // suppress all but one entity -extern idCVar r_singleArea; // only draw the portal area the view is actually in -extern idCVar r_singleSurface; // suppress all but one surface on each entity -extern idCVar r_shadowPolygonOffset; // bias value added to depth test for stencil shadow drawing -extern idCVar r_shadowPolygonFactor; // scale value for stencil shadow drawing - -extern idCVar r_jitter; // randomly subpixel jitter the projection matrix -extern idCVar r_orderIndexes; // perform index reorganization to optimize vertex use - -extern idCVar r_debugLineDepthTest; // perform depth test on debug lines -extern idCVar r_debugLineWidth; // width of debug lines -extern idCVar r_debugArrowStep; // step size of arrow cone line rotation in degrees -extern idCVar r_debugPolygonFilled; - -extern idCVar r_materialOverride; // override all materials - -extern idCVar r_debugRenderToTexture; - -extern idCVar stereoRender_deGhost; // subtract from opposite eye to reduce ghosting - -extern idCVar r_useGPUSkinning; - -// RB begin -extern idCVar r_shadowMapFrustumFOV; -extern idCVar r_shadowMapSingleSide; -extern idCVar r_shadowMapImageSize; -extern idCVar r_shadowMapJitterScale; -extern idCVar r_shadowMapBiasScale; -extern idCVar r_shadowMapRandomizeJitter; -extern idCVar r_shadowMapSamples; -extern idCVar r_shadowMapSplits; -extern idCVar r_shadowMapSplitWeight; -extern idCVar r_shadowMapLodScale; -extern idCVar r_shadowMapLodBias; -extern idCVar r_shadowMapPolygonFactor; -extern idCVar r_shadowMapPolygonOffset; -extern idCVar r_shadowMapOccluderFacing; -extern idCVar r_shadowMapRegularDepthBiasScale; -extern idCVar r_shadowMapSunDepthBiasScale; - -extern idCVar r_hdrAutoExposure; -extern idCVar r_hdrMinLuminance; -extern idCVar r_hdrMaxLuminance; -extern idCVar r_hdrKey; -extern idCVar r_hdrContrastDynamicThreshold; -extern idCVar r_hdrContrastStaticThreshold; -extern idCVar r_hdrContrastOffset; -extern idCVar r_hdrGlarePasses; -extern idCVar r_hdrDebug; - -extern idCVar r_ldrContrastThreshold; -extern idCVar r_ldrContrastOffset; - -extern idCVar r_useFilmicPostProcessEffects; -extern idCVar r_forceAmbient; - -extern idCVar r_useSSGI; -extern idCVar r_ssgiDebug; -extern idCVar r_ssgiFiltering; - -extern idCVar r_useSSAO; -extern idCVar r_ssaoDebug; -extern idCVar r_ssaoFiltering; -extern idCVar r_useHierarchicalDepthBuffer; - -extern idCVar r_exposure; -// RB end - -/* -==================================================================== - -INITIALIZATION - -==================================================================== -*/ - -void R_Init(); -void R_InitOpenGL(); - -void R_SetColorMappings(); - -void R_ScreenShot_f( const idCmdArgs& args ); -void R_StencilShot(); - -/* -==================================================================== - -IMPLEMENTATION SPECIFIC FUNCTIONS - -==================================================================== -*/ - -struct vidMode_t -{ - int width; - int height; - int displayHz; - - // RB begin - vidMode_t() - { - width = 640; - height = 480; - displayHz = 60; - } - - vidMode_t( int width, int height, int displayHz ) : - width( width ), height( height ), displayHz( displayHz ) {} - // RB end - - bool operator==( const vidMode_t& a ) - { - return a.width == width && a.height == height && a.displayHz == displayHz; - } -}; - -// the number of displays can be found by itterating this until it returns false -// displayNum is the 0 based value passed to EnumDisplayDevices(), you must add -// 1 to this to get an r_fullScreen value. -bool R_GetModeListForDisplay( const int displayNum, idList& modeList ); - -struct glimpParms_t -{ - int x; // ignored in fullscreen - int y; // ignored in fullscreen - int width; - int height; - int fullScreen; // 0 = windowed, otherwise 1 based monitor number to go full screen on - // -1 = borderless window for spanning multiple displays - bool stereo; - int displayHz; - int multiSamples; -}; - -// DG: R_GetModeListForDisplay is called before GLimp_Init(), but SDL needs SDL_Init() first. -// So add PreInit for platforms that need it, others can just stub it. -void GLimp_PreInit(); - -// If the desired mode can't be set satisfactorily, false will be returned. -// If succesful, sets glConfig.nativeScreenWidth, glConfig.nativeScreenHeight, and glConfig.pixelAspect -// The renderer will then reset the glimpParms to "safe mode" of 640x480 -// fullscreen and try again. If that also fails, the error will be fatal. -bool GLimp_Init( glimpParms_t parms ); - -// will set up gl up with the new parms -bool GLimp_SetScreenParms( glimpParms_t parms ); - -// Destroys the rendering context, closes the window, resets the resolution, -// and resets the gamma ramps. -void GLimp_Shutdown(); - -// Sets the hardware gamma ramps for gamma and brightness adjustment. -// These are now taken as 16 bit values, so we can take full advantage -// of dacs with >8 bits of precision -void GLimp_SetGamma( unsigned short red[256], - unsigned short green[256], - unsigned short blue[256] ); - - - -/* -============================================================ - -RENDERWORLD_DEFS - -============================================================ -*/ - -void R_DeriveEntityData( idRenderEntityLocal* def ); -void R_CreateEntityRefs( idRenderEntityLocal* def ); -void R_FreeEntityDefDerivedData( idRenderEntityLocal* def, bool keepDecals, bool keepCachedDynamicModel ); -void R_FreeEntityDefCachedDynamicModel( idRenderEntityLocal* def ); -void R_FreeEntityDefDecals( idRenderEntityLocal* def ); -void R_FreeEntityDefOverlay( idRenderEntityLocal* def ); -void R_FreeEntityDefFadedDecals( idRenderEntityLocal* def, int time ); - -// RB: for dmap -void R_DeriveLightData( idRenderLightLocal* light ); - -// Called by the editor and dmap to operate on light volumes -void R_RenderLightFrustum( const renderLight_t& renderLight, idPlane lightFrustum[6] ); - -srfTriangles_t* R_PolytopeSurface( int numPlanes, const idPlane* planes, idWinding** windings ); -// RB end -void R_CreateLightRefs( idRenderLightLocal* light ); -void R_FreeLightDefDerivedData( idRenderLightLocal* light ); - -void R_FreeDerivedData(); -void R_ReCreateWorldReferences(); -void R_CheckForEntityDefsUsingModel( idRenderModel* model ); -void R_ModulateLights_f( const idCmdArgs& args ); - -/* -============================================================ - -RENDERWORLD_PORTALS - -============================================================ -*/ - -viewEntity_t* R_SetEntityDefViewEntity( idRenderEntityLocal* def ); -viewLight_t* R_SetLightDefViewLight( idRenderLightLocal* def ); - -/* -==================================================================== - -TR_FRONTEND_MAIN - -==================================================================== -*/ - -void R_InitFrameData(); -void R_ShutdownFrameData(); -void R_ToggleSmpFrame(); -void* R_FrameAlloc( int bytes, frameAllocType_t type = FRAME_ALLOC_UNKNOWN ); -void* R_ClearedFrameAlloc( int bytes, frameAllocType_t type = FRAME_ALLOC_UNKNOWN ); - -void* R_StaticAlloc( int bytes, const memTag_t tag = TAG_RENDER_STATIC ); // just malloc with error checking -void* R_ClearedStaticAlloc( int bytes ); // with memset -void R_StaticFree( void* data ); - -void R_RenderView( viewDef_t* parms ); -void R_RenderPostProcess( viewDef_t* parms ); - -/* -============================================================ - -TR_FRONTEND_ADDLIGHTS - -============================================================ -*/ - -void R_ShadowBounds( const idBounds& modelBounds, const idBounds& lightBounds, const idVec3& lightOrigin, idBounds& shadowBounds ); - -ID_INLINE bool R_CullModelBoundsToLight( const idRenderLightLocal* light, const idBounds& localBounds, const idRenderMatrix& modelRenderMatrix ) -{ - idRenderMatrix modelLightProject; - idRenderMatrix::Multiply( light->baseLightProject, modelRenderMatrix, modelLightProject ); - return idRenderMatrix::CullBoundsToMVP( modelLightProject, localBounds, true ); -} - -void R_AddLights(); -void R_OptimizeViewLightsList(); - -/* -============================================================ - -TR_FRONTEND_ADDMODELS - -============================================================ -*/ - -bool R_IssueEntityDefCallback( idRenderEntityLocal* def ); -idRenderModel* R_EntityDefDynamicModel( idRenderEntityLocal* def ); -void R_ClearEntityDefDynamicModel( idRenderEntityLocal* def ); - -void R_SetupDrawSurfShader( drawSurf_t* drawSurf, const idMaterial* shader, const renderEntity_t* renderEntity ); -void R_SetupDrawSurfJoints( drawSurf_t* drawSurf, const srfTriangles_t* tri, const idMaterial* shader ); -void R_LinkDrawSurfToView( drawSurf_t* drawSurf, viewDef_t* viewDef ); - -void R_AddModels(); - -/* -============================================================= - -TR_FRONTEND_DEFORM - -============================================================= -*/ - -drawSurf_t* R_DeformDrawSurf( drawSurf_t* drawSurf ); - -/* -============================================================= - -TR_FRONTEND_GUISURF - -============================================================= -*/ - -void R_SurfaceToTextureAxis( const srfTriangles_t* tri, idVec3& origin, idVec3 axis[3] ); -void R_AddInGameGuis( const drawSurf_t* const drawSurfs[], const int numDrawSurfs ); - -/* -============================================================ - -TR_FRONTEND_SUBVIEW - -============================================================ -*/ - -bool R_PreciseCullSurface( const drawSurf_t* drawSurf, idBounds& ndcBounds ); -bool R_GenerateSubViews( const drawSurf_t* const drawSurfs[], const int numDrawSurfs ); - -/* -============================================================ - -TR_TRISURF - -============================================================ -*/ - -srfTriangles_t* R_AllocStaticTriSurf(); -void R_AllocStaticTriSurfVerts( srfTriangles_t* tri, int numVerts ); -void R_AllocStaticTriSurfIndexes( srfTriangles_t* tri, int numIndexes ); -void R_AllocStaticTriSurfPreLightShadowVerts( srfTriangles_t* tri, int numVerts ); -void R_AllocStaticTriSurfSilIndexes( srfTriangles_t* tri, int numIndexes ); -void R_AllocStaticTriSurfDominantTris( srfTriangles_t* tri, int numVerts ); -void R_AllocStaticTriSurfSilEdges( srfTriangles_t* tri, int numSilEdges ); -void R_AllocStaticTriSurfMirroredVerts( srfTriangles_t* tri, int numMirroredVerts ); -void R_AllocStaticTriSurfDupVerts( srfTriangles_t* tri, int numDupVerts ); - -srfTriangles_t* R_CopyStaticTriSurf( const srfTriangles_t* tri ); - -void R_ResizeStaticTriSurfVerts( srfTriangles_t* tri, int numVerts ); -void R_ResizeStaticTriSurfIndexes( srfTriangles_t* tri, int numIndexes ); -void R_ReferenceStaticTriSurfVerts( srfTriangles_t* tri, const srfTriangles_t* reference ); -void R_ReferenceStaticTriSurfIndexes( srfTriangles_t* tri, const srfTriangles_t* reference ); - -void R_FreeStaticTriSurfSilIndexes( srfTriangles_t* tri ); -void R_FreeStaticTriSurf( srfTriangles_t* tri ); -void R_FreeStaticTriSurfVerts( srfTriangles_t* tri ); -void R_FreeStaticTriSurfVertexCaches( srfTriangles_t* tri ); -int R_TriSurfMemory( const srfTriangles_t* tri ); - -void R_BoundTriSurf( srfTriangles_t* tri ); -void R_RemoveDuplicatedTriangles( srfTriangles_t* tri ); -void R_CreateSilIndexes( srfTriangles_t* tri ); -void R_RemoveDegenerateTriangles( srfTriangles_t* tri ); -void R_RemoveUnusedVerts( srfTriangles_t* tri ); -void R_RangeCheckIndexes( const srfTriangles_t* tri ); -void R_CreateVertexNormals( srfTriangles_t* tri ); // also called by dmap -void R_CleanupTriangles( srfTriangles_t* tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents ); -void R_ReverseTriangles( srfTriangles_t* tri ); - -// Only deals with vertexes and indexes, not silhouettes, planes, etc. -// Does NOT perform a cleanup triangles, so there may be duplicated verts in the result. -srfTriangles_t* R_MergeSurfaceList( const srfTriangles_t** surfaces, int numSurfaces ); -srfTriangles_t* R_MergeTriangles( const srfTriangles_t* tri1, const srfTriangles_t* tri2 ); - -// if the deformed verts have significant enough texture coordinate changes to reverse the texture -// polarity of a triangle, the tangents will be incorrect -void R_DeriveTangents( srfTriangles_t* tri ); - -// copy data from a front-end srfTriangles_t to a back-end drawSurf_t -void R_InitDrawSurfFromTri( drawSurf_t& ds, srfTriangles_t& tri ); - -// For static surfaces, the indexes, ambient, and shadow buffers can be pre-created at load -// time, rather than being re-created each frame in the frame temporary buffers. -void R_CreateStaticBuffersForTri( srfTriangles_t& tri ); - -// deformable meshes precalculate as much as possible from a base frame, then generate -// complete srfTriangles_t from just a new set of vertexes -struct deformInfo_t -{ - int numSourceVerts; - - // numOutputVerts may be smaller if the input had duplicated or degenerate triangles - // it will often be larger if the input had mirrored texture seams that needed - // to be busted for proper tangent spaces - int numOutputVerts; - idDrawVert* verts; - - int numIndexes; - triIndex_t* indexes; - - triIndex_t* silIndexes; // indexes changed to be the first vertex with same XYZ, ignoring normal and texcoords - - int numMirroredVerts; // this many verts at the end of the vert list are tangent mirrors - int* mirroredVerts; // tri->mirroredVerts[0] is the mirror of tri->numVerts - tri->numMirroredVerts + 0 - - int numDupVerts; // number of duplicate vertexes - int* dupVerts; // pairs of the number of the first vertex and the number of the duplicate vertex - - int numSilEdges; // number of silhouette edges - silEdge_t* silEdges; // silhouette edges - - vertCacheHandle_t staticIndexCache; // GL_INDEX_TYPE - vertCacheHandle_t staticAmbientCache; // idDrawVert - vertCacheHandle_t staticShadowCache; // idShadowCacheSkinned -}; - - -// if outputVertexes is not NULL, it will point to a newly allocated set of verts that includes the mirrored ones -deformInfo_t* R_BuildDeformInfo( int numVerts, const idDrawVert* verts, int numIndexes, const int* indexes, - bool useUnsmoothedTangents ); -void R_FreeDeformInfo( deformInfo_t* deformInfo ); -int R_DeformInfoMemoryUsed( deformInfo_t* deformInfo ); - -/* -============================================================= - -TR_TRACE - -============================================================= -*/ - -struct localTrace_t -{ - float fraction; - // only valid if fraction < 1.0 - idVec3 point; - idVec3 normal; - int indexes[3]; -}; - -localTrace_t R_LocalTrace( const idVec3& start, const idVec3& end, const float radius, const srfTriangles_t* tri ); -void RB_ShowTrace( drawSurf_t** drawSurfs, int numDrawSurfs ); - -/* -============================================================= - -BACKEND - -============================================================= -*/ - -void RB_ExecuteBackEndCommands( const emptyCommand_t* cmds ); - -/* -============================================================ - -TR_BACKEND_DRAW - -============================================================ -*/ - -void RB_SetMVP( const idRenderMatrix& mvp ); -void RB_DrawElementsWithCounters( const drawSurf_t* surf ); -void RB_DrawViewInternal( const viewDef_t* viewDef, const int stereoEye ); -void RB_DrawView( const void* data, const int stereoEye ); -void RB_CopyRender( const void* data ); -void RB_PostProcess( const void* data ); - -/* -============================================================= - -TR_BACKEND_RENDERTOOLS - -============================================================= -*/ - -float RB_DrawTextLength( const char* text, float scale, int len ); -void RB_AddDebugText( const char* text, const idVec3& origin, float scale, const idVec4& color, const idMat3& viewAxis, const int align, const int lifetime, const bool depthTest ); -void RB_ClearDebugText( int time ); -void RB_AddDebugLine( const idVec4& color, const idVec3& start, const idVec3& end, const int lifeTime, const bool depthTest ); -void RB_ClearDebugLines( int time ); -void RB_AddDebugPolygon( const idVec4& color, const idWinding& winding, const int lifeTime, const bool depthTest ); -void RB_ClearDebugPolygons( int time ); -void RB_DrawBounds( const idBounds& bounds ); -void RB_ShowLights( drawSurf_t** drawSurfs, int numDrawSurfs ); -void RB_ShowLightCount( drawSurf_t** drawSurfs, int numDrawSurfs ); -void RB_PolygonClear(); -void RB_ScanStencilBuffer(); -void RB_ShowDestinationAlpha(); -void RB_ShowOverdraw(); -void RB_RenderDebugTools( drawSurf_t** drawSurfs, int numDrawSurfs ); -void RB_ShutdownDebugTools(); -void RB_SetVertexColorParms( stageVertexColor_t svc ); - -//============================================= - -#include "ResolutionScale.h" -#include "RenderLog.h" -#include "jobs/ShadowShared.h" -#include "jobs/prelightshadowvolume/PreLightShadowVolume.h" -#include "jobs/staticshadowvolume/StaticShadowVolume.h" -#include "jobs/dynamicshadowvolume/DynamicShadowVolume.h" -#include "GraphicsAPIWrapper.h" -#include "GLMatrix.h" - - - -#include "BufferObject.h" -#include "RenderProgs.h" -#include "RenderWorld_local.h" -#include "GuiModel.h" -#include "VertexCache.h" - -#endif /* !__TR_LOCAL_H__ */ diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_trace.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_trace.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_trace.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_trace.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" #include "Model_local.h" #include "../idlib/geometry/DrawVert_intrinsics.h" diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_trisurf.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_trisurf.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/tr_trisurf.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/tr_trisurf.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -29,7 +29,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" /* ============================================================================== diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/VertexCache.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/VertexCache.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/renderer/VertexCache.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/renderer/VertexCache.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -30,7 +30,7 @@ #pragma hdrstop #include "precompiled.h" -#include "tr_local.h" +#include "RenderCommon.h" idVertexCache vertexCache; diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/swf/SWF_Events.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/swf/SWF_Events.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/swf/SWF_Events.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/swf/SWF_Events.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -3,6 +3,7 @@ Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2016-2017 Dustin Land This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). @@ -89,14 +90,14 @@ else if( entry->type == SWF_DICT_SHAPE && ( parentObject != NULL ) ) { idSWFShape* shape = entry->shape; - for( int i = 0; i < shape->fillDraws.Num(); i++ ) + for( int j = 0; j < shape->fillDraws.Num(); j++ ) { - const idSWFShapeDrawFill& fill = shape->fillDraws[i]; - for( int j = 0; j < fill.indices.Num(); j += 3 ) + const idSWFShapeDrawFill& fill = shape->fillDraws[j]; + for( int k = 0; k < fill.indices.Num(); k += 3 ) { - idVec2 xy1 = renderState2.matrix.Transform( fill.startVerts[fill.indices[j + 0]] ); - idVec2 xy2 = renderState2.matrix.Transform( fill.startVerts[fill.indices[j + 1]] ); - idVec2 xy3 = renderState2.matrix.Transform( fill.startVerts[fill.indices[j + 2]] ); + idVec2 xy1 = renderState2.matrix.Transform( fill.startVerts[fill.indices[k + 0]] ); + idVec2 xy2 = renderState2.matrix.Transform( fill.startVerts[fill.indices[k + 1]] ); + idVec2 xy3 = renderState2.matrix.Transform( fill.startVerts[fill.indices[k + 2]] ); idMat3 edgeEquations; edgeEquations[0].Set( xy1.x + xOffset, xy1.y + yOffset, 1.0f ); @@ -162,9 +163,6 @@ idVec3 br; idVec3 bl; - float xOffset = spriteInstance->xOffset; - float yOffset = spriteInstance->yOffset; - float topOffset = 0.0f; if( text->align == SWF_ET_ALIGN_LEFT ) @@ -289,7 +287,7 @@ return true; } - idSWFScriptVar var = hitObject->Get( "onDrag" ); + var = hitObject->Get( "onDrag" ); if( var.IsFunction() ) { idSWFParmList parms; diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/swf/SWF_Render.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/swf/SWF_Render.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/swf/SWF_Render.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/swf/SWF_Render.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -28,7 +28,7 @@ */ #pragma hdrstop #include "precompiled.h" -#include "../renderer/tr_local.h" +#include "../renderer/RenderCommon.h" idCVar swf_timescale( "swf_timescale", "1", CVAR_FLOAT, "timescale for swf files" ); idCVar swf_stopat( "swf_stopat", "0", CVAR_FLOAT, "stop at a specific frame" ); diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/swf/SWF_ScriptFunction.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/swf/SWF_ScriptFunction.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/swf/SWF_ScriptFunction.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/swf/SWF_ScriptFunction.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -2316,7 +2316,7 @@ } else { - line = va( "function %s( ", functionName.c_str() ); + line = va( "function %s( ", functionName.c_str() ); } uint16 numParms = bitstream.ReadU16(); @@ -2392,7 +2392,7 @@ } else { - line = va( "function %s( ", functionName.c_str() ); + line = va( "function %s( ", functionName.c_str() ); } for( int i = 0; i < numParms; i++ ) @@ -2584,7 +2584,7 @@ //actionScript += line; //line.Empty(); - const idStr& member = stack.A().ToString(); + const idStr& member = stack.A().ToString(); //if( stack.A().IsString() ) //{ // stack.B().SetResult( va( "%s[\"%s\"]", stack.B().ToString().c_str(), stack.A().ToString().c_str() ) ); diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/swf/SWF_Sprites.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/swf/SWF_Sprites.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/swf/SWF_Sprites.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/swf/SWF_Sprites.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -453,7 +453,7 @@ idFile_SWF file( new idFile_Memory() ); - idBase64 base64( command["stream"].GetString() ); + idBase64 base64( command["stream"].GetString() ); base64.Decode( file ); uint32 streamLength = file->Length() - 1; // skip trailing zero added by Decode() diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/sys/sdl/sdl_events.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/sys/sdl/sdl_events.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/sys/sdl/sdl_events.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/sys/sdl/sdl_events.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -40,7 +40,7 @@ #include -#include "renderer/tr_local.h" +#include "renderer/RenderCommon.h" #include "sdl_local.h" #include "../posix/posix_public.h" diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/sys/sdl/sdl_glimp.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/sys/sdl/sdl_glimp.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/sys/sdl/sdl_glimp.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/sys/sdl/sdl_glimp.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -40,7 +40,7 @@ #include -#include "renderer/tr_local.h" +#include "renderer/RenderCommon.h" #include "sdl_local.h" idCVar in_nograb( "in_nograb", "0", CVAR_SYSTEM | CVAR_NOCHEAT, "prevents input grabbing" ); diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/tools/compilers/dmap/dmap.cpp rbdoom3bfg-1.2.0+dfsg~git20181013/neo/tools/compilers/dmap/dmap.cpp --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/tools/compilers/dmap/dmap.cpp 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/tools/compilers/dmap/dmap.cpp 2018-10-13 10:08:18.000000000 +0000 @@ -402,7 +402,7 @@ passedName = stripped; // delete any old line leak files - idStr::snPrintf( path, sizeof( path ),"%s.lin", dmapGlobals.mapFileBase ); + idStr::snPrintf( path, sizeof( path ), "%s.lin", dmapGlobals.mapFileBase ); fileSystem->RemoveFile( path ); // delete any old generated binary proc files diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/neo/tools/compilers/dmap/dmap.h rbdoom3bfg-1.2.0+dfsg~git20181013/neo/tools/compilers/dmap/dmap.h --- rbdoom3bfg-1.2.0+dfsg~git20180605/neo/tools/compilers/dmap/dmap.h 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/neo/tools/compilers/dmap/dmap.h 2018-10-13 10:08:18.000000000 +0000 @@ -27,7 +27,7 @@ =========================================================================== */ -#include "../../../renderer/tr_local.h" +#include "../../../renderer/RenderCommon.h" typedef struct primitive_s diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/README.txt rbdoom3bfg-1.2.0+dfsg~git20181013/README.txt --- rbdoom3bfg-1.2.0+dfsg~git20180605/README.txt 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/README.txt 2018-10-13 10:08:18.000000000 +0000 @@ -619,3 +619,36 @@ GNU GPL, (2) the GNU LGPL, or (3) the Perl Artistic License. +libbinkdec +--------------------------------------------------------------------------- +neo/libs/libbinkdec/* + +Copyright (C) 2011 Barry Duncan + +Based on Bink video decoder from FFmpeg + + Copyright (C) 2009 Konstantin Shishkov + Copyright (C) 2011 Peter Ross + +And generic Code from FFmpeg + + Copyright (C) 2000-2011 FFmpeg team, http://www.ffmpeg.org + +libbinkdec and (the used parts of) FFmpeg are released under LGPL v2.1: + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +(You can find the whole license text on https://www.gnu.org/licenses/lgpl-2.1.html + or in neo/libs/libbinkdec/COPYING) diff -Nru rbdoom3bfg-1.2.0+dfsg~git20180605/RELEASE-NOTES.txt rbdoom3bfg-1.2.0+dfsg~git20181013/RELEASE-NOTES.txt --- rbdoom3bfg-1.2.0+dfsg~git20180605/RELEASE-NOTES.txt 2018-06-05 10:17:43.000000000 +0000 +++ rbdoom3bfg-1.2.0+dfsg~git20181013/RELEASE-NOTES.txt 2018-10-13 10:08:18.000000000 +0000 @@ -17,6 +17,10 @@ TBD in 2018 - RBDOOM-3-BFG 1.2.0 _______________________________ +- Refactored OpenGL renderer backend to match Dustin Land's Doom 3 BFG Vulkan port + +- Integrated libbinkdec for video playback as a slim alternative to FFmpeg (thanks to Daniel Gibson) + - Added in-engine Flash debugging tools and new console variables. These tools help to analyse the id Tech view of Flash and what SWF tags are supported and how they are interpreted by id Tech's own ActionScript 2 interpreter