mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 22:56:30 -10:00
Compare commits
242
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34bcb03ef8 | ||
|
|
eb738b3ef7 | ||
|
|
f04debfb36 | ||
|
|
aa8fb89a17 | ||
|
|
44e5f89e41 | ||
|
|
fee0b900de | ||
|
|
6b209223ee | ||
|
|
cb06c73b6a | ||
|
|
7ab8a96903 | ||
|
|
a58376404d | ||
|
|
cfe89f411b | ||
|
|
91c9417d3e | ||
|
|
f37c519b79 | ||
|
|
4dd194f4d6 | ||
|
|
b38367b22f | ||
|
|
72517ff9a2 | ||
|
|
c3e212094e | ||
|
|
9e9378dcb6 | ||
|
|
9b9041513d | ||
|
|
51aac78080 | ||
|
|
3dd21f6cb6 | ||
|
|
a42b27c0b8 | ||
|
|
ca73920b8e | ||
|
|
17374106d1 | ||
|
|
6da5302d34 | ||
|
|
d0a1efacb8 | ||
|
|
8168099eac | ||
|
|
ae943503cb | ||
|
|
4368db845d | ||
|
|
c25163e265 | ||
|
|
4bf9277c10 | ||
|
|
0bcdf19851 | ||
|
|
c4095d1af1 | ||
|
|
5d8f779cff | ||
|
|
6f2592e733 | ||
|
|
528a43952e | ||
|
|
62d1f1978b | ||
|
|
b9b556c7a5 | ||
|
|
16b0db8eb9 | ||
|
|
2c36ea35b4 | ||
|
|
43e540cc4c | ||
|
|
67627bd786 | ||
|
|
ea0c4b7b78 | ||
|
|
29e56bb19a | ||
|
|
57da3e1ef6 | ||
|
|
16ac19946f | ||
|
|
e319b6f941 | ||
|
|
8c88b68327 | ||
|
|
e75ed62692 | ||
|
|
748857ca2f | ||
|
|
bff8231d87 | ||
|
|
29087a3237 | ||
|
|
a228a127e2 | ||
|
|
2692240ed9 | ||
|
|
a47dcc0548 | ||
|
|
9fed19d4fc | ||
|
|
9446e61587 | ||
|
|
1ffd0d3ef8 | ||
|
|
1a94018fb4 | ||
|
|
e8ef727a19 | ||
|
|
dfdfd59367 | ||
|
|
4f7b718167 | ||
|
|
b1046b1c1c | ||
|
|
4663aed194 | ||
|
|
a56432f5fc | ||
|
|
206ce536ec | ||
|
|
d8ccf84452 | ||
|
|
bed9c13233 | ||
|
|
16993b236f | ||
|
|
94f8d547e0 | ||
|
|
b6908d10c4 | ||
|
|
a54aa24a64 | ||
|
|
d083089e1d | ||
|
|
338436d590 | ||
|
|
1d2f778b76 | ||
|
|
aad1bbbb05 | ||
|
|
1e4bede8c5 | ||
|
|
38b331dc92 | ||
|
|
d3965b1f9d | ||
|
|
986099a495 | ||
|
|
07ff605c58 | ||
|
|
a8171c118f | ||
|
|
4b9c7b19aa | ||
|
|
33d2294a49 | ||
|
|
8e558b2095 | ||
|
|
703bfab587 | ||
|
|
344502c436 | ||
|
|
ef06593ed7 | ||
|
|
a22b336bfe | ||
|
|
37b81efea4 | ||
|
|
7c6f99c68b | ||
|
|
f7b7aaead3 | ||
|
|
80dcefa0fc | ||
|
|
27a70d545d | ||
|
|
e4614f01ba | ||
|
|
e2d8502a3e | ||
|
|
dee0cf600f | ||
|
|
6181c0b2f7 | ||
|
|
0f942afaae | ||
|
|
cdde87662a | ||
|
|
4e7f8fa92a | ||
|
|
867ebfed89 | ||
|
|
0ff8a2c159 | ||
|
|
8272304cfa | ||
|
|
0522566790 | ||
|
|
59e7b10b73 | ||
|
|
eb4cfeb256 | ||
|
|
a7b1c00a84 | ||
|
|
e484a84d97 | ||
|
|
bd2bb12ad3 | ||
|
|
c890c0af1f | ||
|
|
9cda43afb2 | ||
|
|
34b4321416 | ||
|
|
3a18a88e30 | ||
|
|
686bf15879 | ||
|
|
22f0ba89a4 | ||
|
|
a3bf47991b | ||
|
|
6af1768147 | ||
|
|
0d9fbd4725 | ||
|
|
c6975fda3c | ||
|
|
52baa1f115 | ||
|
|
d684dcea1b | ||
|
|
fa7f49f1e4 | ||
|
|
cc3dc5f566 | ||
|
|
19c50412ba | ||
|
|
cdd391caa8 | ||
|
|
4860f72678 | ||
|
|
5ba33228cb | ||
|
|
b7f3fdbb98 | ||
|
|
1bffdce6ef | ||
|
|
b130d526ff | ||
|
|
4c1ed2f66a | ||
|
|
d30a73a578 | ||
|
|
fa03117eaf | ||
|
|
2eb109dc49 | ||
|
|
bef57f7559 | ||
|
|
b807c670db | ||
|
|
24b71441c0 | ||
|
|
e47581ffa5 | ||
|
|
c585314ff1 | ||
|
|
97d09ae6ad | ||
|
|
250bf919a7 | ||
|
|
f8dd06ccef | ||
|
|
67416cc8f6 | ||
|
|
7118697a35 | ||
|
|
095c1ebe2b | ||
|
|
8c89c19c7e | ||
|
|
ae3d06c54f | ||
|
|
dbbb8af17b | ||
|
|
a23830359a | ||
|
|
31e572ec03 | ||
|
|
29b5c4bf7a | ||
|
|
3811270a09 | ||
|
|
64fc95ec8c | ||
|
|
0c70672a84 | ||
|
|
67e6bcca9f | ||
|
|
8de33ab56a | ||
|
|
b786b8e230 | ||
|
|
9dc308331b | ||
|
|
628ac86c3e | ||
|
|
dcee8a302e | ||
|
|
c7673f0591 | ||
|
|
000d0c3a0d | ||
|
|
ec19f9be98 | ||
|
|
3005a67573 | ||
|
|
33d4a7efa7 | ||
|
|
6c4e03d9dc | ||
|
|
537ee433de | ||
|
|
2cff45f2c5 | ||
|
|
466e4c159f | ||
|
|
6c7de5120e | ||
|
|
b2b0ba3630 | ||
|
|
14dcff6f5f | ||
|
|
d826537485 | ||
|
|
95c0fad96f | ||
|
|
85b3a30376 | ||
|
|
3c347ae938 | ||
|
|
09b28f2219 | ||
|
|
2fb078f32b | ||
|
|
a19b3030b6 | ||
|
|
5095b1c57a | ||
|
|
ab14742f96 | ||
|
|
492c4ba10a | ||
|
|
999eb8a3f9 | ||
|
|
03aa75c39a | ||
|
|
4f096c26b2 | ||
|
|
3db9fe9383 | ||
|
|
d1e236451f | ||
|
|
6cf7cb0843 | ||
|
|
2084eb01e8 | ||
|
|
7d1365800f | ||
|
|
66ce0acc17 | ||
|
|
c29954d672 | ||
|
|
f2d5246ccb | ||
|
|
b6dcc4f5ef | ||
|
|
bd62ceeeb0 | ||
|
|
f1bf0a411c | ||
|
|
28898ca8e3 | ||
|
|
3acdf3e801 | ||
|
|
f1101bee5d | ||
|
|
e617f0cc41 | ||
|
|
7c9f73fbdc | ||
|
|
c36b47a35c | ||
|
|
8d0b0a76f2 | ||
|
|
36e5afe1be | ||
|
|
20398150d8 | ||
|
|
e085cc20ab | ||
|
|
6b5869853c | ||
|
|
a6411cc1d3 | ||
|
|
bd4427a832 | ||
|
|
6dbd7c34e6 | ||
|
|
7a3029d1e3 | ||
|
|
1bca5f128d | ||
|
|
6bbb6be880 | ||
|
|
c1c2b72ef0 | ||
|
|
1aa85d236e | ||
|
|
1afc5eec13 | ||
|
|
759c9b1148 | ||
|
|
47bb378342 | ||
|
|
0b3dad8dc0 | ||
|
|
13e601a523 | ||
|
|
5de1b684f4 | ||
|
|
c5dcaf88d8 | ||
|
|
55558cc608 | ||
|
|
addc3ef383 | ||
|
|
2c1abf78d1 | ||
|
|
77c950ccd4 | ||
|
|
b160184f5b | ||
|
|
f8d0a9bc7d | ||
|
|
72fa41a284 | ||
|
|
72a797f732 | ||
|
|
2b0ec7161a | ||
|
|
90c23c007c | ||
|
|
841872aae0 | ||
|
|
72013d4c31 | ||
|
|
416d45d060 | ||
|
|
18be4e854c | ||
|
|
526076f8ff | ||
|
|
e003d08249 | ||
|
|
c8baf8b344 | ||
|
|
b5f75af66e | ||
|
|
25415342ea |
No files matched your search
-30
@@ -1,33 +1,3 @@
|
||||
*.o
|
||||
*.a
|
||||
.dirstamp
|
||||
libtool
|
||||
ltmain.sh
|
||||
m4/libtool.m4
|
||||
m4/ltoptions.m4
|
||||
m4/ltsugar.m4
|
||||
m4/ltversion.m4
|
||||
m4/lt~obsolete.m4
|
||||
compile
|
||||
.deps/
|
||||
code/.deps/
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
config.*
|
||||
code/fs2_open_*
|
||||
code/wxFRED2_*
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
missing
|
||||
.svn
|
||||
*.layout
|
||||
projects/Xcode/Frameworks/
|
||||
|
||||
#========
|
||||
|
||||
#OS junk files
|
||||
[Tt]humbs.db
|
||||
*.DS_Store
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
[submodule "cmake/external/cotire"]
|
||||
path = cmake/external/cotire
|
||||
url = https://github.com/sakra/cotire.git
|
||||
[submodule "cmake/external/rpavlik-cmake-modules"]
|
||||
path = cmake/external/rpavlik-cmake-modules
|
||||
url = https://github.com/asarium/cmake-modules.git
|
||||
+1
-1
@@ -53,7 +53,7 @@ endif()
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/finder")
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/rpavlik-cmake-modules")
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/cotire/CMake")
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/cotire")
|
||||
|
||||
IF(RESET_INSTALL_PREFIX)
|
||||
IF(NOT $ENV{FS2PATH} STREQUAL "")
|
||||
|
||||
+1
-14
@@ -2,20 +2,7 @@
|
||||
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild) -Or [System.Convert]::ToBoolean($env:TestBuild)) {
|
||||
# Skip tests for deployment
|
||||
exit 0
|
||||
} else {
|
||||
# Appveyor doesn't have OpenAL so copy our DLLs to the output FOLDER
|
||||
$arch=""
|
||||
if ($Env:CMAKE_GENERATOR -Match "Win64") {
|
||||
$arch="win64"
|
||||
} else {
|
||||
$arch="win32"
|
||||
}
|
||||
$dllPath = "$Env:APPVEYOR_BUILD_FOLDER\lib\openal\libs\$arch\OpenAL32.dll"
|
||||
$copyDestination = "$pwd\bin\$Env:CONFIGURATION\"
|
||||
|
||||
write "Copying OpenAL DLL..."
|
||||
Copy-Item "$dllPath" "$copyDestination"
|
||||
|
||||
} else {
|
||||
write "Running unit tests..."
|
||||
# Run unit tests
|
||||
&"$pwd\bin\$Env:CONFIGURATION\unittests.exe" --gtest_shuffle 2>&1
|
||||
|
||||
@@ -6,6 +6,11 @@ mkdir -p build
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
if [ "$RELEASE_BUILD" = true ]; then
|
||||
PARENT_DIR="$(basename $PWD)"
|
||||
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
|
||||
fi
|
||||
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@ if [[ ! "$(curl -V)" == *"sftp"* ]]; then
|
||||
cd ..
|
||||
dpkg -l | grep curl
|
||||
ls -al
|
||||
sudo dpkg -i curl*.deb
|
||||
sudo dpkg -i libcurl3*.deb
|
||||
sudo dpkg -i curl*.deb
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew install curl --with-libssh2
|
||||
export PATH="/usr/local/opt/curl/bin:$PATH"
|
||||
|
||||
@@ -4,11 +4,6 @@ set -ex
|
||||
mkdir -p /tmp/builds
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
if [ "$RELEASE_BUILD" = true ]; then
|
||||
PARENT_DIR="$(basename $PWD)"
|
||||
(cd .. && tar cvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
|
||||
fi
|
||||
|
||||
cd build
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
HERE=$(dirname $(readlink -f "${0}"))
|
||||
export LD_LIBRARY_PATH="${HERE}"/lib:$PATH
|
||||
export LD_LIBRARY_PATH="${HERE}"/lib:"$LD_LIBRARY_PATH"
|
||||
"${HERE}"/bin/$<TARGET_FILE_NAME:Freespace2> $@
|
||||
@@ -1,6 +1,9 @@
|
||||
|
||||
include(WriteCompilerDetectionHeader)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
set(REQUIRED_CXX_FEATURES cxx_rvalue_references cxx_nullptr)
|
||||
|
||||
get_property(CMAKE_CXX_KNOWN_FEATURES GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
|
||||
|
||||
@@ -27,6 +27,7 @@ int main( int argc, char* argv[] )
|
||||
int SSE = false;
|
||||
int SSE2 = false;
|
||||
int AVX = false;
|
||||
int AVX2 = false;
|
||||
|
||||
int info[4];
|
||||
cpuid(info, 0);
|
||||
@@ -40,8 +41,14 @@ int main( int argc, char* argv[] )
|
||||
|
||||
AVX = (info[2] & ((int)1 << 28)) != 0;
|
||||
}
|
||||
if (nIds >= 7){
|
||||
cpuid(info,0x00000007);
|
||||
AVX2 = (info[1] & ((int)1 << 5)) != 0;
|
||||
}
|
||||
|
||||
if(AVX)
|
||||
if (AVX2)
|
||||
std::cout << "AVX2";
|
||||
else if(AVX)
|
||||
std::cout << "AVX";
|
||||
else if(SSE2)
|
||||
std::cout << "SSE2";
|
||||
|
||||
Vendored
-1
Submodule cmake/external/cotire deleted from 40a46bf2fb.
Vendored
+4054
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
#ifndef __FREDRC_H
|
||||
#define __FREDRC_H
|
||||
|
||||
#define ABOUT_LINE_1 "FRED2_OPEN - FreeSpace Editor, Version @FSO_PRODUCT_VERSION_STRING@ OpenGL"
|
||||
#define MAINFRAME_CONTENTS "FRED2_OPEN @FSO_PRODUCT_VERSION_STRING@ - FreeSpace2 Mission Editor\nUntitled\nFRED2\nFreeSpace2 Missions (*.fs2)\n.fs2\nFreeSpace2Mission\nFreeSpace2 Mission"
|
||||
|
||||
#endif // __FREDRC_H
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
include(platformChecks)
|
||||
|
||||
include(Cxx11)
|
||||
include(platformChecks)
|
||||
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/project.h.in ${GENERATED_SOURCE_DIR}/project.h)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/fred_rc.h.in ${GENERATED_SOURCE_DIR}/fred_rc.h)
|
||||
@@ -15,9 +15,9 @@ CHECK_INCLUDE_FILE_CXX("cxxabi.h" HAVE_CXXAPI_H)
|
||||
|
||||
CHECK_TYPE_SIZE("max_align_t" MAX_ALIGN_T)
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
set(CMAKE_REQUIRED_FLAGS "-std=c++11") # required for g++ <= 5
|
||||
endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
endif()
|
||||
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES "cstddef")
|
||||
CHECK_TYPE_SIZE("std::max_align_t" STD_MAX_ALIGN_T LANGUAGE CXX)
|
||||
@@ -25,6 +25,9 @@ set(CMAKE_EXTRA_INCLUDE_FILES "type_traits")
|
||||
CHECK_TYPE_SIZE("std::is_trivially_copyable<int>" STD_IS_TRIVIALLY_COPYABLE LANGUAGE CXX)
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES)
|
||||
|
||||
CHECK_TYPE_SIZE("char32_t" CHAR32_T LANGUAGE CXX)
|
||||
CHECK_TYPE_SIZE("U'b'" UNICODE_CHAR_LITERAL LANGUAGE CXX)
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS)
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#cmakedefine HAVE_STD_MAX_ALIGN_T
|
||||
|
||||
#cmakedefine HAVE_STD_IS_TRIVIALLY_COPYABLE
|
||||
#cmakedefine HAVE_STD_IS_TRIVIALLY_COPYABLE_ARRAY
|
||||
|
||||
#cmakedefine01 IS_64BIT
|
||||
|
||||
@@ -21,4 +22,7 @@
|
||||
|
||||
#cmakedefine01 HAVE_STRINGS_H
|
||||
|
||||
#cmakedefine01 HAVE_CHAR32_T
|
||||
#cmakedefine01 HAVE_UNICODE_CHAR_LITERAL
|
||||
|
||||
#endif // __PLATFORM_CHECKS_H__
|
||||
@@ -33,7 +33,9 @@ set(WARNING_FLAGS
|
||||
/wd4311 # Disables warnings about casting pointer types to ints. The funny thing is these warnings can't be resolved, just disabled... - m!m
|
||||
/wd4302 # Same as above - m!m
|
||||
/wd4366 # The result of the unary '&' operator may be unaligned - m!m
|
||||
/wd4592 # "symbol will be dynamically initialized" is being generated by a compiler bug, see https://stackoverflow.com/a/34027257 for an explanation - m!m
|
||||
$<$<CONFIG:Release>:/wd4101> # In release mode there are unreferenced variables because debug needs them
|
||||
/wd4995 # "'vsprintf': name was marked as #pragma deprecated" is being caused by our custom definition of vsprintf. I have no idea what causes this or how to fix it - m!m
|
||||
)
|
||||
|
||||
target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
|
||||
@@ -88,7 +90,7 @@ ENDIF(MSVC_USE_RUNTIME_DLL)
|
||||
INCLUDE(MSVCMultipleProcessCompile)
|
||||
|
||||
# Visual Studio supports compiling for multiple vector instruction sets
|
||||
SET(POSSIBLE_INSTUCTION_SETS "" SSE SSE2 AVX)
|
||||
SET(POSSIBLE_INSTUCTION_SETS "" SSE SSE2 AVX AVX2)
|
||||
|
||||
if (NOT DEFINED MSVC_SIMD_INSTRUCTIONS)
|
||||
detect_simd_instructions(MSVC_DETECTED_SIMD_INSTRUCTIONS)
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
endif()
|
||||
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 3)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 7)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 5)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 8)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 1)
|
||||
|
||||
# A numeric revision e.g. the CI build number
|
||||
set_if_not_defined(FSO_VERSION_REVISION 0)
|
||||
|
||||
+3
-3
@@ -21,7 +21,7 @@ TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR}/code)
|
||||
|
||||
target_link_libraries(code PUBLIC OpenGL)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${OPENAL_LIBS})
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC openal)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${LUA_LIBS})
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${PNG_LIBS})
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${JPEG_LIBS})
|
||||
@@ -30,6 +30,8 @@ TARGET_LINK_LIBRARIES(code PUBLIC sdl2)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ffmpeg)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC utfcpp)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC platform)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC compiler)
|
||||
|
||||
@@ -58,8 +60,6 @@ set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "prefix_head
|
||||
include(util)
|
||||
configure_cotire(code)
|
||||
|
||||
include(../cmake/Cxx11.cmake)
|
||||
|
||||
# Ensure that Xcode generates debug symbols on macOS for Debug builds
|
||||
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES")
|
||||
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Debug] "NO")
|
||||
|
||||
+11
-3
@@ -10395,6 +10395,7 @@ void ai_get_dock_goal_indexes(object *objp, ai_info *aip, ai_goal *aigp, object
|
||||
case AIS_DOCK_2:
|
||||
case AIS_DOCK_3:
|
||||
Warning(LOCATION, "Normally dock indexes should be calculated for only AIS_DOCK_0 and AIS_UNDOCK_0. Trace out and debug.");
|
||||
FALLTHROUGH;
|
||||
case AIS_DOCK_0:
|
||||
{
|
||||
// get them from the active goal
|
||||
@@ -10412,6 +10413,7 @@ void ai_get_dock_goal_indexes(object *objp, ai_info *aip, ai_goal *aigp, object
|
||||
case AIS_UNDOCK_1:
|
||||
case AIS_UNDOCK_2:
|
||||
Warning(LOCATION, "Normally dock indexes should be calculated for only AIS_DOCK_0 and AIS_UNDOCK_0. Trace out and debug.");
|
||||
FALLTHROUGH;
|
||||
case AIS_UNDOCK_0:
|
||||
{
|
||||
// get them from the guy I'm docked to
|
||||
@@ -10478,9 +10480,11 @@ void ai_cleanup_dock_mode_subjective(object *objp)
|
||||
case AIS_UNDOCK_0:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKED, dockee_index, -1);
|
||||
FALLTHROUGH;
|
||||
case AIS_UNDOCK_1:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_3, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_3, dockee_index, -1);
|
||||
FALLTHROUGH;
|
||||
case AIS_UNDOCK_2:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_2, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_2, dockee_index, -1);
|
||||
@@ -10490,9 +10494,11 @@ void ai_cleanup_dock_mode_subjective(object *objp)
|
||||
case AIS_DOCK_4A:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKED, dockee_index, -1);
|
||||
FALLTHROUGH;
|
||||
case AIS_DOCK_3:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_3, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_3, dockee_index, -1);
|
||||
FALLTHROUGH;
|
||||
case AIS_DOCK_2:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_2, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_2, dockee_index, -1);
|
||||
@@ -10833,7 +10839,7 @@ void ai_dock()
|
||||
|
||||
if (aip->submode == AIS_DOCK_3) {
|
||||
// Play a ship docking attach sound
|
||||
snd_play_3d( &Snds[SND_DOCK_ATTACH], &Pl_objp->pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DOCK_ATTACH), &Pl_objp->pos, &View_position );
|
||||
|
||||
// start the dock animation
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, 1);
|
||||
@@ -10960,7 +10966,7 @@ void ai_dock()
|
||||
ai_find_path(Pl_objp, OBJ_INDEX(goal_objp), path_num, 0);
|
||||
|
||||
// Play a ship docking detach sound
|
||||
snd_play_3d( &Snds[SND_DOCK_DETACH], &Pl_objp->pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DOCK_DETACH), &Pl_objp->pos, &View_position );
|
||||
|
||||
aip->submode = AIS_UNDOCK_1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
@@ -10980,7 +10986,7 @@ void ai_dock()
|
||||
// play the depart sound, but only once, since this mode is called multiple times per frame
|
||||
if ( !(aigp->flags[AI::Goal_Flags::Depart_sound_played]))
|
||||
{
|
||||
snd_play_3d( &Snds[SND_DOCK_DEPART], &Pl_objp->pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DOCK_DEPART), &Pl_objp->pos, &View_position );
|
||||
aigp->flags.set(AI::Goal_Flags::Depart_sound_played);
|
||||
}
|
||||
|
||||
@@ -12376,6 +12382,7 @@ void ai_maybe_evade_locked_missile(object *objp, ai_info *aip)
|
||||
case AIM_DOCK: // Ships in dock mode can evade iif they are not currently repairing or docked.
|
||||
if (object_is_docked(objp) || (aip->ai_flags[AI::AI_Flags::Repairing, AI::AI_Flags::Being_repaired]))
|
||||
break;
|
||||
FALLTHROUGH;
|
||||
case AIM_GUARD:
|
||||
// If in guard mode and far away from guard object, don't pursue guy that hit me.
|
||||
if ((aip->guard_objnum != -1) && (aip->guard_signature == Objects[aip->guard_objnum].signature)) {
|
||||
@@ -12383,6 +12390,7 @@ void ai_maybe_evade_locked_missile(object *objp, ai_info *aip)
|
||||
return;
|
||||
}
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case AIM_EVADE:
|
||||
case AIM_GET_BEHIND:
|
||||
case AIM_STAY_NEAR:
|
||||
|
||||
@@ -2051,7 +2051,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
if ( wip->launch_snd != -1 ) {
|
||||
// Don't play turret firing sound if turret sits on player ship... it gets annoying.
|
||||
if ( parent_objnum != OBJ_INDEX(Player_obj) || (turret->flags[Ship::Subsystem_Flags::Play_sound_for_player]) ) {
|
||||
snd_play_3d( &Snds[wip->launch_snd], turret_pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(wip->launch_snd), turret_pos, &View_position );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2138,7 +2138,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
if ( Weapon_info[tsi->weapon_class].launch_snd != -1 ) {
|
||||
// Don't play turret firing sound if turret sits on player ship... it gets annoying.
|
||||
if ( tsi->parent_objnum != OBJ_INDEX(Player_obj) ) {
|
||||
snd_play_3d( &Snds[Weapon_info[tsi->weapon_class].launch_snd], &turret_pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(Weapon_info[tsi->weapon_class].launch_snd), &turret_pos, &View_position );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -512,7 +512,14 @@ int unpack_pixel(anim_instance *ai, ubyte *data, ubyte pix, int aabitmap, int bp
|
||||
bit_16 = (ushort)pix;
|
||||
break;
|
||||
case 8:
|
||||
bit_8 = pix;
|
||||
// 8 bit-per-pixel aa bitmaps are a bit special since they only use value in the range [0, 15] where 15 wraps
|
||||
// around back to 0. Since the rest of the code expects the value to be in the range [0, 255] the pixel value
|
||||
// needs to be adjusted here. By muliplying the value with 17 the original range [0, 15] is mapped to [0, 255]
|
||||
if (pix >= 15) {
|
||||
bit_8 = 0;
|
||||
} else {
|
||||
bit_8 = (ubyte)(pix * 17);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Int3();
|
||||
@@ -596,7 +603,14 @@ int unpack_pixel_count(anim_instance *ai, ubyte *data, ubyte pix, int count = 0,
|
||||
bit_16 = (ushort)pix;
|
||||
break;
|
||||
case 8 :
|
||||
bit_8 = pix;
|
||||
// 8 bit-per-pixel aa bitmaps are a bit special since they only use value in the range [0, 15] where 15 wraps
|
||||
// around back to 0. Since the rest of the code expects the value to be in the range [0, 255] the pixel value
|
||||
// needs to be adjusted here. By muliplying the value with 17 the original range [0, 15] is mapped to [0, 255]
|
||||
if (pix >= 15) {
|
||||
bit_8 = 0;
|
||||
} else {
|
||||
bit_8 = (ubyte)(pix * 17);
|
||||
}
|
||||
break;
|
||||
default :
|
||||
Int3();
|
||||
|
||||
@@ -1312,7 +1312,7 @@ void asteriod_explode_sound(object *objp, int type, int play_loud)
|
||||
range_factor = 1.0f;
|
||||
}
|
||||
|
||||
snd_play_3d( &Snds[sound_index], &objp->pos, &Eye_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY, NULL, range_factor );
|
||||
snd_play_3d( gamesnd_get_game_sound(sound_index), &objp->pos, &Eye_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY, NULL, range_factor );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,6 +31,7 @@ union bm_extra_info {
|
||||
int keyframe; //!< used for animations -- keyframe info
|
||||
float total_time; //!< used for animations -- total animation time (not always derived from num_frames/fps)
|
||||
ubyte fps; //!< used for animations -- frames per second
|
||||
bool is_array; //!< Flag for if all frames of an animation have the same size which means that it can be put into a texture array
|
||||
|
||||
struct {
|
||||
// stuff for static animations
|
||||
@@ -89,7 +90,7 @@ struct bitmap_entry {
|
||||
#endif
|
||||
};
|
||||
|
||||
extern bitmap_entry bm_bitmaps[MAX_BITMAPS];
|
||||
extern bitmap_entry* bm_bitmaps;
|
||||
|
||||
// image specific lock functions
|
||||
void bm_lock_ani( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
|
||||
+123
-30
@@ -24,6 +24,7 @@
|
||||
#include "debugconsole/console.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/matrix.h"
|
||||
#include "graphics/grinternal.h"
|
||||
#include "io/key.h"
|
||||
#include "io/timer.h"
|
||||
@@ -83,17 +84,19 @@ const int BM_ANI_NUM_TYPES = sizeof(bm_ani_type_list) / sizeof(bm_ani_type_list[
|
||||
void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
|
||||
void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
|
||||
|
||||
int MAX_BITMAPS = DEFAULT_MAX_BITMAPS;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Declaration of protected variables (defined in cmdline.cpp).
|
||||
extern int Cmdline_cache_bitmaps;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Definition of public variables (declared as extern in bm_internal.h).
|
||||
bitmap_entry bm_bitmaps[MAX_BITMAPS];
|
||||
bitmap_entry* bm_bitmaps = nullptr;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Definition of private variables at file scope (static).
|
||||
static int bm_inited = 0;
|
||||
static bool bm_inited = false;
|
||||
static uint Bm_next_signature = 0x1234;
|
||||
static int bm_next_handle = 1;
|
||||
static int Bm_low_mem = 0;
|
||||
@@ -480,7 +483,11 @@ void bm_close() {
|
||||
for (i = 0; i<MAX_BITMAPS; i++) {
|
||||
bm_free_data(i); // clears flags, bbp, data, etc
|
||||
}
|
||||
bm_inited = 0;
|
||||
if (bm_bitmaps != nullptr) {
|
||||
delete[] bm_bitmaps;
|
||||
bm_bitmaps = nullptr;
|
||||
}
|
||||
bm_inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,7 +498,7 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
|
||||
Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
|
||||
}
|
||||
|
||||
if (!bm_inited) bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int n = -1;
|
||||
|
||||
@@ -871,7 +878,7 @@ int bm_get_info(int handle, int *w, int * h, ubyte * flags, int *nframes, int *f
|
||||
if (h) *h = bmp->h;
|
||||
if (flags) *flags = bmp->flags;
|
||||
|
||||
if (bm_is_anim(bitmapnum) == true) {
|
||||
if (bm_is_anim(bitmapnum)) {
|
||||
if (nframes) {
|
||||
*nframes = bm_bitmaps[bitmapnum].info.ani.num_frames;
|
||||
}
|
||||
@@ -942,7 +949,7 @@ void bm_get_palette(int handle, ubyte *pal, char *name) {
|
||||
}
|
||||
|
||||
uint bm_get_signature(int handle) {
|
||||
if (!bm_inited) bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int bitmapnum = handle % MAX_BITMAPS;
|
||||
Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid bitmap handle %d passed to bm_get_signature().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
|
||||
@@ -967,7 +974,7 @@ int bm_get_tcache_type(int num) {
|
||||
}
|
||||
|
||||
BM_TYPE bm_get_type(int handle) {
|
||||
if (!bm_inited) bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int bitmapnum = handle % MAX_BITMAPS;
|
||||
Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid bitmap handle %d passed to bm_get_type().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
|
||||
@@ -989,16 +996,17 @@ bool bm_has_alpha_channel(int handle) {
|
||||
}
|
||||
|
||||
void bm_init() {
|
||||
Assertion(!bm_inited, "bmpman cannot be initialized more than once!");
|
||||
|
||||
int i;
|
||||
|
||||
mprintf(("Size of bitmap info = " SIZE_T_ARG " KB\n", sizeof(bm_bitmaps) / 1024));
|
||||
mprintf(("Size of bitmap extra info = " SIZE_T_ARG " bytes\n", sizeof(bm_extra_info)));
|
||||
|
||||
if (!bm_inited) {
|
||||
bm_inited = 1;
|
||||
atexit(bm_close);
|
||||
if (bm_bitmaps == nullptr) {
|
||||
bm_bitmaps = new bitmap_entry[MAX_BITMAPS];
|
||||
}
|
||||
|
||||
mprintf(("Size of bitmap info = " SIZE_T_ARG " KB\n", (sizeof(bm_bitmaps[0]) * MAX_BITMAPS) / 1024));
|
||||
mprintf(("Size of bitmap extra info = " SIZE_T_ARG " bytes\n", sizeof(bm_extra_info)));
|
||||
|
||||
for (i = 0; i<MAX_BITMAPS; i++) {
|
||||
bm_bitmaps[i].filename[0] = '\0';
|
||||
bm_bitmaps[i].type = BM_TYPE_NONE;
|
||||
@@ -1022,6 +1030,8 @@ void bm_init() {
|
||||
|
||||
bm_free_data(i); // clears flags, bbp, data, etc
|
||||
}
|
||||
|
||||
bm_inited = true;
|
||||
}
|
||||
|
||||
int bm_is_compressed(int num) {
|
||||
@@ -1203,8 +1213,7 @@ int bm_load(const char *real_filename) {
|
||||
CFILE *img_cfp = NULL;
|
||||
int handle = -1;
|
||||
|
||||
if (!bm_inited)
|
||||
bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
// if no file was passed then get out now
|
||||
if ((real_filename == NULL) || (strlen(real_filename) <= 0))
|
||||
@@ -1509,8 +1518,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
size_t img_size = 0;
|
||||
char clean_name[MAX_FILENAME_LEN];
|
||||
|
||||
if (!bm_inited)
|
||||
bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
// set output param defaults before going any further
|
||||
if (nframes != nullptr)
|
||||
@@ -1701,6 +1709,8 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
}
|
||||
|
||||
int first_handle = bm_get_next_handle();
|
||||
// if all images of the animation have the same size then we can use a texture array
|
||||
bool is_array = true;
|
||||
|
||||
for (i = 0; i < anim_frames; i++) {
|
||||
memset(&bm_bitmaps[n + i], 0, sizeof(bitmap_entry));
|
||||
@@ -1787,8 +1797,39 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
bm_bitmaps[n + i].info.ani.apng.is_apng = false;
|
||||
}
|
||||
|
||||
if (bm_bitmaps[n].bm.w != bm_bitmaps[n + i].bm.w || bm_bitmaps[n].bm.h != bm_bitmaps[n + i].bm.h) {
|
||||
// We found a frame with a different size than the first frame -> this can't be used as a texture array
|
||||
is_array = false;
|
||||
|
||||
Warning(LOCATION, "Animation '%s' has images that are of different sizes (currently at frame %d)."
|
||||
"Performance could be improved by making all images the same size.", filename, i + 1);
|
||||
}
|
||||
if (bm_bitmaps[n].comp_type != bm_bitmaps[n + i].comp_type) {
|
||||
// Different compression type
|
||||
is_array = false;
|
||||
|
||||
Warning(LOCATION, "Animation '%s' has images that are of different compression formats (currently at frame %d)."
|
||||
"Performance could be improved by making all images the same compression format.", filename, i + 1);
|
||||
}
|
||||
if (bm_bitmaps[n].bm.true_bpp != bm_bitmaps[n + i].bm.true_bpp) {
|
||||
// We found a frame with an incompatible pixel format
|
||||
is_array = false;
|
||||
|
||||
Warning(LOCATION, "Animation '%s' has images that are of different pixel formats (currently at frame %d)."
|
||||
"Performance could be improved by making all images the same pixel format.", filename, i + 1);
|
||||
}
|
||||
if (bm_bitmaps[n].num_mipmaps != bm_bitmaps[n + i].num_mipmaps) {
|
||||
// We found a frame with a different number of mipmaps
|
||||
is_array = false;
|
||||
|
||||
Warning(LOCATION, "Animation '%s' has images that have a different number of mipmaps (currently at frame %d)."
|
||||
"Performance could be improved by giving all frames the same number of mipmaps.", filename, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Set array flag of first frame
|
||||
bm_bitmaps[n].info.ani.is_array = is_array;
|
||||
|
||||
if (nframes != nullptr)
|
||||
*nframes = anim_frames;
|
||||
|
||||
@@ -1897,7 +1938,7 @@ bitmap * bm_lock(int handle, int bpp, ubyte flags, bool nodebug) {
|
||||
bitmap *bmp;
|
||||
bitmap_entry *be;
|
||||
|
||||
if (!bm_inited) bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int bitmapnum = handle % MAX_BITMAPS;
|
||||
|
||||
@@ -2239,6 +2280,9 @@ void bm_lock_jpg(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
|
||||
// Unload any existing data
|
||||
bm_free_data(bitmapnum);
|
||||
|
||||
// JPEG actually only support 24 bits per pixel so we enforce that here
|
||||
bpp = 24;
|
||||
|
||||
d_size = (bpp >> 3);
|
||||
|
||||
// allocate bitmap data
|
||||
@@ -2299,7 +2343,7 @@ void bm_lock_pcx(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
|
||||
// this will populate filename[] whether it's EFF or not
|
||||
EFF_FILENAME_CHECK;
|
||||
|
||||
pcx_error = pcx_read_bitmap(filename, data, NULL, (bpp >> 3), (flags & BMP_AABITMAP), 0, be->dir_type);
|
||||
pcx_error = pcx_read_bitmap(filename, data, NULL, (bpp >> 3), (flags & BMP_AABITMAP), (flags & BMP_MASK_BITMAP) != 0, be->dir_type);
|
||||
|
||||
if (pcx_error != PCX_ERROR_NONE) {
|
||||
mprintf(("Couldn't load PCX!!! (%s)\n", filename));
|
||||
@@ -2378,7 +2422,7 @@ void bm_lock_tga(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
|
||||
Assert(byte_size);
|
||||
Assert(be->mem_taken > 0);
|
||||
|
||||
data = (ubyte*)bm_malloc(bitmapnum, be->mem_taken);
|
||||
data = (ubyte*)bm_malloc(bitmapnum, static_cast<size_t>(bmp->w * bmp->h * byte_size));
|
||||
|
||||
if (data) {
|
||||
memset(data, 0, be->mem_taken);
|
||||
@@ -2463,8 +2507,7 @@ int bm_make_render_target(int width, int height, int flags) {
|
||||
int bpp = 32;
|
||||
int size = 0;
|
||||
|
||||
if (!bm_inited)
|
||||
bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
// Find an open slot (starting from the end)
|
||||
for (n = -1, i = MAX_BITMAPS - 1; i >= 0; i--) {
|
||||
@@ -2837,12 +2880,16 @@ int bm_release(int handle, int clear_render_targets) {
|
||||
}
|
||||
|
||||
// be sure that all frames of an ani are unloaded - taylor
|
||||
if (bm_is_anim(n) == true) {
|
||||
if (bm_is_anim(n)) {
|
||||
int i, first = be->info.ani.first_frame, total = bm_bitmaps[first].info.ani.num_frames;
|
||||
|
||||
// The graphics system requires that the bitmap information for the whole animation is still valid when the data
|
||||
// is freed so we first free all the data and then clear the bitmaps data
|
||||
for (i = 0; i < total; i++) {
|
||||
bm_free_data(first + i, true); // clears flags, bbp, data, etc
|
||||
}
|
||||
|
||||
for (i = 0; i < total; i++) {
|
||||
memset(&bm_bitmaps[first + i], 0, sizeof(bitmap_entry));
|
||||
|
||||
bm_bitmaps[first + i].type = BM_TYPE_NONE;
|
||||
@@ -2891,8 +2938,7 @@ int bm_release(int handle, int clear_render_targets) {
|
||||
}
|
||||
|
||||
int bm_reload(int bitmap_handle, const char* filename) {
|
||||
if (!bm_inited)
|
||||
bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
// if no file was passed then get out now
|
||||
if ((filename == NULL) || (strlen(filename) <= 0))
|
||||
@@ -3072,10 +3118,7 @@ bool bm_set_render_target(int handle, int face) {
|
||||
|
||||
gr_reset_clip();
|
||||
|
||||
if (gr_screen.mode == GR_OPENGL) {
|
||||
extern void opengl_setup_viewport();
|
||||
opengl_setup_viewport();
|
||||
}
|
||||
gr_setup_viewport();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -3205,7 +3248,7 @@ int bm_unload_fast(int handle, int clear_render_targets) {
|
||||
void bm_unlock(int handle) {
|
||||
bitmap_entry *be;
|
||||
|
||||
if (!bm_inited) bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int bitmapnum = handle % MAX_BITMAPS;
|
||||
|
||||
@@ -3261,3 +3304,53 @@ int find_block_of(int n)
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool bm_is_texture_array(const int handle) {
|
||||
int bitmapnum = handle % MAX_BITMAPS;
|
||||
|
||||
if (!bm_is_anim(bitmapnum)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// This will return the index of the first animation frame
|
||||
int n = bm_get_cache_slot(handle, 0);
|
||||
bitmap_entry *be = &bm_bitmaps[n];
|
||||
|
||||
return be->info.ani.is_array;
|
||||
}
|
||||
|
||||
int bm_get_base_frame(const int handle, int* num_frames) {
|
||||
// If the bitmap is no animation then num_frames will still be at least 1
|
||||
auto animation_begin = bm_get_info(handle, nullptr, nullptr, nullptr, num_frames);
|
||||
|
||||
if (animation_begin < 0) {
|
||||
// Some kind of error
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!bm_is_texture_array(animation_begin)) {
|
||||
// If this is not a texture array then we just treat it like a single frame animation
|
||||
animation_begin = handle;
|
||||
if (num_frames != nullptr) {
|
||||
*num_frames = 1;
|
||||
}
|
||||
}
|
||||
return animation_begin;
|
||||
}
|
||||
int bm_get_array_index(const int handle) {
|
||||
return handle - bm_get_base_frame(handle, nullptr);
|
||||
}
|
||||
|
||||
int bmpman_count_bitmaps() {
|
||||
if (!bm_inited)
|
||||
return -1;
|
||||
|
||||
int total_bitmaps = 0;
|
||||
for (int i = 0; i < MAX_BITMAPS; i++) {
|
||||
if (bm_bitmaps[i].type != BM_TYPE_NONE) {
|
||||
total_bitmaps++;
|
||||
}
|
||||
}
|
||||
|
||||
return total_bitmaps;
|
||||
}
|
||||
+45
-2
@@ -33,7 +33,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief How many bitmaps the game can handle
|
||||
* @brief How many bitmaps the game can handle by default
|
||||
*
|
||||
* @attention MAX_BITMAPS shouldn't need to be bumped again. With the fixed bm_release() and it's proper use even the
|
||||
* largest missions should stay under this number. With the largest retail missions and wasteful content we should
|
||||
@@ -45,7 +45,9 @@
|
||||
* If anything we could/should reduce MAX_BITMAPS in the future. Where it's at now should accomidate even the
|
||||
* largest mods. -- Taylor
|
||||
*/
|
||||
#define MAX_BITMAPS 4750
|
||||
#define DEFAULT_MAX_BITMAPS 4750
|
||||
|
||||
extern int MAX_BITMAPS;
|
||||
|
||||
// Flag positions for bitmap.flags
|
||||
// ***** NOTE: bitmap.flags is an 8-bit value, no more BMP_TEX_* flags can be added unless the type is changed!! ******
|
||||
@@ -56,6 +58,7 @@
|
||||
#define BMP_TEX_DXT3 (1<<4) //!< dxt3 compressed 8r8g8b4a (32bit)
|
||||
#define BMP_TEX_DXT5 (1<<5) //!< dxt5 compressed 8r8g8b8a (32bit)
|
||||
#define BMP_TEX_CUBEMAP (1<<6) //!< a texture made for cubic environment map
|
||||
#define BMP_MASK_BITMAP (1<<7) //!< a bitmap that will be used for masking mouse interaction. Typically not used in render operations
|
||||
|
||||
// Combined flags
|
||||
#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 ) //!< Compressed textures
|
||||
@@ -698,4 +701,44 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
|
||||
*/
|
||||
int bm_get_anim_frame(const int frame1_handle, float elapsed_time, const float divisor = 0.0f, const bool loop = false);
|
||||
|
||||
/**
|
||||
* @brief Determines if the given handle could be used in a texture array
|
||||
*
|
||||
* @param handle The handle to query the value for
|
||||
* @return @c true if all frames have the same size, @c false otherwise. Always returns @c true for single images
|
||||
*/
|
||||
bool bm_is_texture_array(const int handle);
|
||||
|
||||
/**
|
||||
* @brief Gets the base frame of the specified animation
|
||||
*
|
||||
* @details The base frame is the frame of the animation that should be used to determine if two animation frames can be
|
||||
* used in the same draw call. Use this if you want to optimize your draw calls to make use of texture arrays.
|
||||
*
|
||||
* @param handle The handle of the animation to check. This may also be a single frame bitmap
|
||||
* @param num_frames Optionally return the number of frames in the animation
|
||||
* @return The bitmap handle of the base frame or -1 on error
|
||||
*/
|
||||
int bm_get_base_frame(const int handle, int* num_frames = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Get the array index of the specified bitmap
|
||||
*
|
||||
* This should be used when passing the array index to the GPU (e.g. when building uniform structs or streaming particle
|
||||
* data)
|
||||
*
|
||||
* @param handle The handle of the bitmap
|
||||
* @return The index into the array
|
||||
*/
|
||||
int bm_get_array_index(const int handle);
|
||||
|
||||
/**
|
||||
* @brief Counts how many slots are used in bm_bitmaps
|
||||
*
|
||||
* This needs to iterate through all the slots in order to determine whether or not they're used, so shouldn't be used frivolously.
|
||||
*
|
||||
* @return The number of used slots
|
||||
*/
|
||||
int bmpman_count_bitmaps();
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "globalincs/alphacolors.h"
|
||||
#include "globalincs/linklist.h"
|
||||
#include "globalincs/systemvars.h" //VM_FREECAMERA etc
|
||||
#include "graphics/font.h"
|
||||
#include "graphics/matrix.h"
|
||||
#include "hud/hud.h" //hud_get_draw
|
||||
#include "math/vecmat.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
|
||||
@@ -88,6 +88,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA },
|
||||
};
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -78,8 +78,9 @@ typedef struct {
|
||||
#define CF_TYPE_INTEL_ANIMS 34
|
||||
#define CF_TYPE_SCRIPTS 35
|
||||
#define CF_TYPE_FICTION 36
|
||||
#define CF_TYPE_FREDDOCS 37
|
||||
|
||||
#define CF_MAX_PATH_TYPES 37 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
|
||||
#define CF_MAX_PATH_TYPES 38 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
|
||||
|
||||
|
||||
// TRUE if type is specified and valid
|
||||
|
||||
@@ -1567,8 +1567,10 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
|
||||
continue;
|
||||
|
||||
char fn[MAX_PATH];
|
||||
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
|
||||
fn[MAX_PATH-1] = 0;
|
||||
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
|
||||
// Make sure the string is null terminated
|
||||
fn[MAX_PATH-1] = 0;
|
||||
}
|
||||
|
||||
struct stat buf;
|
||||
if (stat(fn, &buf) == -1) {
|
||||
@@ -1776,8 +1778,10 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
|
||||
continue;
|
||||
|
||||
char fn[MAX_PATH];
|
||||
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
|
||||
fn[MAX_PATH-1] = 0;
|
||||
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
|
||||
// Make sure the string is null terminated
|
||||
fn[MAX_PATH-1] = 0;
|
||||
}
|
||||
|
||||
struct stat buf;
|
||||
if (stat(fn, &buf) == -1) {
|
||||
@@ -1991,8 +1995,10 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
continue;
|
||||
|
||||
char fn[MAX_PATH];
|
||||
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
|
||||
fn[MAX_PATH-1] = 0;
|
||||
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
|
||||
// Make sure the string is null terminated
|
||||
fn[MAX_PATH-1] = 0;
|
||||
}
|
||||
|
||||
struct stat buf;
|
||||
if (stat(fn, &buf) == -1) {
|
||||
|
||||
+268
-50
@@ -23,6 +23,9 @@
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "osapi/osapi.h"
|
||||
#include "cfile/cfilesystem.h"
|
||||
#include "sound/speech.h"
|
||||
#include "sound/openal.h"
|
||||
#include "io/joy.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
@@ -38,6 +41,9 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstdio>
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
// Stupid windows workaround...
|
||||
#ifdef MessageBox
|
||||
@@ -60,6 +66,11 @@ const char *cmdline_arg_types[] =
|
||||
"STRING",
|
||||
};
|
||||
|
||||
enum class flag_output_type {
|
||||
Binary,
|
||||
Json_V1,
|
||||
};
|
||||
|
||||
// variables
|
||||
class cmdline_parm {
|
||||
public:
|
||||
@@ -78,6 +89,7 @@ public:
|
||||
float get_float();
|
||||
char *str();
|
||||
bool check_if_args_is_valid();
|
||||
bool has_param();
|
||||
};
|
||||
|
||||
static cmdline_parm Parm_list(NULL, NULL, AT_NONE);
|
||||
@@ -177,7 +189,6 @@ Flag exe_params[] =
|
||||
{ "-no_ap_interrupt", "Disable interrupting autopilot", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_ap_interrupt", },
|
||||
{ "-stretch_menu", "Stretch interface to fill screen", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
|
||||
|
||||
{ "-snd_preload", "Preload mission game sounds", true, EASY_MEM_ALL_ON, EASY_DEFAULT_MEM, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-snd_preload", },
|
||||
{ "-nosound", "Disable all sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nosound", },
|
||||
{ "-nomusic", "Disable music", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomusic", },
|
||||
{ "-no_enhanced_sound", "Disable enhanced sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_enhanced_sound", },
|
||||
@@ -218,6 +229,7 @@ Flag exe_params[] =
|
||||
{ "-voicer", "Enable voice recognition", true, 0, EASY_DEFAULT, "Experimental", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-voicer", },
|
||||
|
||||
{ "-fps", "Show frames per second on HUD", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fps", },
|
||||
{ "-bmpmanusage", "Show how many BMPMAN slots are in use", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-bmpmanusage", },
|
||||
{ "-pos", "Show position of camera", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-pos", },
|
||||
{ "-window", "Run in window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-window", },
|
||||
{ "-fullscreen_window", "Run in fullscreen window", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fullscreen_window", },
|
||||
@@ -393,11 +405,9 @@ int Cmdline_stretch_menu = 0;
|
||||
|
||||
// Audio related
|
||||
cmdline_parm query_speech_arg("-query_speech", NULL, AT_NONE); // Cmdline_query_speech
|
||||
cmdline_parm snd_preload_arg("-snd_preload", NULL, AT_NONE); // Cmdline_snd_preload
|
||||
cmdline_parm voice_recognition_arg("-voicer", NULL, AT_NONE); // Cmdline_voice_recognition
|
||||
|
||||
int Cmdline_query_speech = 0;
|
||||
int Cmdline_snd_preload = 0; // preload game sounds during mission load
|
||||
int Cmdline_voice_recognition = 0;
|
||||
int Cmdline_no_enhanced_sound = 0;
|
||||
|
||||
@@ -472,6 +482,7 @@ cmdline_parm dis_weapons("-dis_weapons", NULL, AT_NONE); // Cmdline_dis_weapons
|
||||
cmdline_parm noparseerrors_arg("-noparseerrors", NULL, AT_NONE); // Cmdline_noparseerrors -- turns off parsing errors -C
|
||||
cmdline_parm extra_warn_arg("-extra_warn", "Enable 'extra' warnings", AT_NONE); // Cmdline_extra_warn
|
||||
cmdline_parm fps_arg("-fps", NULL, AT_NONE); // Cmdline_show_fps
|
||||
cmdline_parm bmpmanusage_arg("-bmpmanusage", NULL, AT_NONE); // Cmdline_bmpman_usage
|
||||
cmdline_parm pos_arg("-pos", NULL, AT_NONE); // Cmdline_show_pos
|
||||
cmdline_parm stats_arg("-stats", NULL, AT_NONE); // Cmdline_show_stats
|
||||
cmdline_parm save_render_targets_arg("-save_render_target", NULL, AT_NONE); // Cmdline_save_render_targets
|
||||
@@ -502,6 +513,7 @@ int Cmdline_noparseerrors = 0;
|
||||
int Cmdline_nowarn = 0; // turn warnings off in FRED
|
||||
#endif
|
||||
int Cmdline_extra_warn = 0;
|
||||
int Cmdline_bmpman_usage = 0;
|
||||
int Cmdline_show_pos = 0;
|
||||
int Cmdline_show_stats = 0;
|
||||
int Cmdline_save_render_targets = 0;
|
||||
@@ -522,7 +534,7 @@ bool Cmdline_show_video_info = false;
|
||||
bool Cmdline_debug_window = false;
|
||||
|
||||
// Other
|
||||
cmdline_parm get_flags_arg("-get_flags", "Output the launcher flags file", AT_NONE);
|
||||
cmdline_parm get_flags_arg("-get_flags", "Output the launcher flags file", AT_STRING);
|
||||
cmdline_parm output_sexp_arg("-output_sexps", NULL, AT_NONE); //WMC - outputs all SEXPs to sexps.html
|
||||
cmdline_parm output_scripting_arg("-output_scripting", NULL, AT_NONE); //WMC
|
||||
|
||||
@@ -535,6 +547,7 @@ cmdline_parm deprecated_tbp_arg("-tbp", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_jpgtga_arg("-jpgtga", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_htl_arg("-nohtl", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_brieflighting_arg("-brief_lighting", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_sndpreload_arg("-snd_preload", "Deprecated", AT_NONE);
|
||||
|
||||
int Cmdline_deprecated_spec = 0;
|
||||
int Cmdline_deprecated_glow = 0;
|
||||
@@ -1143,6 +1156,9 @@ char *cmdline_parm::str()
|
||||
|
||||
return args;
|
||||
}
|
||||
bool cmdline_parm::has_param() {
|
||||
return args != nullptr;
|
||||
}
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
// Return a vector with all filesystem names of "parent/dir" relative to parent.
|
||||
@@ -1241,6 +1257,248 @@ static void handle_unix_modlist(char **modlist, size_t *len)
|
||||
|
||||
// external entry point into this modules
|
||||
|
||||
static json_t* json_get_v1() {
|
||||
auto root = json_object();
|
||||
|
||||
{
|
||||
auto version_obj = json_object();
|
||||
|
||||
json_object_set_new(version_obj, "full", json_string(FS_VERSION_FULL));
|
||||
json_object_set_new(version_obj, "major", json_integer(FS_VERSION_MAJOR));
|
||||
json_object_set_new(version_obj, "minor", json_integer(FS_VERSION_MINOR));
|
||||
json_object_set_new(version_obj, "build", json_integer(FS_VERSION_BUILD));
|
||||
|
||||
json_object_set_new(version_obj, "has_revision", json_boolean(FS_VERSION_HAS_REVIS));
|
||||
json_object_set_new(version_obj, "revision", json_integer(FS_VERSION_REVIS));
|
||||
json_object_set_new(version_obj, "revision_str", json_string(FS_VERSION_REVIS_STR));
|
||||
|
||||
json_object_set_new(root, "version", version_obj);
|
||||
}
|
||||
{
|
||||
auto easy_array = json_array();
|
||||
|
||||
for (auto& easy_flag : easy_flags) {
|
||||
json_array_append_new(easy_array, json_string(easy_flag.name));
|
||||
}
|
||||
|
||||
json_object_set_new(root, "easy_flags", easy_array);
|
||||
}
|
||||
{
|
||||
auto flags_array = json_array();
|
||||
|
||||
for (auto& flag : exe_params) {
|
||||
auto flag_obj = json_object();
|
||||
|
||||
json_object_set_new(flag_obj, "name", json_string(flag.name));
|
||||
json_object_set_new(flag_obj, "description", json_string(flag.desc));
|
||||
json_object_set_new(flag_obj, "fso_only", json_boolean(flag.fso_only));
|
||||
json_object_set_new(flag_obj, "on_flags", json_integer(flag.on_flags));
|
||||
json_object_set_new(flag_obj, "off_flags", json_integer(flag.off_flags));
|
||||
json_object_set_new(flag_obj, "type", json_string(flag.type));
|
||||
json_object_set_new(flag_obj, "web_url", json_string(flag.web_url));
|
||||
|
||||
json_array_append_new(flags_array, flag_obj);
|
||||
}
|
||||
|
||||
json_object_set_new(root, "flags", flags_array);
|
||||
}
|
||||
{
|
||||
auto caps_array = json_array();
|
||||
|
||||
json_array_append_new(caps_array, json_string("OpenAL"));
|
||||
json_array_append_new(caps_array, json_string("No D3D"));
|
||||
json_array_append_new(caps_array, json_string("New Sound"));
|
||||
json_array_append_new(caps_array, json_string("SDL"));
|
||||
|
||||
json_object_set_new(root, "caps", caps_array);
|
||||
}
|
||||
{
|
||||
auto voices_array = json_array();
|
||||
|
||||
auto voices = speech_enumerate_voices();
|
||||
|
||||
for (auto& voice : voices) {
|
||||
json_array_append_new(voices_array, json_string(voice.c_str()));
|
||||
}
|
||||
|
||||
json_object_set_new(root, "voices", voices_array);
|
||||
}
|
||||
{
|
||||
auto resolution_array = json_array();
|
||||
|
||||
auto displays = gr_enumerate_displays();
|
||||
|
||||
for (auto& display : displays) {
|
||||
auto display_obj = json_object();
|
||||
|
||||
json_object_set_new(display_obj, "index", json_integer(display.index));
|
||||
json_object_set_new(display_obj, "name", json_string(display.name.c_str()));
|
||||
|
||||
json_object_set_new(display_obj, "x", json_integer(display.x));
|
||||
json_object_set_new(display_obj, "y", json_integer(display.y));
|
||||
json_object_set_new(display_obj, "width", json_integer(display.width));
|
||||
json_object_set_new(display_obj, "height", json_integer(display.height));
|
||||
|
||||
auto modes_array = json_array();
|
||||
|
||||
for (auto& mode : display.video_modes) {
|
||||
auto mode_obj = json_object();
|
||||
|
||||
json_object_set_new(mode_obj, "x", json_integer(mode.width));
|
||||
json_object_set_new(mode_obj, "y", json_integer(mode.height));
|
||||
json_object_set_new(mode_obj, "bits", json_integer(mode.bit_depth));
|
||||
|
||||
json_array_append_new(modes_array, mode_obj);
|
||||
}
|
||||
|
||||
json_object_set_new(display_obj, "modes", modes_array);
|
||||
|
||||
json_array_append_new(resolution_array, display_obj);
|
||||
}
|
||||
|
||||
json_object_set_new(root, "displays", resolution_array);
|
||||
}
|
||||
{
|
||||
auto openal_obj = json_object();
|
||||
|
||||
auto openal_info = openal_get_platform_information();
|
||||
|
||||
json_object_set_new(openal_obj, "version_major", json_integer(openal_info.version_major));
|
||||
json_object_set_new(openal_obj, "version_minor", json_integer(openal_info.version_minor));
|
||||
|
||||
json_object_set(openal_obj, "default_playback", json_string(openal_info.default_playback_device.c_str()));
|
||||
json_object_set(openal_obj, "default_capture", json_string(openal_info.default_capture_device.c_str()));
|
||||
|
||||
{
|
||||
auto playback_array = json_array();
|
||||
|
||||
for (auto& device : openal_info.playback_devices) {
|
||||
json_array_append_new(playback_array, json_string(device.c_str()));
|
||||
}
|
||||
|
||||
json_object_set_new(openal_obj, "playback_devices", playback_array);
|
||||
}
|
||||
{
|
||||
auto capture_array = json_array();
|
||||
|
||||
for (auto& device : openal_info.capture_devices) {
|
||||
json_array_append_new(capture_array, json_string(device.c_str()));
|
||||
}
|
||||
|
||||
json_object_set_new(openal_obj, "capture_devices", capture_array);
|
||||
}
|
||||
|
||||
json_object_set_new(root, "openal", openal_obj);
|
||||
}
|
||||
{
|
||||
auto joystick_array = json_array();
|
||||
|
||||
auto joysticks = io::joystick::getJoystickInformations();
|
||||
for (auto& info : joysticks) {
|
||||
auto joystick_obj = json_object();
|
||||
|
||||
json_object_set_new(joystick_obj, "name", json_string(info.name.c_str()));
|
||||
json_object_set_new(joystick_obj, "guid", json_string(info.guid.c_str()));
|
||||
|
||||
json_object_set_new(joystick_obj, "num_axes", json_integer(info.num_axes));
|
||||
json_object_set_new(joystick_obj, "num_balls", json_integer(info.num_balls));
|
||||
json_object_set_new(joystick_obj, "num_buttons", json_integer(info.num_buttons));
|
||||
json_object_set_new(joystick_obj, "num_hats", json_integer(info.num_hats));
|
||||
|
||||
json_object_set_new(joystick_obj, "is_haptic", json_boolean(info.is_haptic));
|
||||
|
||||
json_array_append_new(joystick_array, joystick_obj);
|
||||
}
|
||||
|
||||
json_object_set_new(root, "joysticks", joystick_array);
|
||||
}
|
||||
{
|
||||
json_object_set_new(root, "pref_path", json_string(os_get_config_path().c_str()));
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
static void write_flags_file() {
|
||||
FILE *fp = fopen("flags.lch","w");
|
||||
|
||||
if (fp == NULL) {
|
||||
os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "Error creating flag list for launcher");
|
||||
return;
|
||||
}
|
||||
|
||||
int easy_flag_size = sizeof(EasyFlag);
|
||||
int flag_size = sizeof(Flag);
|
||||
|
||||
int num_easy_flags = sizeof(easy_flags) / easy_flag_size;
|
||||
int num_flags = sizeof(exe_params) / flag_size;
|
||||
|
||||
// Launcher will check its using structures of the same size
|
||||
fwrite(&easy_flag_size, sizeof(int), 1, fp);
|
||||
fwrite(&flag_size, sizeof(int), 1, fp);
|
||||
|
||||
fwrite(&num_easy_flags, sizeof(int), 1, fp);
|
||||
fwrite(&easy_flags, sizeof(easy_flags), 1, fp);
|
||||
|
||||
fwrite(&num_flags, sizeof(int), 1, fp);
|
||||
fwrite(&exe_params, sizeof(exe_params), 1, fp);
|
||||
|
||||
{
|
||||
// cheap and bastardly cap check for builds
|
||||
// (needs to be compatible with older Launchers, which means having
|
||||
// this implies an OpenAL build for old Launchers)
|
||||
ubyte build_caps = 0;
|
||||
|
||||
/* portej05 defined this always */
|
||||
build_caps |= BUILD_CAPS_OPENAL;
|
||||
build_caps |= BUILD_CAPS_NO_D3D;
|
||||
build_caps |= BUILD_CAPS_NEW_SND;
|
||||
build_caps |= BUILD_CAPS_SDL;
|
||||
|
||||
fwrite(&build_caps, 1, 1, fp);
|
||||
}
|
||||
|
||||
fflush(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static flag_output_type get_flags_output_type() {
|
||||
Assertion(get_flags_arg.found(), "This function is only valid if -get_flags is present!");
|
||||
|
||||
if (!get_flags_arg.has_param()) {
|
||||
// Default to binary mode
|
||||
return flag_output_type::Binary;
|
||||
}
|
||||
|
||||
SCP_string type(get_flags_arg.str());
|
||||
|
||||
if (type == "binary") {
|
||||
return flag_output_type::Binary;
|
||||
} else if (type == "json_v1") {
|
||||
return flag_output_type::Json_V1;
|
||||
} else {
|
||||
// This is supposed to make it easy for the launcher to recognize an unsupported type
|
||||
printf("OUTPUT TYPE NOT SUPPORTED!\n");
|
||||
// Default to json in this case so that no flags.lch file is created
|
||||
return flag_output_type::Json_V1;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_flags() {
|
||||
auto type = get_flags_output_type();
|
||||
switch(type) {
|
||||
case flag_output_type::Binary:
|
||||
write_flags_file();
|
||||
break;
|
||||
case flag_output_type::Json_V1:
|
||||
json_t* root = json_get_v1();
|
||||
|
||||
json_dumpf(root, stdout, JSON_INDENT(4));
|
||||
json_decref(root);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SetCmdlineParams()
|
||||
// Sets externed variables used for communication cmdline information
|
||||
{
|
||||
@@ -1248,47 +1506,7 @@ bool SetCmdlineParams()
|
||||
|
||||
// DO THIS FIRST to avoid unrecognized flag warnings when just getting flag file
|
||||
if ( get_flags_arg.found() ) {
|
||||
FILE *fp = fopen("flags.lch","w");
|
||||
|
||||
if (fp == NULL) {
|
||||
os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "Error creating flag list for launcher");
|
||||
return false;
|
||||
}
|
||||
|
||||
int easy_flag_size = sizeof(EasyFlag);
|
||||
int flag_size = sizeof(Flag);
|
||||
|
||||
int num_easy_flags = sizeof(easy_flags) / easy_flag_size;
|
||||
int num_flags = sizeof(exe_params) / flag_size;
|
||||
|
||||
// Launcher will check its using structures of the same size
|
||||
fwrite(&easy_flag_size, sizeof(int), 1, fp);
|
||||
fwrite(&flag_size, sizeof(int), 1, fp);
|
||||
|
||||
fwrite(&num_easy_flags, sizeof(int), 1, fp);
|
||||
fwrite(&easy_flags, sizeof(easy_flags), 1, fp);
|
||||
|
||||
fwrite(&num_flags, sizeof(int), 1, fp);
|
||||
fwrite(&exe_params, sizeof(exe_params), 1, fp);
|
||||
|
||||
{
|
||||
// cheap and bastardly cap check for builds
|
||||
// (needs to be compatible with older Launchers, which means having
|
||||
// this implies an OpenAL build for old Launchers)
|
||||
ubyte build_caps = 0;
|
||||
|
||||
/* portej05 defined this always */
|
||||
build_caps |= BUILD_CAPS_OPENAL;
|
||||
build_caps |= BUILD_CAPS_NO_D3D;
|
||||
build_caps |= BUILD_CAPS_NEW_SND;
|
||||
build_caps |= BUILD_CAPS_SDL;
|
||||
|
||||
|
||||
fwrite(&build_caps, 1, 1, fp);
|
||||
}
|
||||
|
||||
fflush(fp);
|
||||
fclose(fp);
|
||||
write_flags();
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1541,6 +1759,11 @@ bool SetCmdlineParams()
|
||||
Show_framerate = 1;
|
||||
}
|
||||
|
||||
if (bmpmanusage_arg.found())
|
||||
{
|
||||
Cmdline_bmpman_usage = 1;
|
||||
}
|
||||
|
||||
if(pos_arg.found())
|
||||
{
|
||||
Cmdline_show_pos = 1;
|
||||
@@ -1721,11 +1944,6 @@ bool SetCmdlineParams()
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( snd_preload_arg.found() )
|
||||
{
|
||||
Cmdline_snd_preload = 1;
|
||||
}
|
||||
|
||||
if ( env.found() ) {
|
||||
Cmdline_env = 0;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,6 @@ extern int Cmdline_stretch_menu;
|
||||
|
||||
// Audio related
|
||||
extern int Cmdline_query_speech;
|
||||
extern int Cmdline_snd_preload;
|
||||
extern int Cmdline_voice_recognition;
|
||||
extern int Cmdline_no_enhanced_sound;
|
||||
|
||||
@@ -148,6 +147,7 @@ extern int Cmdline_dis_collisions;
|
||||
extern int Cmdline_dis_weapons;
|
||||
extern int Cmdline_noparseerrors;
|
||||
extern int Cmdline_extra_warn;
|
||||
extern int Cmdline_bmpman_usage;
|
||||
extern int Cmdline_show_pos;
|
||||
extern int Cmdline_show_stats;
|
||||
extern int Cmdline_save_render_targets;
|
||||
|
||||
@@ -92,7 +92,7 @@ void cmeasure_maybe_alert_success(object *objp)
|
||||
|
||||
if ( objp->parent == OBJ_INDEX(Player_obj) ) {
|
||||
hud_start_text_flash(XSTR("Evaded", 1430), 800);
|
||||
snd_play(&Snds[ship_get_sound(Player_obj, SND_MISSILE_EVADED_POPUP)]);
|
||||
snd_play(gamesnd_get_game_sound(ship_get_sound(Player_obj, SND_MISSILE_EVADED_POPUP)));
|
||||
} else if ( Objects[objp->parent].flags[Object::Object_Flags::Player_ship] ) {
|
||||
send_countermeasure_success_packet( objp->parent );
|
||||
}
|
||||
|
||||
@@ -14,6 +14,11 @@ bool Decoder::tryPopAudioData(AudioFramePtr& out) {
|
||||
return res == queue_op_status::success;
|
||||
}
|
||||
|
||||
bool Decoder::tryPopSubtitleData(SubtitleFramePtr& out) {
|
||||
auto res = m_subtitleQueue->try_pull_front(out);
|
||||
return res == queue_op_status::success;
|
||||
}
|
||||
|
||||
bool Decoder::tryPopVideoFrame(VideoFramePtr& out) {
|
||||
auto res = m_videoQueue->try_pull_front(out);
|
||||
return res == queue_op_status::success;
|
||||
@@ -24,6 +29,7 @@ void Decoder::initializeQueues(size_t queueSize) {
|
||||
|
||||
m_videoQueue.reset(new sync_bounded_queue<VideoFramePtr>(m_queueSize));
|
||||
m_audioQueue.reset(new sync_bounded_queue<AudioFramePtr>(m_queueSize));
|
||||
m_subtitleQueue.reset(new sync_bounded_queue<SubtitleFramePtr>(m_queueSize));
|
||||
}
|
||||
|
||||
void Decoder::stopDecoder() {
|
||||
@@ -31,6 +37,7 @@ void Decoder::stopDecoder() {
|
||||
|
||||
m_videoQueue->close();
|
||||
m_audioQueue->close();
|
||||
m_subtitleQueue->close();
|
||||
}
|
||||
|
||||
bool Decoder::canPushAudioData() {
|
||||
@@ -48,6 +55,20 @@ void Decoder::pushAudioData(AudioFramePtr&& data) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Decoder::canPushSubtitleData() {
|
||||
return !isSubtitleQueueFull();
|
||||
}
|
||||
void Decoder::pushSubtitleData(SubtitleFramePtr&& data) {
|
||||
Assertion(data, "Invalid audio data passed!");
|
||||
|
||||
try {
|
||||
m_subtitleQueue->push_back(std::move(data));
|
||||
}
|
||||
catch (sync_queue_is_closed&) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
bool Decoder::canPushVideoData() {
|
||||
return !isVideoQueueFull();
|
||||
}
|
||||
|
||||
@@ -58,6 +58,14 @@ struct AudioFrame {
|
||||
};
|
||||
typedef std::unique_ptr<AudioFrame> AudioFramePtr;
|
||||
|
||||
struct SubtitleFrame {
|
||||
double displayStartTime = -1.0;
|
||||
double displayEndTime = -1.0;
|
||||
|
||||
SCP_string text;
|
||||
};
|
||||
typedef std::unique_ptr<SubtitleFrame> SubtitleFramePtr;
|
||||
|
||||
/**
|
||||
* @brief Abstract class for decoding a video or audio stream
|
||||
*
|
||||
@@ -68,6 +76,7 @@ class Decoder {
|
||||
private:
|
||||
std::unique_ptr<sync_bounded_queue<VideoFramePtr>> m_videoQueue;
|
||||
std::unique_ptr<sync_bounded_queue<AudioFramePtr>> m_audioQueue;
|
||||
std::unique_ptr<sync_bounded_queue<SubtitleFramePtr>> m_subtitleQueue;
|
||||
|
||||
bool m_decoding;
|
||||
size_t m_queueSize = 0;
|
||||
@@ -109,6 +118,8 @@ class Decoder {
|
||||
*/
|
||||
virtual bool hasAudio() = 0;
|
||||
|
||||
virtual bool hasSubtitles() = 0;
|
||||
|
||||
/**
|
||||
* @brief Ends decoding of the video file
|
||||
*/
|
||||
@@ -122,6 +133,14 @@ class Decoder {
|
||||
|
||||
bool tryPopAudioData(AudioFramePtr&);
|
||||
|
||||
bool isSubtitleQueueFull() { return m_subtitleQueue->size() == m_queueSize; }
|
||||
|
||||
bool isSubtitleFrameAvailable() { return !m_subtitleQueue->empty(); }
|
||||
|
||||
size_t getSubtitleQueueSize() { return m_subtitleQueue->size(); }
|
||||
|
||||
bool tryPopSubtitleData(SubtitleFramePtr&);
|
||||
|
||||
bool isVideoQueueFull() { return m_videoQueue->size() == m_queueSize; }
|
||||
|
||||
bool isVideoFrameAvailable() { return !m_videoQueue->empty(); }
|
||||
@@ -141,6 +160,10 @@ class Decoder {
|
||||
|
||||
void pushAudioData(AudioFramePtr&& data);
|
||||
|
||||
bool canPushSubtitleData();
|
||||
|
||||
void pushSubtitleData(SubtitleFramePtr&& data);
|
||||
|
||||
bool canPushVideoData();
|
||||
|
||||
void pushFrameData(VideoFramePtr&& frame);
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "VideoPresenter.h"
|
||||
|
||||
#include "graphics/matrix.h"
|
||||
|
||||
using namespace cutscene;
|
||||
using namespace cutscene::player;
|
||||
|
||||
namespace {
|
||||
struct movie_vertex {
|
||||
vec2d pos;
|
||||
vec2d uv;
|
||||
};
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
VideoPresenter::VideoPresenter(const MovieProperties& props) {
|
||||
GR_DEBUG_SCOPE("Init video");
|
||||
|
||||
auto w = static_cast<int>(props.size.width);
|
||||
auto h = static_cast<int>(props.size.height);
|
||||
|
||||
// Create buffer textures
|
||||
_yTexBuffer.reset(new uint8_t[w * h]);
|
||||
_ytex = bm_create(8, w, h, _yTexBuffer.get(), BMP_AABITMAP);
|
||||
|
||||
_uTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
|
||||
_utex = bm_create(8, w / 2, h / 2, _uTexBuffer.get(), BMP_AABITMAP);
|
||||
|
||||
_vTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
|
||||
_vtex = bm_create(8, w / 2, h / 2, _vTexBuffer.get(), BMP_AABITMAP);
|
||||
|
||||
material_set_movie(&_render_material, _ytex, _utex, _vtex);
|
||||
}
|
||||
|
||||
VideoPresenter::~VideoPresenter() {
|
||||
GR_DEBUG_SCOPE("Deinit video");
|
||||
|
||||
bm_release(_ytex);
|
||||
bm_release(_utex);
|
||||
bm_release(_vtex);
|
||||
|
||||
_ytex = _utex = _vtex = -1;
|
||||
}
|
||||
|
||||
void VideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
|
||||
GR_DEBUG_SCOPE("Update video frame");
|
||||
auto ptrs = frame->getDataPointers();
|
||||
|
||||
memcpy(_yTexBuffer.get(), ptrs.y, frame->ySize.stride * frame->ySize.height);
|
||||
memcpy(_uTexBuffer.get(), ptrs.u, frame->uvSize.stride * frame->uvSize.height);
|
||||
memcpy(_vTexBuffer.get(), ptrs.v, frame->uvSize.stride * frame->uvSize.height);
|
||||
|
||||
gr_update_texture(_ytex, 8, _yTexBuffer.get(), (int) frame->ySize.width, (int) frame->ySize.height);
|
||||
gr_update_texture(_utex, 8, _uTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
|
||||
gr_update_texture(_vtex, 8, _vTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
|
||||
}
|
||||
|
||||
void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
|
||||
GR_DEBUG_SCOPE("Draw video frame");
|
||||
|
||||
movie_vertex vertex_data[4];
|
||||
|
||||
vertex_data[0].pos.x = x1;
|
||||
vertex_data[0].pos.y = y1;
|
||||
vertex_data[0].uv.x = 0.0f;
|
||||
vertex_data[0].uv.y = 0.0f;
|
||||
|
||||
vertex_data[1].pos.x = x1;
|
||||
vertex_data[1].pos.y = y2;
|
||||
vertex_data[1].uv.x = 0.0f;
|
||||
vertex_data[1].uv.y = 1.0f;
|
||||
|
||||
vertex_data[2].pos.x = x2;
|
||||
vertex_data[2].pos.y = y1;
|
||||
vertex_data[2].uv.x = 1.0f;
|
||||
vertex_data[2].uv.y = 0.0f;
|
||||
|
||||
vertex_data[3].pos.x = x2;
|
||||
vertex_data[3].pos.y = y2;
|
||||
vertex_data[3].uv.x = 1.0f;
|
||||
vertex_data[3].uv.y = 1.0f;
|
||||
|
||||
// Use the immediate buffer for storing our data since that is exactly what we need
|
||||
auto offset = gr_add_to_immediate_buffer(sizeof(vertex_data), vertex_data);
|
||||
|
||||
vertex_layout layout;
|
||||
layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, pos));
|
||||
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, uv));
|
||||
|
||||
gr_render_movie(&_render_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
#define FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/material.h"
|
||||
#include "cutscene/Decoder.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
|
||||
class VideoPresenter {
|
||||
int _ytex = -1;
|
||||
std::unique_ptr<uint8_t[]> _yTexBuffer;
|
||||
|
||||
int _utex = -1;
|
||||
std::unique_ptr<uint8_t[]> _uTexBuffer;
|
||||
|
||||
int _vtex = -1;
|
||||
std::unique_ptr<uint8_t[]> _vTexBuffer;
|
||||
|
||||
movie_material _render_material;
|
||||
public:
|
||||
explicit VideoPresenter(const MovieProperties& props);
|
||||
|
||||
// Disallow copying
|
||||
VideoPresenter(const VideoPresenter&) = delete;
|
||||
VideoPresenter& operator=(const VideoPresenter&) = delete;
|
||||
|
||||
virtual ~VideoPresenter();
|
||||
|
||||
void uploadVideoFrame(const VideoFramePtr& frame);
|
||||
|
||||
void displayFrame(float x1, float y1, float x2, float y2);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
@@ -9,6 +9,9 @@
|
||||
|
||||
#include "cutscene/ffmpeg/AudioDecoder.h"
|
||||
#include "cutscene/ffmpeg/VideoDecoder.h"
|
||||
#include "cutscene/ffmpeg/SubtitleDecoder.h"
|
||||
|
||||
#include "localization/localize.h"
|
||||
|
||||
using namespace libs::ffmpeg;
|
||||
|
||||
@@ -62,6 +65,8 @@ CodecContextParameters getCodecParameters(AVStream* stream) {
|
||||
paras.channel_layout = stream->codecpar->channel_layout;
|
||||
paras.sample_rate = stream->codecpar->sample_rate;
|
||||
paras.audio_format = (AVSampleFormat)stream->codecpar->format;
|
||||
|
||||
paras.codec_id = stream->codecpar->codec_id;
|
||||
#else
|
||||
paras.width = stream->codec->width;
|
||||
paras.height = stream->codec->height;
|
||||
@@ -70,9 +75,29 @@ CodecContextParameters getCodecParameters(AVStream* stream) {
|
||||
paras.channel_layout = stream->codec->channel_layout;
|
||||
paras.sample_rate = stream->codec->sample_rate;
|
||||
paras.audio_format = stream->codec->sample_fmt;
|
||||
|
||||
paras.codec_id = stream->codec->codec_id;
|
||||
#endif
|
||||
return paras;
|
||||
}
|
||||
|
||||
SCP_string normalizeLanguage(const char* langauge_name) {
|
||||
if (!stricmp(langauge_name, "eng")) {
|
||||
return "English";
|
||||
}
|
||||
if (!stricmp(langauge_name, "ger")) {
|
||||
return "German";
|
||||
}
|
||||
if (!stricmp(langauge_name, "spa")) {
|
||||
return "Spanish";
|
||||
}
|
||||
|
||||
// Print to log so that we can find the actual value more easily later
|
||||
mprintf(("FFmpeg log: Found unknown language value '%s'!\n", langauge_name));
|
||||
|
||||
// Default to english for everything else
|
||||
return "English";
|
||||
}
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
@@ -155,7 +180,30 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
|
||||
status->audioStream = ctx->streams[audioStream];
|
||||
}
|
||||
|
||||
status->videoCodecPars = getCodecParameters(status->videoStream);
|
||||
auto& current_language = Lcl_languages[Lcl_current_lang];
|
||||
for (uint32_t i = 0; i < ctx->nb_streams; ++i) {
|
||||
auto test_stream = ctx->streams[i];
|
||||
|
||||
auto& pars = test_stream->codecpar;
|
||||
|
||||
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
|
||||
continue;
|
||||
}
|
||||
AVDictionaryEntry* tag = nullptr;
|
||||
if ((tag = av_dict_get(test_stream->metadata, "language", nullptr, 0)) == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto normalized_language = normalizeLanguage(tag->value);
|
||||
|
||||
if (!stricmp(normalized_language.c_str(), current_language.lang_name)) {
|
||||
status->subtitleStreamIndex = i;
|
||||
status->subtitleStream = test_stream;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
status->videoCodecPars = getCodecParameters(status->videoStream);
|
||||
|
||||
int err;
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
@@ -213,6 +261,37 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
|
||||
status->audioCodec->name ? status->audioCodec->name : "<Unknown>"));
|
||||
}
|
||||
|
||||
if (status->subtitleStreamIndex >= 0) {
|
||||
// Not really sure if this makes sense for subtitles but it shouldn't break anything...
|
||||
status->subtitleCodecPars = getCodecParameters(status->subtitleStream);
|
||||
|
||||
status->subtitleCodec = avcodec_find_decoder(status->subtitleCodecPars.codec_id);
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
status->subtitleCodecCtx = avcodec_alloc_context3(status->subtitleCodec);
|
||||
|
||||
err = avcodec_parameters_to_context(status->subtitleCodecCtx, status->subtitleStream->codecpar);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to copy context parameters! Error: %s\n", errorStr));
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
status->subtitleCodecCtx = status->subtitleStream->codec;
|
||||
#endif
|
||||
|
||||
err = avcodec_open2(status->subtitleCodecCtx, status->subtitleCodec, nullptr);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to open subtitle codec! Error: %s\n", errorStr));
|
||||
}
|
||||
|
||||
mprintf(("FFmpeg: Using subtitle codec %s (%s).\n", status->subtitleCodec->long_name ? status->subtitleCodec->long_name : "<Unknown>",
|
||||
status->subtitleCodec->name ? status->subtitleCodec->name : "<Unknown>"));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -279,10 +358,14 @@ void FFMPEGDecoder::startDecoding() {
|
||||
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get()));
|
||||
|
||||
std::unique_ptr<AudioDecoder> audioDecoder;
|
||||
std::unique_ptr<SubtitleDecoder> subtitleDecoder;
|
||||
|
||||
if (hasAudio()) {
|
||||
audioDecoder.reset(new AudioDecoder(m_status.get()));
|
||||
}
|
||||
if (hasSubtitles()) {
|
||||
subtitleDecoder.reset(new SubtitleDecoder(m_status.get()));
|
||||
}
|
||||
|
||||
auto ctx = m_input->m_ctx->ctx();
|
||||
AVPacket packet;
|
||||
@@ -322,7 +405,14 @@ void FFMPEGDecoder::startDecoding() {
|
||||
while ((ptr = audioDecoder->getFrame()) != nullptr) {
|
||||
pushAudioData(std::move(ptr));
|
||||
}
|
||||
}
|
||||
} else if (subtitleDecoder && packet.stream_index == m_status->subtitleStreamIndex) {
|
||||
subtitleDecoder->decodePacket(&packet);
|
||||
|
||||
SubtitleFramePtr ptr;
|
||||
while((ptr = subtitleDecoder->getFrame()) != nullptr) {
|
||||
pushSubtitleData(std::move(ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isDecoding()) {
|
||||
@@ -349,6 +439,10 @@ bool FFMPEGDecoder::hasAudio() {
|
||||
return m_status->audioStreamIndex >= 0;
|
||||
}
|
||||
|
||||
bool FFMPEGDecoder::hasSubtitles() {
|
||||
return m_status->subtitleStreamIndex >= 0;
|
||||
}
|
||||
|
||||
void FFMPEGDecoder::close() {
|
||||
if (m_status) {
|
||||
m_status = nullptr;
|
||||
|
||||
@@ -27,6 +27,8 @@ class FFMPEGDecoder: public Decoder {
|
||||
|
||||
bool hasAudio() SCP_OVERRIDE;
|
||||
|
||||
bool hasSubtitles() SCP_OVERRIDE;
|
||||
|
||||
void close() SCP_OVERRIDE;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
//
|
||||
//
|
||||
|
||||
#include "SubtitleDecoder.h"
|
||||
|
||||
namespace {
|
||||
|
||||
double getFrameTime(int64_t pts, AVRational time_base) {
|
||||
return pts * av_q2d(time_base);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
|
||||
SubtitleDecoder::SubtitleDecoder(cutscene::ffmpeg::DecoderStatus* status) : FFMPEGStreamDecoder(status) {
|
||||
}
|
||||
SubtitleDecoder::~SubtitleDecoder() {
|
||||
|
||||
}
|
||||
void SubtitleDecoder::decodePacket(AVPacket* packet) {
|
||||
int finishedFrame = 0;
|
||||
AVSubtitle subtitle;
|
||||
auto result = avcodec_decode_subtitle2(m_status->subtitleCodecCtx, &subtitle, &finishedFrame, packet);
|
||||
|
||||
if (result >= 0 && finishedFrame) {
|
||||
pushSubtitleFrame(packet, &subtitle);
|
||||
|
||||
avsubtitle_free(&subtitle);
|
||||
}
|
||||
}
|
||||
void SubtitleDecoder::finishDecoding() {
|
||||
|
||||
}
|
||||
void SubtitleDecoder::pushSubtitleFrame(AVPacket* packet, AVSubtitle* subtitle) {
|
||||
if (subtitle->format != 1) {
|
||||
// Non-text subtitles are not supported yet.
|
||||
mprintf(("FFmpeg: Detected a non-text subtitle! This is not supported yet!\n"));
|
||||
return;
|
||||
}
|
||||
if (subtitle->num_rects < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t pts = subtitle->pts;
|
||||
if (pts == AV_NOPTS_VALUE) {
|
||||
pts = packet->pts;
|
||||
}
|
||||
if (pts == AV_NOPTS_VALUE) {
|
||||
// Still no valid timestamp...
|
||||
return;
|
||||
}
|
||||
auto packet_time = getFrameTime(pts, m_status->subtitleStream->time_base);
|
||||
|
||||
auto start_time = packet_time + (subtitle->start_display_time / 1000.0);
|
||||
auto end_time = packet_time + (subtitle->end_display_time / 1000.0);
|
||||
if (subtitle->end_display_time == 0 && m_status->subtitleStream->time_base.num != 0) {
|
||||
end_time = packet_time + getFrameTime(packet->duration, m_status->subtitleStream->time_base);
|
||||
}
|
||||
|
||||
SCP_string processed_text;
|
||||
// For now we only use the first subtitle rectangle
|
||||
auto subtitle_rect = subtitle->rects[0];
|
||||
if (subtitle_rect->type == SUBTITLE_BITMAP) {
|
||||
// Same as above, non-text subtitles are not supported yet.
|
||||
mprintf(("FFmpeg: Detected a non-text subtitle! This is not supported yet!\n"));
|
||||
return;
|
||||
} else if (subtitle_rect->type == SUBTITLE_TEXT) {
|
||||
// Subtitle does not need to be processed any further
|
||||
processed_text = subtitle_rect->text;
|
||||
} else if (subtitle_rect->type == SUBTITLE_ASS) {
|
||||
SCP_string ass_text = subtitle_rect->ass;
|
||||
|
||||
// We are not interested in any of the other information contained in the ASS line but we still need to figure
|
||||
// out where our text starts
|
||||
auto comma_pos = ass_text.find(',');
|
||||
for (auto i = 0; i < 8 && comma_pos != SCP_string::npos; ++i) {
|
||||
comma_pos = ass_text.find(',', comma_pos + 1);
|
||||
}
|
||||
Assertion(comma_pos != SCP_string::npos, "Received an ill-formed ASS line from FFmpeg! Text was '%s'.", subtitle_rect->ass);
|
||||
|
||||
// This + 1 is safe since comma_pos points to a valid character so the next character is at worst the end of the string
|
||||
processed_text = ass_text.substr(comma_pos + 1);
|
||||
|
||||
// ASS has a special sequence for new lines that needs to be converted to an actual new line
|
||||
auto newline_pos = processed_text.find("\\N");
|
||||
while(newline_pos != SCP_string::npos) {
|
||||
processed_text.replace(newline_pos, 2, "\n");
|
||||
|
||||
newline_pos = processed_text.find("\\N");
|
||||
}
|
||||
} else {
|
||||
mprintf(("FFmpeg: Detected unknown subtitle name in movie!\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove \r from string. Some subtitles use \r\n for line breaks and we only support \n
|
||||
auto ret_pos = processed_text.find('\r');
|
||||
while(ret_pos != SCP_string::npos) {
|
||||
processed_text.erase(ret_pos, 1);
|
||||
|
||||
ret_pos = processed_text.find('\r');
|
||||
}
|
||||
|
||||
SubtitleFramePtr frame(new SubtitleFrame());
|
||||
frame->text = processed_text;
|
||||
|
||||
frame->displayStartTime = start_time;
|
||||
frame->displayEndTime = end_time;
|
||||
|
||||
pushFrame(std::move(frame));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "cutscene/ffmpeg/internal.h"
|
||||
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
|
||||
class SubtitleDecoder: public FFMPEGStreamDecoder<SubtitleFrame> {
|
||||
public:
|
||||
explicit SubtitleDecoder(DecoderStatus* status);
|
||||
|
||||
virtual ~SubtitleDecoder();
|
||||
|
||||
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
|
||||
|
||||
virtual void finishDecoding() SCP_OVERRIDE;
|
||||
void pushSubtitleFrame(AVPacket* subtitle, AVSubtitle* pSubtitle);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,18 @@ DecoderStatus::~DecoderStatus() {
|
||||
#endif
|
||||
audioCodecCtx = nullptr;
|
||||
}
|
||||
|
||||
subtitleStreamIndex = -1;
|
||||
subtitleStream = nullptr;
|
||||
subtitleCodec = nullptr;
|
||||
|
||||
if (subtitleCodecCtx != nullptr) {
|
||||
avcodec_close(subtitleCodecCtx);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
avcodec_free_context(&subtitleCodecCtx);
|
||||
#endif
|
||||
subtitleCodecCtx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ffmpeg
|
||||
|
||||
@@ -16,6 +16,8 @@ struct CodecContextParameters {
|
||||
uint64_t channel_layout = 0;
|
||||
int sample_rate = -1;
|
||||
AVSampleFormat audio_format = AV_SAMPLE_FMT_NONE;
|
||||
|
||||
AVCodecID codec_id = AV_CODEC_ID_NONE;
|
||||
};
|
||||
|
||||
struct DecoderStatus {
|
||||
@@ -31,6 +33,12 @@ struct DecoderStatus {
|
||||
AVCodec* audioCodec = nullptr;
|
||||
AVCodecContext* audioCodecCtx = nullptr;
|
||||
|
||||
int subtitleStreamIndex = -1;
|
||||
AVStream* subtitleStream = nullptr;
|
||||
CodecContextParameters subtitleCodecPars;
|
||||
AVCodec* subtitleCodec = nullptr;
|
||||
AVCodecContext* subtitleCodecCtx = nullptr;
|
||||
|
||||
DecoderStatus();
|
||||
|
||||
~DecoderStatus();
|
||||
|
||||
+200
-1
@@ -14,6 +14,7 @@
|
||||
#endif
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "globalincs/alphacolors.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "io/cursor.h"
|
||||
#include "graphics/2d.h"
|
||||
@@ -21,10 +22,203 @@
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "cutscene/cutscenes.h" // cutscene_mark_viewable()
|
||||
#include "cutscene/player.h" // cutscene_mark_viewable()
|
||||
#include "tracing/categories.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "io/timer.h"
|
||||
#include "io/key.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
|
||||
extern int Game_mode;
|
||||
extern int Is_standalone;
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace cutscene;
|
||||
|
||||
struct PlaybackState {
|
||||
bool playing = true;
|
||||
|
||||
vec2d posTopLeft;
|
||||
vec2d posBottomRight;
|
||||
|
||||
int subtitle_font = -1;
|
||||
};
|
||||
|
||||
void processEvents(PlaybackState* state) {
|
||||
io::mouse::CursorManager::get()->showCursor(false);
|
||||
|
||||
os_poll();
|
||||
|
||||
int k = key_inkey();
|
||||
switch (k) {
|
||||
case KEY_ESC:
|
||||
case KEY_ENTER:
|
||||
case KEY_SPACEBAR:
|
||||
state->playing = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
float print_string(float x, float y, const char* fmt, Args... params) {
|
||||
SCP_string text;
|
||||
sprintf(text, fmt, params...);
|
||||
|
||||
gr_string(x, y, text.c_str(), GR_RESIZE_NONE);
|
||||
|
||||
return y + font::get_current_font()->getHeight();
|
||||
}
|
||||
|
||||
void showVideoInfo(const PlayerState& state) {
|
||||
gr_set_color_fast(&Color_white);
|
||||
font::set_font(font::FONT1);
|
||||
|
||||
float y = 200.f;
|
||||
float x = 100.f;
|
||||
y = print_string(x, y, "Movie FPS: %f", state.props.fps);
|
||||
y = print_string(x, y, "Size: %dx%d", state.props.size.width, state.props.size.height);
|
||||
|
||||
y = gr_screen.max_h - 200.f;
|
||||
|
||||
size_t audio_queue_size = state.decoder->getAudioQueueSize();
|
||||
if (state.hasAudio) {
|
||||
ALint queued;
|
||||
OpenAL_ErrorPrint(alGetSourcei(state.audioSid, AL_BUFFERS_QUEUED, &queued));
|
||||
audio_queue_size += queued;
|
||||
}
|
||||
|
||||
y = print_string(x, y, "Audio Queue size: " SIZE_T_ARG, audio_queue_size);
|
||||
y = print_string(x, y, "Video Queue size: " SIZE_T_ARG, state.decoder->getVideoQueueSize());
|
||||
y += font::get_current_font()->getHeight();
|
||||
// Estimate the size of the video buffer
|
||||
// We use YUV420p frames so one pixel uses 1.5 bytes of storage
|
||||
size_t single_frame_size = (size_t) (state.props.size.width * state.props.size.height * 1.5);
|
||||
size_t total_size = single_frame_size * state.decoder->getVideoQueueSize();
|
||||
print_string(x, y, "Video buffer size: " SIZE_T_ARG "B", total_size);
|
||||
}
|
||||
|
||||
void displayVideo(Player* player, PlaybackState* state) {
|
||||
TRACE_SCOPE(tracing::CutsceneDrawVideoFrame);
|
||||
GR_DEBUG_SCOPE("Display Video");
|
||||
|
||||
gr_clear();
|
||||
player->draw(state->posTopLeft.x, state->posTopLeft.y, state->posBottomRight.x, state->posBottomRight.y);
|
||||
|
||||
auto subtitle = player->getCurrentSubtitle();
|
||||
if (!subtitle.empty() && state->subtitle_font >= 0) {
|
||||
gr_set_color_fast(&Color_bright_white);
|
||||
font::set_font(state->subtitle_font);
|
||||
|
||||
int width;
|
||||
int height;
|
||||
gr_get_string_size(&width, &height, subtitle.c_str());
|
||||
|
||||
// Offset the subtitle by 20% of the viewport size from the bottom
|
||||
auto y_offset = static_cast<int>((state->posBottomRight.y - state->posTopLeft.y) * 0.1);
|
||||
|
||||
auto center_x = (state->posBottomRight.x - state->posTopLeft.x) / 2;
|
||||
|
||||
auto text_x = center_x - width / 2;
|
||||
auto text_y = state->posBottomRight.y - y_offset - height;
|
||||
|
||||
gr_string(text_x, text_y, subtitle.c_str(), GR_RESIZE_NONE);
|
||||
}
|
||||
|
||||
if (Cmdline_show_video_info) {
|
||||
showVideoInfo(player->getInternalState());
|
||||
}
|
||||
|
||||
gr_flip();
|
||||
}
|
||||
void determine_display_positions(Player* player, PlaybackState* state) {
|
||||
auto& props = player->getMovieProperties();
|
||||
|
||||
float screen_ratio = (float) gr_screen.center_w / (float) gr_screen.center_h;
|
||||
float movie_ratio = (float) props.size.width / (float) props.size.height;
|
||||
|
||||
float scale_by;
|
||||
if (screen_ratio > movie_ratio) {
|
||||
scale_by = (float) gr_screen.center_h / (float) props.size.height;
|
||||
} else {
|
||||
scale_by = (float) gr_screen.center_w / (float) props.size.width;
|
||||
}
|
||||
|
||||
float screenX;
|
||||
float screenY;
|
||||
|
||||
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
|
||||
screenX = ((gr_screen.center_w / 2.0f + gr_screen.center_offset_x) / scale_by) - (static_cast<int>(props.size.width) / 2.0f) + 0.5f;
|
||||
screenY = ((gr_screen.center_h / 2.0f + gr_screen.center_offset_y) / scale_by) - (static_cast<int>(props.size.height) / 2.0f) + 0.5f;
|
||||
} else {
|
||||
// centers on 1024x768, fills on 640x480
|
||||
screenX = i2fl(((gr_screen.center_w - static_cast<int>(props.size.width)) / 2) + gr_screen.center_offset_x);
|
||||
screenY = i2fl(((gr_screen.center_h - static_cast<int>(props.size.height)) / 2) + gr_screen.center_offset_y);
|
||||
}
|
||||
|
||||
// set additional values for screen width/height and UV coords
|
||||
float screenXW = screenX + static_cast<int>(props.size.width);
|
||||
float screenYH = screenY + static_cast<int>(props.size.height);
|
||||
|
||||
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
|
||||
// Apply scaling
|
||||
screenX *= scale_by;
|
||||
screenY *= scale_by;
|
||||
|
||||
screenXW *= scale_by;
|
||||
screenYH *= scale_by;
|
||||
}
|
||||
|
||||
state->posTopLeft.x = screenX;
|
||||
state->posTopLeft.y = screenY;
|
||||
|
||||
state->posBottomRight.x = screenXW;
|
||||
state->posBottomRight.y = screenYH;
|
||||
}
|
||||
|
||||
void initialize_player_state(Player* player, PlaybackState* state) {
|
||||
determine_display_positions(player, state);
|
||||
|
||||
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
|
||||
|
||||
if (state->subtitle_font < 0) {
|
||||
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void movie_display_loop(Player* player, PlaybackState* state) {
|
||||
// Compute the maximum time we will sleep to make sure we can still maintain the movie FPS
|
||||
// and not waste too much CPU time
|
||||
// We will sleep at most half the time a frame would be displayed
|
||||
auto sleepTime = static_cast<std::uint64_t>((1. / (4. * player->getMovieProperties().fps)) * 1000.);
|
||||
|
||||
auto lastDisplayTimestamp = timer_get_microseconds();
|
||||
while (state->playing) {
|
||||
TRACE_SCOPE(tracing::CutsceneStep);
|
||||
|
||||
auto timestamp = timer_get_microseconds();
|
||||
|
||||
auto passed = timestamp - lastDisplayTimestamp;
|
||||
lastDisplayTimestamp = timestamp;
|
||||
|
||||
// Play as long as the player reports that there is more to display
|
||||
state->playing = player->update(passed);
|
||||
|
||||
displayVideo(player, state);
|
||||
|
||||
processEvents(state);
|
||||
|
||||
if (passed < sleepTime) {
|
||||
auto sleep = sleepTime - passed;
|
||||
|
||||
os_sleep(static_cast<uint>(sleep));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace movie {
|
||||
// Play one movie
|
||||
bool play(const char* name) {
|
||||
@@ -57,7 +251,12 @@ bool play(const char* name) {
|
||||
|
||||
auto player = cutscene::Player::newPlayer(name);
|
||||
if (player) {
|
||||
player->startPlayback();
|
||||
PlaybackState state;
|
||||
initialize_player_state(player.get(), &state);
|
||||
|
||||
movie_display_loop(player.get(), &state);
|
||||
|
||||
player->stopPlayback();
|
||||
} else {
|
||||
// uh-oh, movie is invalid... Abory, Retry, Fail?
|
||||
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
|
||||
|
||||
+96
-176
@@ -1,7 +1,7 @@
|
||||
#include "cutscene/player.h"
|
||||
|
||||
#include "cutscene/Decoder.h"
|
||||
#include "cutscene/player/VideoPresenter.h"
|
||||
#include "cutscene/VideoPresenter.h"
|
||||
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
|
||||
|
||||
#include "graphics/2d.h"
|
||||
@@ -19,62 +19,19 @@
|
||||
|
||||
#include "parse/parselo.h"
|
||||
|
||||
#include "cutscene/player/OpenGLVideoPresenter.h"
|
||||
|
||||
using namespace cutscene::player;
|
||||
|
||||
namespace cutscene {
|
||||
struct PlayerState {
|
||||
MovieProperties props;
|
||||
Decoder* decoder = nullptr;
|
||||
|
||||
bool playing = true;
|
||||
|
||||
bool playbackHasBegun = false;
|
||||
|
||||
// Timing state
|
||||
std::uint64_t playback_time = 0;
|
||||
|
||||
// Audio state
|
||||
bool audioInited = false;
|
||||
bool hasAudio = false;
|
||||
ALuint audioSid = 0;
|
||||
SCP_vector<ALuint> audioBuffers;
|
||||
SCP_queue<ALuint> unqueuedAudioBuffers;
|
||||
|
||||
// Graphics state following
|
||||
bool videoInited = false;
|
||||
|
||||
VideoFramePtr currentFrame;
|
||||
VideoFramePtr nextFrame;
|
||||
bool newFrameAdded = false;
|
||||
|
||||
std::unique_ptr<VideoPresenter> videoPresenter;
|
||||
|
||||
PlayerState() : decoder(nullptr), playing(true), playbackHasBegun(false),
|
||||
playback_time(0),
|
||||
audioInited(0), hasAudio(false), audioSid(0),
|
||||
videoInited(false), newFrameAdded(false) {}
|
||||
|
||||
private:
|
||||
PlayerState(const PlayerState&) SCP_DELETED_FUNCTION;
|
||||
|
||||
PlayerState& operator=(const PlayerState&) SCP_DELETED_FUNCTION;
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
using namespace cutscene;
|
||||
|
||||
const int MAX_AUDIO_BUFFERS = 15;
|
||||
|
||||
Decoder* findDecoder(const SCP_string& name) {
|
||||
std::unique_ptr<Decoder> findDecoder(const SCP_string& name) {
|
||||
{
|
||||
auto ffmpeg = new ffmpeg::FFMPEGDecoder();
|
||||
std::unique_ptr<Decoder> ffmpeg(new ffmpeg::FFMPEGDecoder());
|
||||
if (ffmpeg->initialize(name)) {
|
||||
return ffmpeg;
|
||||
}
|
||||
delete ffmpeg;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -93,7 +50,7 @@ void videoPlaybackInit(PlayerState* state) {
|
||||
Assert(state != NULL);
|
||||
|
||||
if (gr_screen.mode == GR_OPENGL) {
|
||||
state->videoPresenter.reset(new OpenGLVideoPresenter(state->props));
|
||||
state->videoPresenter.reset(new VideoPresenter(state->props));
|
||||
}
|
||||
|
||||
state->videoInited = true;
|
||||
@@ -163,7 +120,7 @@ void processVideoData(PlayerState* state) {
|
||||
return;
|
||||
}
|
||||
|
||||
while(currentTime >= state->nextFrame->frameTime) {
|
||||
while (currentTime >= state->nextFrame->frameTime) {
|
||||
// Move the next frame to the current frame slot
|
||||
state->currentFrame = std::move(state->nextFrame);
|
||||
|
||||
@@ -184,6 +141,34 @@ void processVideoData(PlayerState* state) {
|
||||
}
|
||||
}
|
||||
|
||||
void processSubtitleData(PlayerState* state) {
|
||||
SubtitleFramePtr ptr;
|
||||
while (state->decoder->tryPopSubtitleData(ptr)) {
|
||||
// Take all subtitle frames from our queue
|
||||
state->queued_subtitles.push(std::move(ptr));
|
||||
}
|
||||
|
||||
if (state->currentSubtitle && playbackGetTime(state) <= state->currentSubtitle->displayEndTime) {
|
||||
// We currently have a frame and it it still being displayed so there is nothing for us to do here
|
||||
return;
|
||||
}
|
||||
|
||||
// Subtitle has expired so we don't need it anymore
|
||||
state->currentSubtitle = nullptr;
|
||||
|
||||
while(!state->queued_subtitles.empty()) {
|
||||
// Take a look at the first entry and check if it's time to display it yet
|
||||
auto& nextSubtitle = state->queued_subtitles.front();
|
||||
if (playbackGetTime(state) >= nextSubtitle->displayStartTime) {
|
||||
state->currentSubtitle = std::move(nextSubtitle);
|
||||
state->queued_subtitles.pop();
|
||||
} else {
|
||||
// The next subtitle should not be displayed yet so we are done here
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool processAudioData(PlayerState* state) {
|
||||
TRACE_SCOPE(tracing::CutsceneProcessAudioData);
|
||||
|
||||
@@ -191,7 +176,7 @@ bool processAudioData(PlayerState* state) {
|
||||
if (state->decoder->hasAudio()) {
|
||||
// Even if we don't play the sound we still need to remove it from the queue
|
||||
AudioFramePtr audioData;
|
||||
while(state->decoder->tryPopAudioData(audioData)) {
|
||||
while (state->decoder->tryPopAudioData(audioData)) {
|
||||
// Intentionally left empty
|
||||
}
|
||||
}
|
||||
@@ -216,7 +201,9 @@ bool processAudioData(PlayerState* state) {
|
||||
|
||||
ALenum format = (audioData->channels == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
|
||||
|
||||
OpenAL_ErrorCheck(alBufferData(buffer, format, audioData->audioData.data(),
|
||||
OpenAL_ErrorCheck(alBufferData(buffer,
|
||||
format,
|
||||
audioData->audioData.data(),
|
||||
static_cast<ALsizei>(audioData->audioData.size() * sizeof(short)),
|
||||
static_cast<ALsizei>(audioData->rate)), return false);
|
||||
|
||||
@@ -269,82 +256,10 @@ void videoPlaybackClose(PlayerState* state) {
|
||||
state->videoInited = false;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
float print_string(float x, float y, const char* fmt, Args... params) {
|
||||
SCP_string text;
|
||||
sprintf(text, fmt, params...);
|
||||
|
||||
gr_string(x, y, text.c_str(), GR_RESIZE_NONE);
|
||||
|
||||
return y + font::get_current_font()->getHeight();
|
||||
}
|
||||
|
||||
void showVideoInfo(PlayerState* state) {
|
||||
gr_set_color_fast(&Color_white);
|
||||
|
||||
float y = 200.f;
|
||||
float x = 100.f;
|
||||
y = print_string(x, y, "Movie FPS: %f", state->props.fps);
|
||||
y = print_string(x, y, "Size: %dx%d", state->props.size.width, state->props.size.height);
|
||||
|
||||
y = gr_screen.max_h - 200.f;
|
||||
|
||||
size_t audio_queue_size = state->decoder->getAudioQueueSize();
|
||||
if (state->hasAudio) {
|
||||
ALint queued;
|
||||
OpenAL_ErrorPrint(alGetSourcei(state->audioSid, AL_BUFFERS_QUEUED, &queued));
|
||||
audio_queue_size += queued;
|
||||
}
|
||||
|
||||
y = print_string(x, y, "Audio Queue size: " SIZE_T_ARG, audio_queue_size);
|
||||
y = print_string(x, y, "Video Queue size: " SIZE_T_ARG, state->decoder->getVideoQueueSize());
|
||||
y += font::get_current_font()->getHeight();
|
||||
// Estimate the size of the video buffer
|
||||
// We use YUV420p frames so one pixel uses 1.5 bytes of storage
|
||||
size_t single_frame_size = (size_t) (state->props.size.width * state->props.size.height * 1.5);
|
||||
size_t total_size = single_frame_size * state->decoder->getVideoQueueSize();
|
||||
print_string(x, y, "Video buffer size: " SIZE_T_ARG "B", total_size);
|
||||
}
|
||||
|
||||
void displayVideo(PlayerState* state) {
|
||||
if (!state->currentFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE_SCOPE(tracing::CutsceneDrawVideoFrame);
|
||||
|
||||
gr_clear();
|
||||
if (state->videoPresenter) {
|
||||
state->videoPresenter->displayFrame();
|
||||
}
|
||||
|
||||
if (Cmdline_show_video_info) {
|
||||
showVideoInfo(state);
|
||||
}
|
||||
|
||||
gr_flip();
|
||||
}
|
||||
|
||||
void processEvents(PlayerState* state) {
|
||||
io::mouse::CursorManager::get()->showCursor(false);
|
||||
|
||||
os_poll();
|
||||
|
||||
int k = key_inkey();
|
||||
switch (k) {
|
||||
case KEY_ESC:
|
||||
case KEY_ENTER:
|
||||
case KEY_SPACEBAR:
|
||||
state->playing = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldBeginPlayback(Decoder* decoder) {
|
||||
auto video = decoder->isVideoQueueFull();
|
||||
auto audio = decoder->isAudioQueueFull();
|
||||
auto subtitles = decoder->isSubtitleQueueFull();
|
||||
|
||||
// Wait until one of the queues is full, that should make sure
|
||||
// that we have enough frames at the beginning of playback and that
|
||||
@@ -352,92 +267,79 @@ bool shouldBeginPlayback(Decoder* decoder) {
|
||||
// or video at the beginning
|
||||
// Also only wait while the decoder is still working. Otherwise we will wait indefinitely if the video
|
||||
// is very short.
|
||||
return (audio || video) || !decoder->isDecoding();
|
||||
return (audio || video || subtitles) || !decoder->isDecoding();
|
||||
}
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
Player::Player() {
|
||||
Player::Player(std::unique_ptr<Decoder>&& decoder) : m_decoder(std::move(decoder)) {
|
||||
initPlayback();
|
||||
}
|
||||
|
||||
Player::~Player() {
|
||||
// If video is initialized it means that stopPlayback has not been called yet
|
||||
if (m_state.videoInited) {
|
||||
stopPlayback();
|
||||
}
|
||||
|
||||
if (m_decoder) {
|
||||
m_decoder->close();
|
||||
}
|
||||
}
|
||||
|
||||
void Player::processDecoderData(PlayerState* state) {
|
||||
if (!state->playbackHasBegun) {
|
||||
bool Player::processDecoderData() {
|
||||
if (!m_state.playbackHasBegun) {
|
||||
// Wait until video and audio are available
|
||||
// If we don't have audio, don't wait for it (obviously...)
|
||||
if (!shouldBeginPlayback(state->decoder)) {
|
||||
return;
|
||||
if (!shouldBeginPlayback(m_state.decoder)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
state->playbackHasBegun = true;
|
||||
m_state.playbackHasBegun = true;
|
||||
}
|
||||
|
||||
TRACE_SCOPE(tracing::CutsceneProcessDecoder);
|
||||
|
||||
processVideoData(state);
|
||||
processVideoData(&m_state);
|
||||
|
||||
auto audioPlaying = processAudioData(state);
|
||||
processSubtitleData(&m_state);
|
||||
|
||||
auto audioPlaying = processAudioData(&m_state);
|
||||
|
||||
// Set the playing flag if the decoder is still active or there is still data available
|
||||
auto decoding = m_decoder->isDecoding();
|
||||
|
||||
// Audio is pending if there is data left in the queue or of OpenAL is still playing audio
|
||||
// Audio is pending if there is data left in the queue or if OpenAL is still playing audio
|
||||
auto pendingAudio = (m_decoder->isAudioFrameAvailable() && m_decoder->hasAudio()) || audioPlaying;
|
||||
auto pendingVideo = m_decoder->isVideoFrameAvailable();
|
||||
|
||||
state->playing = decoding || pendingAudio || pendingVideo;
|
||||
return decoding || pendingAudio || pendingVideo;
|
||||
}
|
||||
|
||||
void Player::startPlayback() {
|
||||
void Player::initPlayback() {
|
||||
Assertion(!m_state.videoInited, "Internal State has been initialized before! Create a new player for replaying a movie.");
|
||||
|
||||
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
|
||||
|
||||
PlayerState state;
|
||||
state.props = m_decoder->getProperties();
|
||||
state.decoder = m_decoder.get();
|
||||
m_state.props = m_decoder->getProperties();
|
||||
m_state.decoder = m_decoder.get();
|
||||
|
||||
// Compute the maximum time we will sleep to make sure we can still maintain the movie FPS
|
||||
// and not waste too much CPU time
|
||||
// We will sleep at most half the time a frame would be displayed
|
||||
auto sleepTime = static_cast<std::uint64_t>((1. / (4. * state.props.fps)) * 1000.);
|
||||
videoPlaybackInit(&m_state);
|
||||
|
||||
videoPlaybackInit(&state);
|
||||
|
||||
audioPlaybackInit(&state);
|
||||
|
||||
auto lastDisplayTimestamp = timer_get_microseconds();
|
||||
while (state.playing) {
|
||||
TRACE_SCOPE(tracing::CutsceneStep);
|
||||
|
||||
processDecoderData(&state);
|
||||
|
||||
displayVideo(&state);
|
||||
|
||||
processEvents(&state);
|
||||
|
||||
auto timestamp = timer_get_microseconds();
|
||||
|
||||
auto passed = timestamp - lastDisplayTimestamp;
|
||||
lastDisplayTimestamp = timestamp;
|
||||
|
||||
if (state.playbackHasBegun) {
|
||||
state.playback_time += passed;
|
||||
}
|
||||
|
||||
if (passed < sleepTime) {
|
||||
auto sleep = sleepTime - passed;
|
||||
|
||||
os_sleep(static_cast<uint>(sleep));
|
||||
}
|
||||
audioPlaybackInit(&m_state);
|
||||
}
|
||||
bool Player::update(uint64_t diff_time_micro) {
|
||||
if (m_state.playbackHasBegun) {
|
||||
m_state.playback_time += diff_time_micro;
|
||||
}
|
||||
|
||||
return processDecoderData();
|
||||
}
|
||||
void Player::stopPlayback() {
|
||||
m_decoder->stopDecoder();
|
||||
|
||||
audioPlaybackClose(&state);
|
||||
videoPlaybackClose(&state);
|
||||
audioPlaybackClose(&m_state);
|
||||
videoPlaybackClose(&m_state);
|
||||
|
||||
m_decoderThread->join();
|
||||
}
|
||||
@@ -460,10 +362,28 @@ std::unique_ptr<Player> Player::newPlayer(const SCP_string& name) {
|
||||
if (decoder == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<Player>(new Player(std::move(decoder)));
|
||||
}
|
||||
const PlayerState& Player::getInternalState() const {
|
||||
return m_state;
|
||||
}
|
||||
const MovieProperties& Player::getMovieProperties() const {
|
||||
return m_state.props;
|
||||
}
|
||||
void Player::draw(float x1, float y1, float x2, float y2) {
|
||||
if (!m_state.currentFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<Player> player(new Player());
|
||||
player->m_decoder.reset(decoder);
|
||||
|
||||
return player;
|
||||
if (m_state.videoPresenter) {
|
||||
m_state.videoPresenter->displayFrame(x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
SCP_string Player::getCurrentSubtitle() {
|
||||
if (!m_state.currentSubtitle) {
|
||||
return "";
|
||||
} else {
|
||||
return m_state.currentSubtitle->text;
|
||||
}
|
||||
}
|
||||
}
|
||||
+89
-8
@@ -5,11 +5,48 @@
|
||||
#include <thread>
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "sound/openal.h"
|
||||
|
||||
#include "Decoder.h"
|
||||
#include "VideoPresenter.h"
|
||||
|
||||
namespace cutscene {
|
||||
class Decoder;
|
||||
|
||||
struct PlayerState;
|
||||
struct PlayerState {
|
||||
MovieProperties props;
|
||||
Decoder* decoder = nullptr;
|
||||
|
||||
bool playbackHasBegun = false;
|
||||
|
||||
// Timing state
|
||||
std::uint64_t playback_time = 0;
|
||||
|
||||
// Audio state
|
||||
bool audioInited = false;
|
||||
bool hasAudio = false;
|
||||
ALuint audioSid = 0;
|
||||
SCP_vector<ALuint> audioBuffers;
|
||||
SCP_queue<ALuint> unqueuedAudioBuffers;
|
||||
|
||||
// Graphics state following
|
||||
bool videoInited = false;
|
||||
|
||||
VideoFramePtr currentFrame;
|
||||
VideoFramePtr nextFrame;
|
||||
bool newFrameAdded = false;
|
||||
|
||||
std::unique_ptr<player::VideoPresenter> videoPresenter;
|
||||
|
||||
SCP_queue<SubtitleFramePtr> queued_subtitles;
|
||||
SubtitleFramePtr currentSubtitle;
|
||||
|
||||
PlayerState() {
|
||||
}
|
||||
|
||||
PlayerState(const PlayerState&) = delete;
|
||||
PlayerState& operator=(const PlayerState&) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A movie player
|
||||
@@ -20,22 +57,66 @@ class Player {
|
||||
|
||||
std::unique_ptr<std::thread> m_decoderThread;
|
||||
|
||||
void processDecoderData(PlayerState* state);
|
||||
PlayerState m_state;
|
||||
|
||||
bool processDecoderData();
|
||||
|
||||
private:
|
||||
Player(const Player&) = delete;
|
||||
|
||||
void decoderThread();
|
||||
|
||||
void initPlayback();
|
||||
|
||||
public:
|
||||
Player();
|
||||
explicit Player(std::unique_ptr<Decoder>&& decoder);
|
||||
|
||||
~Player();
|
||||
|
||||
Player(const Player&) = delete;
|
||||
Player& operator=(const Player&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Begin playing the previously selected movie
|
||||
*/
|
||||
void startPlayback();
|
||||
* @brief Update the player and increase display timestamp by specified delta time
|
||||
* @param diff_time_micro The time to increase the display timestamp in microseconds (not milliseconds!)
|
||||
* @return @c true if there is more content to display. @c false if the player reached the end of the movie and has
|
||||
* displayed the last frame.
|
||||
*/
|
||||
bool update(uint64_t diff_time_micro);
|
||||
|
||||
/**
|
||||
* @brief Gives access to the internal state of the player
|
||||
*
|
||||
* @warning This should only be used for debugging purposed!
|
||||
*
|
||||
* @return A reference to the internal state
|
||||
*/
|
||||
const PlayerState& getInternalState() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the properties of the movie that this player is displaying
|
||||
* @return A reference to the movie properties
|
||||
*/
|
||||
const MovieProperties& getMovieProperties() const;
|
||||
|
||||
/**
|
||||
* @brief Draws the current movie frame at the specified coordinates.
|
||||
*
|
||||
* This may not draw anything if there is currently not a frame to display.
|
||||
*
|
||||
* @param x1 The X coordinate of the top left corner
|
||||
* @param y1 The Y coordinate of the top left corner
|
||||
* @param x2 The X coordinate of the bottom right corner
|
||||
* @param y2 The Y coordinate of the bottom right corner
|
||||
*/
|
||||
void draw(float x1, float y1, float x2, float y2);
|
||||
|
||||
SCP_string getCurrentSubtitle();
|
||||
|
||||
/**
|
||||
* @brief Stops playback
|
||||
*
|
||||
* This is also automatically called when this instance is destroyed.
|
||||
*/
|
||||
void stopPlayback();
|
||||
|
||||
/**
|
||||
* @brief Creates a player
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
|
||||
#include "OpenGLVideoPresenter.h"
|
||||
|
||||
#include "graphics/opengl/gropenglstate.h"
|
||||
#include "graphics/opengl/gropengltnl.h"
|
||||
#include "graphics/opengl/gropengldraw.h"
|
||||
|
||||
|
||||
using namespace cutscene;
|
||||
using namespace cutscene::player;
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
OpenGLVideoPresenter::OpenGLVideoPresenter(const MovieProperties& props) : _scaleVideo(false),
|
||||
_ytex(0), _utex(0), _vtex(0) {
|
||||
GR_DEBUG_SCOPE("Init video");
|
||||
|
||||
opengl_set_texture_target(GL_TEXTURE_2D);
|
||||
|
||||
_vertexBuffer = gr_create_vertex_buffer(true);
|
||||
|
||||
auto w = static_cast<int>(props.size.width);
|
||||
auto h = static_cast<int>(props.size.height);
|
||||
|
||||
_sdr_handle = gr_maybe_create_shader(SDR_TYPE_VIDEO_PROCESS, 0);
|
||||
|
||||
glGenTextures(1, &_ytex);
|
||||
glGenTextures(1, &_utex);
|
||||
glGenTextures(1, &_vtex);
|
||||
|
||||
if (_ytex + _utex + _vtex == 0) {
|
||||
throw std::runtime_error("Can't create a GL texture");
|
||||
}
|
||||
opengl_shader_set_current(_sdr_handle);
|
||||
|
||||
gr_set_lighting(false, false);
|
||||
|
||||
GL_state.SetAlphaBlendMode(ALPHA_BLEND_NONE);
|
||||
GL_state.SetZbufferType(ZBUFFER_TYPE_NONE);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(0);
|
||||
GL_state.Texture.SetTarget(GL_texture_target);
|
||||
GL_state.Texture.Enable(_ytex);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
|
||||
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w, h, 0, GL_RED,
|
||||
GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(1);
|
||||
GL_state.Texture.SetTarget(GL_texture_target);
|
||||
GL_state.Texture.Enable(_utex);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
|
||||
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w / 2, h / 2, 0, GL_RED,
|
||||
GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(2);
|
||||
GL_state.Texture.SetTarget(GL_texture_target);
|
||||
GL_state.Texture.Enable(_vtex);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
|
||||
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w / 2, h / 2, 0, GL_RED,
|
||||
GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
float screen_ratio = (float) gr_screen.center_w / (float) gr_screen.center_h;
|
||||
float movie_ratio = (float) props.size.width / (float) props.size.height;
|
||||
|
||||
float scale_by;
|
||||
if (screen_ratio > movie_ratio) {
|
||||
scale_by = (float) gr_screen.center_h / (float) props.size.height;
|
||||
} else {
|
||||
scale_by = (float) gr_screen.center_w / (float) props.size.width;
|
||||
}
|
||||
|
||||
// don't bother setting anything if we aren't going to need it
|
||||
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
|
||||
vec3d scale;
|
||||
|
||||
scale.xyz.x = scale_by;
|
||||
scale.xyz.y = scale_by;
|
||||
scale.xyz.z = -1.0f;
|
||||
|
||||
gr_push_scale_matrix(&scale);
|
||||
_scaleVideo = true;
|
||||
}
|
||||
|
||||
int screenX;
|
||||
int screenY;
|
||||
|
||||
if (_scaleVideo) {
|
||||
screenX = fl2i(((gr_screen.center_w / 2.0f + gr_screen.center_offset_x) / scale_by) - (static_cast<int>(props.size.width) / 2.0f) + 0.5f);
|
||||
screenY = fl2i(((gr_screen.center_h / 2.0f + gr_screen.center_offset_y) / scale_by) - (static_cast<int>(props.size.height) / 2.0f) + 0.5f);
|
||||
} else {
|
||||
// centers on 1024x768, fills on 640x480
|
||||
screenX = ((gr_screen.center_w - static_cast<int>(props.size.width)) / 2) + gr_screen.center_offset_x;
|
||||
screenY = ((gr_screen.center_h - static_cast<int>(props.size.height)) / 2) + gr_screen.center_offset_y;
|
||||
}
|
||||
|
||||
// set additional values for screen width/height and UV coords
|
||||
int screenXW = screenX + static_cast<int>(props.size.width);
|
||||
int screenYH = screenY + static_cast<int>(props.size.height);
|
||||
|
||||
Current_shader->program->Uniforms.setUniformi("ytex", 0);
|
||||
Current_shader->program->Uniforms.setUniformi("utex", 1);
|
||||
Current_shader->program->Uniforms.setUniformi("vtex", 2);
|
||||
|
||||
Current_shader->program->Uniforms.setUniformMatrix4f("projMatrix", GL_projection_matrix);
|
||||
Current_shader->program->Uniforms.setUniformMatrix4f("modelViewMatrix", GL_model_view_matrix);
|
||||
|
||||
GLfloat glVertices[4][4] = {{0}};
|
||||
glVertices[0][0] = (GLfloat)screenX;
|
||||
glVertices[0][1] = (GLfloat)screenY;
|
||||
glVertices[0][2] = 0.0f;
|
||||
glVertices[0][3] = 0.0f;
|
||||
|
||||
glVertices[1][0] = (GLfloat)screenX;
|
||||
glVertices[1][1] = (GLfloat)screenYH;
|
||||
glVertices[1][2] = 0.0f;
|
||||
glVertices[1][3] = 1.0f;
|
||||
|
||||
glVertices[2][0] = (GLfloat)screenXW;
|
||||
glVertices[2][1] = (GLfloat)screenY;
|
||||
glVertices[2][2] = 1.0f;
|
||||
glVertices[2][3] = 0.0f;
|
||||
|
||||
glVertices[3][0] = (GLfloat)screenXW;
|
||||
glVertices[3][1] = (GLfloat)screenYH;
|
||||
glVertices[3][2] = 1.0f;
|
||||
glVertices[3][3] = 1.0f;
|
||||
|
||||
_vertexLayout.add_vertex_component(vertex_format_data::POSITION2, sizeof(glVertices[0]), 0);
|
||||
_vertexLayout.add_vertex_component(vertex_format_data::TEX_COORD, sizeof(glVertices[0]), sizeof(GLfloat) * 2);
|
||||
|
||||
gr_update_buffer_data(_vertexBuffer, sizeof(glVertices[0]) * 4, glVertices);
|
||||
}
|
||||
|
||||
OpenGLVideoPresenter::~OpenGLVideoPresenter() {
|
||||
GR_DEBUG_SCOPE("Deinit video");
|
||||
|
||||
if (_scaleVideo) {
|
||||
gr_pop_scale_matrix();
|
||||
}
|
||||
|
||||
gr_delete_buffer(_vertexBuffer);
|
||||
_vertexBuffer = -1;
|
||||
|
||||
GL_state.Texture.Delete(_ytex);
|
||||
GL_state.Texture.Delete(_utex);
|
||||
GL_state.Texture.Delete(_vtex);
|
||||
glDeleteTextures(1, &_ytex);
|
||||
glDeleteTextures(1, &_utex);
|
||||
glDeleteTextures(1, &_vtex);
|
||||
|
||||
opengl_set_texture_target();
|
||||
|
||||
_ytex = _utex = _vtex = 0;
|
||||
opengl_shader_set_current();
|
||||
}
|
||||
|
||||
void OpenGLVideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
|
||||
GR_DEBUG_SCOPE("Update video frame");
|
||||
auto ptrs = frame->getDataPointers();
|
||||
|
||||
auto stride = static_cast<GLint>(frame->ySize.stride);
|
||||
auto width = static_cast<GLint>(frame->ySize.width);
|
||||
auto height = static_cast<GLint>(frame->ySize.height);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(0);
|
||||
GL_state.Texture.Enable(_ytex);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
||||
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
|
||||
ptrs.y);
|
||||
|
||||
stride = static_cast<int>(frame->uvSize.stride);
|
||||
width = static_cast<int>(frame->uvSize.width);
|
||||
height = static_cast<int>(frame->uvSize.height);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(1);
|
||||
GL_state.Texture.Enable(_utex);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
||||
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
|
||||
ptrs.u);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(2);
|
||||
GL_state.Texture.Enable(_vtex);
|
||||
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
|
||||
ptrs.v);
|
||||
|
||||
// Reset this back to default
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
|
||||
void OpenGLVideoPresenter::displayFrame() {
|
||||
opengl_shader_set_current(_sdr_handle);
|
||||
|
||||
opengl_bind_buffer_object(_vertexBuffer);
|
||||
opengl_bind_vertex_layout(_vertexLayout);
|
||||
|
||||
// Bind textures
|
||||
GL_state.Texture.SetActiveUnit(0);
|
||||
GL_state.Texture.Enable(_ytex);
|
||||
GL_state.Texture.SetActiveUnit(1);
|
||||
GL_state.Texture.Enable(_utex);
|
||||
GL_state.Texture.SetActiveUnit(2);
|
||||
GL_state.Texture.Enable(_vtex);
|
||||
|
||||
GR_DEBUG_SCOPE("Draw video frame");
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
|
||||
#ifndef FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
#define FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "cutscene/player/VideoPresenter.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <memory>
|
||||
#include <graphics/2d.h>
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
class OpenGLVideoPresenter: public VideoPresenter {
|
||||
int _vertexBuffer = -1;
|
||||
vertex_layout _vertexLayout;
|
||||
int _sdr_handle = -1;
|
||||
|
||||
bool _scaleVideo = false;
|
||||
|
||||
GLuint _ytex = 0;
|
||||
GLuint _utex = 0;
|
||||
GLuint _vtex = 0;
|
||||
public:
|
||||
OpenGLVideoPresenter(const MovieProperties& props);
|
||||
|
||||
virtual ~OpenGLVideoPresenter();
|
||||
|
||||
virtual void uploadVideoFrame(const VideoFramePtr& frame) SCP_OVERRIDE;
|
||||
|
||||
virtual void displayFrame() SCP_OVERRIDE;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
@@ -1,21 +0,0 @@
|
||||
|
||||
#ifndef FS2_OPEN_VIDEOPRESENTER_H
|
||||
#define FS2_OPEN_VIDEOPRESENTER_H
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "cutscene/Decoder.h"
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
class VideoPresenter {
|
||||
public:
|
||||
virtual ~VideoPresenter() {}
|
||||
|
||||
virtual void uploadVideoFrame(const VideoFramePtr& frame) = 0;
|
||||
|
||||
virtual void displayFrame() = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif //FS2_OPEN_VIDEOPRESENTER_H
|
||||
@@ -74,7 +74,7 @@ static void debris_start_death_roll(object *debris_obj, debris *debris_p)
|
||||
|
||||
// only play debris destroy sound if hull piece and it has been around for at least 2 seconds
|
||||
if ( Missiontime > debris_p->time_started + 2*F1_0 ) {
|
||||
snd_play_3d( &Snds[SND_MISSILE_IMPACT1], &debris_obj->pos, &View_position, debris_obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_MISSILE_IMPACT1), &debris_obj->pos, &View_position, debris_obj->radius );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -324,19 +324,19 @@ void debris_process_post(object * obj, float frame_time)
|
||||
//Play a sound effect
|
||||
if ( lifetime > 750 ) {
|
||||
// 1.00 second effect
|
||||
snd_play_3d( &Snds[SND_DEBRIS_ARC_05], &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_05), &snd_pos, &View_position, obj->radius );
|
||||
} else if ( lifetime > 500 ) {
|
||||
// 0.75 second effect
|
||||
snd_play_3d( &Snds[SND_DEBRIS_ARC_04], &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_04), &snd_pos, &View_position, obj->radius );
|
||||
} else if ( lifetime > 250 ) {
|
||||
// 0.50 second effect
|
||||
snd_play_3d( &Snds[SND_DEBRIS_ARC_03], &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_03), &snd_pos, &View_position, obj->radius );
|
||||
} else if ( lifetime > 100 ) {
|
||||
// 0.25 second effect
|
||||
snd_play_3d( &Snds[SND_DEBRIS_ARC_02], &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_02), &snd_pos, &View_position, obj->radius );
|
||||
} else {
|
||||
// 0.10 second effect
|
||||
snd_play_3d( &Snds[SND_DEBRIS_ARC_01], &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_01), &snd_pos, &View_position, obj->radius );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
in vec4 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2DArray baseMap;
|
||||
uniform float intensity;
|
||||
#define SRGB_GAMMA 2.2
|
||||
void main()
|
||||
{
|
||||
vec4 baseColor = texture(baseMap, fragTexCoord.xyz);
|
||||
|
||||
baseColor.rgb = pow(baseColor.rgb, vec3(SRGB_GAMMA));
|
||||
vec4 blendColor = vec4(pow(fragColor.rgb, vec3(SRGB_GAMMA)), fragColor.a);
|
||||
|
||||
fragOut0 = baseColor * blendColor * intensity;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
in vec4 vertPosition;
|
||||
in vec4 vertTexCoord;
|
||||
in vec4 vertColor;
|
||||
out vec4 fragTexCoord;
|
||||
out vec4 fragColor;
|
||||
uniform mat4 modelViewMatrix;
|
||||
uniform mat4 projMatrix;
|
||||
uniform vec4 color;
|
||||
void main()
|
||||
{
|
||||
fragTexCoord = vec4(vertTexCoord.xyz, 0.0);
|
||||
fragColor = vertColor * color;
|
||||
gl_Position = projMatrix * modelViewMatrix * vertPosition;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
in vec4 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2DArray baseMap;
|
||||
uniform int baseMapIndex;
|
||||
uniform int alphaTexture;
|
||||
uniform int noTexturing;
|
||||
uniform int srgb;
|
||||
uniform float intensity;
|
||||
uniform float alphaThreshold;
|
||||
#define SRGB_GAMMA 2.2
|
||||
void main()
|
||||
{
|
||||
vec4 baseColor = texture(baseMap, vec3(fragTexCoord.xy, float(baseMapIndex)));
|
||||
if(alphaThreshold > baseColor.a) discard;
|
||||
baseColor.rgb = (srgb == 1) ? pow(baseColor.rgb, vec3(SRGB_GAMMA)) : baseColor.rgb;
|
||||
vec4 blendColor = (srgb == 1) ? vec4(pow(fragColor.rgb, vec3(SRGB_GAMMA)), fragColor.a) : fragColor;
|
||||
fragOut0 = mix(mix(baseColor * blendColor, vec4(blendColor.rgb, baseColor.r * blendColor.a), float(alphaTexture)), blendColor, float(noTexturing)) * intensity;
|
||||
}
|
||||
@@ -1,21 +1,31 @@
|
||||
in vec3 beamVec;
|
||||
in vec3 lightPosition;
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D ColorBuffer;
|
||||
uniform sampler2D NormalBuffer;
|
||||
uniform sampler2D PositionBuffer;
|
||||
uniform sampler2D SpecBuffer;
|
||||
|
||||
uniform float specFactor;
|
||||
uniform float invScreenWidth;
|
||||
uniform float invScreenHeight;
|
||||
uniform int lightType;
|
||||
uniform float lightRadius;
|
||||
uniform vec3 diffuseLightColor;
|
||||
uniform vec3 specLightColor;
|
||||
uniform float coneAngle;
|
||||
uniform float coneInnerAngle;
|
||||
uniform bool dualCone;
|
||||
uniform vec3 coneDir;
|
||||
|
||||
layout (std140) uniform lightData {
|
||||
vec3 diffuseLightColor;
|
||||
float coneAngle;
|
||||
|
||||
vec3 specLightColor;
|
||||
float coneInnerAngle;
|
||||
|
||||
vec3 coneDir;
|
||||
bool dualCone;
|
||||
|
||||
vec3 scale;
|
||||
float lightRadius;
|
||||
|
||||
int lightType;
|
||||
};
|
||||
|
||||
#define SPEC_INTENSITY_POINT 5.3 // Point light
|
||||
#define SPEC_INTENSITY_DIRECTIONAL 3.0 // Directional light
|
||||
@@ -93,4 +103,4 @@ void main()
|
||||
vec4 fragmentColor = vec4(color * (diffuseLightColor * NdotL * attenuation), 1.0);
|
||||
fragmentColor.rgb += SpecularBlinnPhong(specColor.rgb, lightDir, normal.xyz, halfVec, exp2(10.0 * gloss + 1.0), fresnel, NdotL).rgb * specLightColor * attenuation;
|
||||
fragOut0 = max(fragmentColor, vec4(0.0));
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,23 @@
|
||||
in vec4 vertPosition;
|
||||
uniform mat4 modelViewMatrix;
|
||||
uniform mat4 projMatrix;
|
||||
uniform vec3 scale;
|
||||
uniform int lightType;
|
||||
|
||||
layout (std140) uniform lightData {
|
||||
vec3 diffuseLightColor;
|
||||
float coneAngle;
|
||||
|
||||
vec3 specLightColor;
|
||||
float coneInnerAngle;
|
||||
|
||||
vec3 coneDir;
|
||||
bool dualCone;
|
||||
|
||||
vec3 scale;
|
||||
float lightRadius;
|
||||
|
||||
int lightType;
|
||||
};
|
||||
|
||||
out vec3 lightPosition;
|
||||
out vec3 beamVec;
|
||||
void main()
|
||||
@@ -11,4 +26,4 @@ void main()
|
||||
lightPosition = modelViewMatrix[3].xyz;
|
||||
if(lightType == 1)
|
||||
beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ in vec4 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
in float fragOffset;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2D baseMap;
|
||||
uniform sampler2DArray baseMap;
|
||||
uniform sampler2D depthMap;
|
||||
uniform float window_width;
|
||||
uniform float window_height;
|
||||
@@ -11,10 +11,10 @@ uniform sampler2D frameBuffer;
|
||||
void main()
|
||||
{
|
||||
vec2 depthCoord = vec2(gl_FragCoord.x / window_width, gl_FragCoord.y / window_height);
|
||||
vec4 fragmentColor = texture(baseMap, fragTexCoord.xy) * fragColor.a;
|
||||
vec4 fragmentColor = texture(baseMap, fragTexCoord.xyz) * fragColor.a;
|
||||
vec2 distortion = texture(distMap, fragTexCoord.xy+vec2(0.0, fragOffset)).rg;
|
||||
float alpha = clamp(dot(fragmentColor.rgb,vec3(0.3333))*10.0,0.0,1.0);
|
||||
distortion = ((distortion - 0.5) * 0.01) * alpha;
|
||||
fragOut0 = texture(frameBuffer,depthCoord+distortion);
|
||||
fragOut0.a = alpha;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,6 @@ void main()
|
||||
{
|
||||
gl_Position = projMatrix * modelViewMatrix * vertPosition;
|
||||
fragOffset = vertRadius * use_offset;
|
||||
fragTexCoord = vertTexCoord;
|
||||
fragTexCoord = vec4(vertTexCoord.xyz, 0.0);
|
||||
fragColor = vertColor;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
in vec4 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2D baseMap;
|
||||
uniform int textured;
|
||||
void main()
|
||||
{
|
||||
vec4 fragmentColor = mix(fragColor, texture(baseMap, fragTexCoord.xy)*fragColor.a, (float)textured);
|
||||
fragOut0 = fragmentColor;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
uniform sampler2D baseMap;
|
||||
uniform sampler2DArray baseMap;
|
||||
uniform sampler2D depthMap;
|
||||
uniform float window_width;
|
||||
uniform float window_height;
|
||||
@@ -15,7 +15,7 @@ out vec4 fragOut0;
|
||||
#define SRGB_GAMMA 2.2
|
||||
void main()
|
||||
{
|
||||
vec4 fragmentColor = texture(baseMap, fragTexCoord.xy);
|
||||
vec4 fragmentColor = texture(baseMap, fragTexCoord.xyz);
|
||||
fragmentColor.rgb = mix(fragmentColor.rgb, pow(fragmentColor.rgb, vec3(SRGB_GAMMA)), float(srgb));
|
||||
fragmentColor *= mix(fragColor, vec4(pow(fragColor.rgb, vec3(SRGB_GAMMA)), fragColor.a), float(srgb));
|
||||
vec2 offset = vec2(fragRadius * abs(0.5 - fragTexCoord.x) * 2.0, fragRadius * abs(0.5 - fragTexCoord.y) * 2.0);
|
||||
@@ -43,4 +43,4 @@ void main()
|
||||
fragmentColor.rgb *= (srgb == 1) ? 1.5 : 1.0;
|
||||
fragmentColor = (blend_alpha == 1) ? vec4(fragmentColor.rgb, fragmentColor.a * intensity) : vec4(fragmentColor.rgb * intensity, fragmentColor.a);
|
||||
fragOut0 = max(fragmentColor, vec4(0.0));
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ layout (triangle_strip, max_vertices = 4) out;
|
||||
in vec3 geoUvec[];
|
||||
in float geoRadius[];
|
||||
in vec4 geoColor[];
|
||||
in float geoArrayIndex[];
|
||||
out float fragRadius;
|
||||
out vec4 fragPosition;
|
||||
out vec4 fragTexCoord;
|
||||
@@ -18,7 +19,7 @@ void main(void)
|
||||
pos = (gl_in[0].gl_Position - vec4(geoRadius[0] * up_vec, 0.0) - vec4(geoRadius[0] * right_vec, 0.0));
|
||||
gl_Position = projMatrix * pos;
|
||||
fragPosition = pos;
|
||||
fragTexCoord = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
fragTexCoord = vec4(0.0, 0.0, geoArrayIndex[0], 0.0);
|
||||
fragRadius = geoRadius[0];
|
||||
fragColor = geoColor[0];
|
||||
EmitVertex();
|
||||
@@ -26,7 +27,7 @@ void main(void)
|
||||
pos = (gl_in[0].gl_Position - vec4(geoRadius[0] * up_vec, 0.0) + vec4(geoRadius[0] * right_vec, 0.0));
|
||||
gl_Position = projMatrix * pos;
|
||||
fragPosition = pos;
|
||||
fragTexCoord = vec4(0.0, 1.0, 0.0, 0.0);
|
||||
fragTexCoord = vec4(0.0, 1.0, geoArrayIndex[0], 0.0);
|
||||
fragRadius = geoRadius[0];
|
||||
fragColor = geoColor[0];
|
||||
EmitVertex();
|
||||
@@ -34,7 +35,7 @@ void main(void)
|
||||
pos = (gl_in[0].gl_Position + vec4(geoRadius[0] * up_vec, 0.0) - vec4(geoRadius[0] * right_vec, 0.0));
|
||||
gl_Position = projMatrix * pos;
|
||||
fragPosition = pos;
|
||||
fragTexCoord = vec4(1.0, 0.0, 0.0, 0.0);
|
||||
fragTexCoord = vec4(1.0, 0.0, geoArrayIndex[0], 0.0);
|
||||
fragRadius = geoRadius[0];
|
||||
fragColor = geoColor[0];
|
||||
EmitVertex();
|
||||
@@ -42,9 +43,9 @@ void main(void)
|
||||
pos = (gl_in[0].gl_Position + vec4(geoRadius[0] * up_vec, 0.0) + vec4(geoRadius[0] * right_vec, 0.0));
|
||||
gl_Position = projMatrix * pos;
|
||||
fragPosition = pos;
|
||||
fragTexCoord = vec4(1.0, 1.0, 0.0, 0.0);
|
||||
fragTexCoord = vec4(1.0, 1.0, geoArrayIndex[0], 0.0);
|
||||
fragRadius = geoRadius[0];
|
||||
fragColor = geoColor[0];
|
||||
EmitVertex();
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ in float vertRadius;
|
||||
out vec3 geoUvec;
|
||||
out float geoRadius;
|
||||
out vec4 geoColor;
|
||||
out float geoArrayIndex;
|
||||
#else
|
||||
out float fragRadius;
|
||||
out vec4 fragPosition;
|
||||
@@ -26,14 +27,15 @@ void main()
|
||||
geoUvec = vertUvec;
|
||||
gl_Position = modelViewMatrix * vertPosition;
|
||||
geoColor = vertColor;
|
||||
geoArrayIndex = vertTexCoord.z;
|
||||
#else
|
||||
fragRadius = vertRadius;
|
||||
gl_Position = projMatrix * modelViewMatrix * vertPosition;
|
||||
fragPosition = modelViewMatrix * vertPosition;
|
||||
fragTexCoord = vertTexCoord;
|
||||
fragTexCoord = vec4(vertTexCoord.xyz, 0.0);
|
||||
fragColor = vertColor;
|
||||
#endif
|
||||
#ifdef FLAG_EFFECT_DISTORTION
|
||||
fragOffset = vertRadius * use_offset;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
+114
-77
@@ -2,88 +2,131 @@
|
||||
#define LT_DIRECTIONAL 0
|
||||
#define LT_POINT 1
|
||||
#define LT_TUBE 2
|
||||
uniform vec4 color;
|
||||
#ifdef FLAG_LIGHT
|
||||
uniform vec4 lightPosition[MAX_LIGHTS];
|
||||
uniform vec3 lightDirection[MAX_LIGHTS];
|
||||
uniform vec3 lightDiffuseColor[MAX_LIGHTS];
|
||||
uniform vec3 lightSpecColor[MAX_LIGHTS];
|
||||
uniform int lightType[MAX_LIGHTS];
|
||||
uniform float lightAttenuation[MAX_LIGHTS];
|
||||
uniform int n_lights;
|
||||
uniform float defaultGloss;
|
||||
uniform vec3 ambientFactor;
|
||||
uniform vec3 diffuseFactor;
|
||||
uniform vec3 emissionFactor;
|
||||
#endif
|
||||
struct model_light {
|
||||
vec4 position;
|
||||
|
||||
vec3 diffuse_color;
|
||||
int light_type;
|
||||
|
||||
vec3 spec_color;
|
||||
float attenuation;
|
||||
|
||||
vec3 direction;
|
||||
};
|
||||
|
||||
layout (std140) uniform modelData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 modelMatrix;
|
||||
mat4 viewMatrix;
|
||||
mat4 projMatrix;
|
||||
mat4 textureMatrix;
|
||||
mat4 shadow_mv_matrix;
|
||||
mat4 shadow_proj_matrix[4];
|
||||
mat4 envMatrix;
|
||||
|
||||
vec4 color;
|
||||
|
||||
model_light lights[MAX_LIGHTS];
|
||||
|
||||
float extrudeWidth;
|
||||
float fogStart;
|
||||
float fogScale;
|
||||
int buffer_matrix_offset;
|
||||
|
||||
vec4 clip_equation;
|
||||
|
||||
float thruster_scale;
|
||||
bool use_clip_plane;
|
||||
int n_lights;
|
||||
float defaultGloss;
|
||||
|
||||
vec3 ambientFactor;
|
||||
int desaturate;
|
||||
|
||||
vec3 diffuseFactor;
|
||||
int blend_alpha;
|
||||
|
||||
vec3 emissionFactor;
|
||||
bool overrideDiffuse;
|
||||
|
||||
vec3 diffuseClr;
|
||||
bool overrideGlow;
|
||||
|
||||
vec3 glowClr;
|
||||
bool overrideSpec;
|
||||
|
||||
vec3 specClr;
|
||||
bool alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
bool alpha_spec;
|
||||
int effect_num;
|
||||
|
||||
vec4 fogColor;
|
||||
|
||||
vec3 base_color;
|
||||
float anim_timer;
|
||||
|
||||
vec3 stripe_color;
|
||||
float vpwidth;
|
||||
|
||||
float vpheight;
|
||||
bool team_glow_enabled;
|
||||
float znear;
|
||||
float zfar;
|
||||
|
||||
float veryneardist;
|
||||
float neardist;
|
||||
float middist;
|
||||
float fardist;
|
||||
|
||||
vec2 normalAlphaMinMax;
|
||||
int sBasemapIndex;
|
||||
int sGlowmapIndex;
|
||||
|
||||
int sSpecmapIndex;
|
||||
int sNormalmapIndex;
|
||||
int sAmbientmapIndex;
|
||||
int sMiscmapIndex;
|
||||
};
|
||||
|
||||
#ifdef FLAG_DIFFUSE_MAP
|
||||
uniform sampler2D sBasemap;
|
||||
uniform int desaturate;
|
||||
uniform int blend_alpha;
|
||||
uniform bool overrideDiffuse;
|
||||
uniform vec3 diffuseClr;
|
||||
uniform sampler2DArray sBasemap;
|
||||
#endif
|
||||
#ifdef FLAG_GLOW_MAP
|
||||
uniform sampler2D sGlowmap;
|
||||
uniform bool overrideGlow;
|
||||
uniform vec3 glowClr;
|
||||
uniform sampler2DArray sGlowmap;
|
||||
#endif
|
||||
#ifdef FLAG_SPEC_MAP
|
||||
uniform sampler2D sSpecmap;
|
||||
uniform bool overrideSpec;
|
||||
uniform vec3 specClr;
|
||||
uniform bool alphaGloss;
|
||||
uniform bool gammaSpec;
|
||||
uniform sampler2DArray sSpecmap;
|
||||
#endif
|
||||
#ifdef FLAG_ENV_MAP
|
||||
uniform samplerCube sEnvmap;
|
||||
uniform bool envGloss;
|
||||
uniform bool alpha_spec;
|
||||
in vec3 fragEnvReflect;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
uniform sampler2D sNormalmap;
|
||||
uniform sampler2DArray sNormalmap;
|
||||
in mat3 fragTangentMatrix;
|
||||
#endif
|
||||
#ifdef FLAG_AMBIENT_MAP
|
||||
uniform sampler2D sAmbientmap;
|
||||
uniform sampler2DArray sAmbientmap;
|
||||
#endif
|
||||
#ifdef FLAG_FOG
|
||||
uniform vec4 fogColor;
|
||||
in float fragFogDist;
|
||||
#endif
|
||||
#ifdef FLAG_ANIMATED
|
||||
uniform sampler2D sFramebuffer;
|
||||
uniform int effect_num;
|
||||
uniform float anim_timer;
|
||||
uniform float vpwidth;
|
||||
uniform float vpheight;
|
||||
#endif
|
||||
#ifdef FLAG_TRANSFORM
|
||||
in float fragNotVisible;
|
||||
#endif
|
||||
#ifdef FLAG_TEAMCOLOR
|
||||
uniform vec3 base_color;
|
||||
uniform vec3 stripe_color;
|
||||
uniform bool team_glow_enabled;
|
||||
vec2 teamMask = vec2(0.0, 0.0);
|
||||
#endif
|
||||
#ifdef FLAG_MISC_MAP
|
||||
uniform sampler2D sMiscmap;
|
||||
uniform sampler2DArray sMiscmap;
|
||||
#endif
|
||||
#ifdef FLAG_SHADOWS
|
||||
in vec4 fragShadowUV[4];
|
||||
in vec4 fragShadowPos;
|
||||
uniform sampler2DArray shadow_map;
|
||||
uniform float znear;
|
||||
uniform float zfar;
|
||||
uniform float veryneardist;
|
||||
uniform float neardist;
|
||||
uniform float middist;
|
||||
uniform float fardist;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_ALPHA
|
||||
uniform vec2 normalAlphaMinMax;
|
||||
#endif
|
||||
#define SPEC_INTENSITY_POINT 5.3 // Point light
|
||||
#define SPEC_INTENSITY_DIRECTIONAL 3.0 // Directional light
|
||||
@@ -210,26 +253,26 @@ vec3 SpecularBlinnPhong(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, f
|
||||
#ifdef FLAG_LIGHT
|
||||
void GetLightInfo(int i, out vec3 lightDir, out float attenuation)
|
||||
{
|
||||
lightDir = normalize(lightPosition[i].xyz);
|
||||
lightDir = normalize(lights[i].position.xyz);
|
||||
attenuation = 1.0;
|
||||
if (lightType[i] != LT_DIRECTIONAL) {
|
||||
if (lights[i].light_type != LT_DIRECTIONAL) {
|
||||
// Positional light source
|
||||
float dist = distance(lightPosition[i].xyz, fragPosition.xyz);
|
||||
lightDir = (lightPosition[i].xyz - fragPosition.xyz);
|
||||
float dist = distance(lights[i].position.xyz, fragPosition.xyz);
|
||||
lightDir = (lights[i].position.xyz - fragPosition.xyz);
|
||||
|
||||
if (lightType[i] == LT_TUBE) { // Tube light
|
||||
float beamlength = length(lightDirection[i]);
|
||||
vec3 beamDir = normalize(lightDirection[i]);
|
||||
if (lights[i].light_type == LT_TUBE) { // Tube light
|
||||
float beamlength = length(lights[i].direction);
|
||||
vec3 beamDir = normalize(lights[i].direction);
|
||||
// Get nearest point on line
|
||||
float neardist = dot(fragPosition.xyz - lightPosition[i].xyz, beamDir);
|
||||
float neardist = dot(fragPosition.xyz - lights[i].position.xyz, beamDir);
|
||||
// Move back from the endpoint of the beam along the beam by the distance we calculated
|
||||
vec3 nearest = lightPosition[i].xyz - beamDir * abs(neardist);
|
||||
vec3 nearest = lights[i].position.xyz - beamDir * abs(neardist);
|
||||
lightDir = nearest - fragPosition.xyz;
|
||||
dist = length(lightDir);
|
||||
}
|
||||
|
||||
lightDir = normalize(lightDir);
|
||||
attenuation = 1.0 / (1.0 + lightAttenuation[i] * dist);
|
||||
attenuation = 1.0 / (1.0 + lights[i].attenuation * dist);
|
||||
}
|
||||
}
|
||||
vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial, float gloss, float fresnel, float shadow, float aoFactor)
|
||||
@@ -239,10 +282,7 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
|
||||
vec3 lightDiffuse = vec3(0.0, 0.0, 0.0);
|
||||
vec3 lightSpecular = vec3(0.0, 0.0, 0.0);
|
||||
#pragma optionNV unroll all
|
||||
for (int i = 0; i < MAX_LIGHTS; ++i) {
|
||||
if (i > n_lights)
|
||||
break;
|
||||
|
||||
for (int i = 0; i < n_lights; ++i) {
|
||||
if(i > 0) {
|
||||
shadow = 1.0;
|
||||
}
|
||||
@@ -254,17 +294,14 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
|
||||
vec3 halfVec = normalize(lightDir + eyeDir);
|
||||
float NdotL = max(dot(normal, lightDir), 0.0);
|
||||
// Ambient, Diffuse, and Specular
|
||||
lightDiffuse += (lightDiffuseColor[i].rgb * diffuseFactor * NdotL * attenuation) * shadow;
|
||||
lightSpecular += lightSpecColor[i] * SpecularBlinnPhong(specularMaterial, lightDir, normal, halfVec, exp2(10.0 * gloss + 1.0), fresnel, NdotL) * attenuation * shadow;
|
||||
lightDiffuse += (lights[i].diffuse_color.rgb * diffuseFactor * NdotL * attenuation) * shadow;
|
||||
lightSpecular += lights[i].spec_color * SpecularBlinnPhong(specularMaterial, lightDir, normal, halfVec, exp2(10.0 * gloss + 1.0), fresnel, NdotL) * attenuation * shadow;
|
||||
}
|
||||
return diffuseMaterial * (lightAmbient + lightDiffuse) + lightSpecular;
|
||||
}
|
||||
#endif
|
||||
void main()
|
||||
{
|
||||
#ifdef FLAG_TRANSFORM
|
||||
if(fragNotVisible >= 0.9) { discard; }
|
||||
#endif
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
// need depth and depth squared for variance shadow maps
|
||||
fragOut0 = vec4(fragPosition.z, fragPosition.z * fragPosition.z * VARIANCE_SHADOW_SCALE_INV, 0.0, 1.0);
|
||||
@@ -283,14 +320,14 @@ void main()
|
||||
#ifdef FLAG_AMBIENT_MAP
|
||||
// red channel is ambient occlusion factor which only affects ambient lighting.
|
||||
// green is cavity occlusion factor which only affects diffuse and specular lighting.
|
||||
aoFactors = texture(sAmbientmap, texCoord).xy;
|
||||
aoFactors = texture(sAmbientmap, vec3(texCoord, float(sAmbientmapIndex))).xy;
|
||||
#endif
|
||||
vec3 unitNormal = normalize(fragNormal);
|
||||
vec3 normal = unitNormal;
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
// Normal map - convert from DXT5nm
|
||||
vec2 normalSample;
|
||||
normal.rg = normalSample = (texture(sNormalmap, texCoord).ag * 2.0) - 1.0;
|
||||
normal.rg = normalSample = (texture(sNormalmap, vec3(texCoord, float(sNormalmapIndex))).ag * 2.0) - 1.0;
|
||||
normal.b = clamp(sqrt(1.0 - dot(normal.rg, normal.rg)), 0.0001, 1.0);
|
||||
normal = fragTangentMatrix * normal;
|
||||
float norm = length(normal);
|
||||
@@ -312,7 +349,7 @@ void main()
|
||||
diffuseTexCoord = texCoord + distort*(1.0-anim_timer);
|
||||
}
|
||||
#endif
|
||||
baseColor = texture(sBasemap, diffuseTexCoord);
|
||||
baseColor = texture(sBasemap, vec3(diffuseTexCoord, float(sBasemapIndex)));
|
||||
if ( blend_alpha == 0 && baseColor.a < 0.95 ) discard; // if alpha blending is not on, discard transparent pixels
|
||||
// premultiply alpha if blend_alpha is 1. assume that our blend function is srcColor + (1-Alpha)*destColor.
|
||||
// if blend_alpha is 2, assume blend func is additive and don't modify color
|
||||
@@ -324,7 +361,7 @@ void main()
|
||||
baseColor.rgb = pow(baseColor.rgb, vec3(SRGB_GAMMA));
|
||||
#endif
|
||||
#ifdef FLAG_SPEC_MAP
|
||||
specColor = texture(sSpecmap, texCoord);
|
||||
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
|
||||
if(alphaGloss) glossData = specColor.a;
|
||||
if(overrideSpec) {
|
||||
specColor.rgb = specClr;
|
||||
@@ -343,7 +380,7 @@ void main()
|
||||
#ifdef FLAG_MISC_MAP
|
||||
#ifdef FLAG_TEAMCOLOR
|
||||
vec4 teamMask = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
teamMask = texture(sMiscmap, texCoord);
|
||||
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
|
||||
vec3 base = max(base_color - vec3(0.5), vec3(0.0));
|
||||
vec3 stripe = max(stripe_color - vec3(0.5), vec3(0.0));
|
||||
baseColor.rgb += (base * teamMask.x) + (stripe * teamMask.y);
|
||||
@@ -376,7 +413,7 @@ void main()
|
||||
baseColor.rgb += envColour.rgb * FresnelLazarovEnv(specColor.rgb, eyeDir, normal, glossData);
|
||||
#endif
|
||||
#ifdef FLAG_GLOW_MAP
|
||||
vec3 glowColor = texture(sGlowmap, texCoord).rgb;
|
||||
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
|
||||
if(overrideGlow) glowColor = glowClr;
|
||||
#ifdef FLAG_HDR
|
||||
glowColor = pow(glowColor, vec3(SRGB_GAMMA)) * 3.0f;
|
||||
|
||||
+107
-12
@@ -1,35 +1,130 @@
|
||||
#extension GL_ARB_gpu_shader5: enable
|
||||
|
||||
layout (triangles) in;
|
||||
layout (triangle_strip, max_vertices = 3) out;
|
||||
uniform mat4 shadow_proj_matrix[4];
|
||||
#ifdef GL_ARB_gpu_shader5
|
||||
layout(invocations = 4) in;
|
||||
#endif
|
||||
|
||||
#define MAX_LIGHTS 8
|
||||
struct model_light {
|
||||
vec4 position;
|
||||
|
||||
vec3 diffuse_color;
|
||||
int light_type;
|
||||
|
||||
vec3 spec_color;
|
||||
float attenuation;
|
||||
|
||||
vec3 direction;
|
||||
};
|
||||
|
||||
layout (std140) uniform modelData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 modelMatrix;
|
||||
mat4 viewMatrix;
|
||||
mat4 projMatrix;
|
||||
mat4 textureMatrix;
|
||||
mat4 shadow_mv_matrix;
|
||||
mat4 shadow_proj_matrix[4];
|
||||
mat4 envMatrix;
|
||||
|
||||
vec4 color;
|
||||
|
||||
model_light lights[MAX_LIGHTS];
|
||||
|
||||
float extrudeWidth;
|
||||
float fogStart;
|
||||
float fogScale;
|
||||
int buffer_matrix_offset;
|
||||
|
||||
vec4 clip_equation;
|
||||
|
||||
float thruster_scale;
|
||||
bool use_clip_plane;
|
||||
int n_lights;
|
||||
float defaultGloss;
|
||||
|
||||
vec3 ambientFactor;
|
||||
int desaturate;
|
||||
|
||||
vec3 diffuseFactor;
|
||||
int blend_alpha;
|
||||
|
||||
vec3 emissionFactor;
|
||||
bool overrideDiffuse;
|
||||
|
||||
vec3 diffuseClr;
|
||||
bool overrideGlow;
|
||||
|
||||
vec3 glowClr;
|
||||
bool overrideSpec;
|
||||
|
||||
vec3 specClr;
|
||||
bool alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
bool alpha_spec;
|
||||
int effect_num;
|
||||
|
||||
vec4 fogColor;
|
||||
|
||||
vec3 base_color;
|
||||
float anim_timer;
|
||||
|
||||
vec3 stripe_color;
|
||||
float vpwidth;
|
||||
|
||||
float vpheight;
|
||||
bool team_glow_enabled;
|
||||
float znear;
|
||||
float zfar;
|
||||
|
||||
float veryneardist;
|
||||
float neardist;
|
||||
float middist;
|
||||
float fardist;
|
||||
|
||||
vec2 normalAlphaMinMax;
|
||||
int sBasemapIndex;
|
||||
int sGlowmapIndex;
|
||||
|
||||
int sSpecmapIndex;
|
||||
int sNormalmapIndex;
|
||||
int sAmbientmapIndex;
|
||||
int sMiscmapIndex;
|
||||
};
|
||||
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
in float geoInstance[];
|
||||
#endif
|
||||
in vec3 geoNormal[];
|
||||
in vec4 geoTexCoord[];
|
||||
out vec4 fragPosition;
|
||||
out vec3 fragNormal;
|
||||
out vec4 fragTexCoord;
|
||||
#ifdef FLAG_TRANSFORM
|
||||
in float geoNotVisible[];
|
||||
out float fragNotVisible;
|
||||
#endif
|
||||
void main(void)
|
||||
{
|
||||
#ifdef GL_ARB_gpu_shader5
|
||||
int instanceID = gl_InvocationID;
|
||||
#else
|
||||
int instanceID = int(geoInstance[0]);
|
||||
for(int vert = 0; vert < gl_in.length(); vert++)
|
||||
#endif
|
||||
for(int vert = 0; vert < gl_in.length(); vert++)
|
||||
{
|
||||
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
|
||||
if(gl_Position.z < -1.0)
|
||||
gl_Position.z = -1.0;
|
||||
fragPosition = gl_in[vert].gl_Position;
|
||||
fragPosition = gl_in[vert].gl_Position;
|
||||
fragNormal = geoNormal[vert];
|
||||
fragTexCoord = geoTexCoord[vert];
|
||||
|
||||
gl_Layer = instanceID;
|
||||
#ifdef FLAG_TRANSFORM
|
||||
fragNotVisible = geoNotVisible[0];
|
||||
#endif
|
||||
#ifdef FLAG_CLIP
|
||||
#if defined(FLAG_CLIP) || defined(FLAG_TRANSFORM)
|
||||
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
|
||||
#endif
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
||||
+113
-41
@@ -1,41 +1,117 @@
|
||||
#extension GL_ARB_gpu_shader5: enable
|
||||
|
||||
#define MAX_LIGHTS 8
|
||||
|
||||
struct model_light {
|
||||
vec4 position;
|
||||
|
||||
vec3 diffuse_color;
|
||||
int light_type;
|
||||
|
||||
vec3 spec_color;
|
||||
float attenuation;
|
||||
|
||||
vec3 direction;
|
||||
};
|
||||
|
||||
layout (std140) uniform modelData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 modelMatrix;
|
||||
mat4 viewMatrix;
|
||||
mat4 projMatrix;
|
||||
mat4 textureMatrix;
|
||||
mat4 shadow_mv_matrix;
|
||||
mat4 shadow_proj_matrix[4];
|
||||
mat4 envMatrix;
|
||||
|
||||
vec4 color;
|
||||
|
||||
model_light lights[MAX_LIGHTS];
|
||||
|
||||
float extrudeWidth;
|
||||
float fogStart;
|
||||
float fogScale;
|
||||
int buffer_matrix_offset;
|
||||
|
||||
vec4 clip_equation;
|
||||
|
||||
float thruster_scale;
|
||||
bool use_clip_plane;
|
||||
int n_lights;
|
||||
float defaultGloss;
|
||||
|
||||
vec3 ambientFactor;
|
||||
int desaturate;
|
||||
|
||||
vec3 diffuseFactor;
|
||||
int blend_alpha;
|
||||
|
||||
vec3 emissionFactor;
|
||||
bool overrideDiffuse;
|
||||
|
||||
vec3 diffuseClr;
|
||||
bool overrideGlow;
|
||||
|
||||
vec3 glowClr;
|
||||
bool overrideSpec;
|
||||
|
||||
vec3 specClr;
|
||||
bool alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
bool alpha_spec;
|
||||
int effect_num;
|
||||
|
||||
vec4 fogColor;
|
||||
|
||||
vec3 base_color;
|
||||
float anim_timer;
|
||||
|
||||
vec3 stripe_color;
|
||||
float vpwidth;
|
||||
|
||||
float vpheight;
|
||||
bool team_glow_enabled;
|
||||
float znear;
|
||||
float zfar;
|
||||
|
||||
float veryneardist;
|
||||
float neardist;
|
||||
float middist;
|
||||
float fardist;
|
||||
|
||||
vec2 normalAlphaMinMax;
|
||||
int sBasemapIndex;
|
||||
int sGlowmapIndex;
|
||||
|
||||
int sSpecmapIndex;
|
||||
int sNormalmapIndex;
|
||||
int sAmbientmapIndex;
|
||||
int sMiscmapIndex;
|
||||
};
|
||||
|
||||
in vec4 vertPosition;
|
||||
in vec4 vertTexCoord;
|
||||
in vec3 vertNormal;
|
||||
in vec4 vertTangent;
|
||||
in float vertModelID;
|
||||
uniform mat4 modelViewMatrix;
|
||||
uniform mat4 modelMatrix;
|
||||
uniform mat4 viewMatrix;
|
||||
uniform mat4 projMatrix;
|
||||
uniform mat4 textureMatrix;
|
||||
uniform vec4 color;
|
||||
#ifdef FLAG_NORMAL_EXTRUDE
|
||||
uniform float extrudeWidth;
|
||||
#endif
|
||||
#ifdef FLAG_ENV_MAP
|
||||
uniform mat4 envMatrix;
|
||||
out vec3 fragEnvReflect;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
out mat3 fragTangentMatrix;
|
||||
#endif
|
||||
#ifdef FLAG_FOG
|
||||
uniform float fogStart;
|
||||
uniform float fogScale;
|
||||
out float fragFogDist;
|
||||
#endif
|
||||
#ifdef FLAG_TRANSFORM
|
||||
uniform samplerBuffer transform_tex;
|
||||
uniform int buffer_matrix_offset;
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
out float geoNotVisible;
|
||||
#else
|
||||
out float fragNotVisible;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
out float geoInstance;
|
||||
uniform mat4 shadow_proj_matrix[4];
|
||||
#endif
|
||||
out vec3 geoNormal;
|
||||
out vec4 geoTexCoord;
|
||||
#else
|
||||
@@ -44,27 +120,18 @@ out vec3 fragNormal;
|
||||
out vec4 fragTexCoord;
|
||||
#endif
|
||||
#ifdef FLAG_SHADOWS
|
||||
uniform mat4 shadow_mv_matrix;
|
||||
uniform mat4 shadow_proj_matrix[4];
|
||||
out vec4 fragShadowUV[4];
|
||||
out vec4 fragShadowPos;
|
||||
#endif
|
||||
#ifdef FLAG_THRUSTER
|
||||
uniform float thruster_scale;
|
||||
#endif
|
||||
#ifdef FLAG_CLIP
|
||||
uniform int use_clip_plane;
|
||||
uniform vec4 clip_equation;
|
||||
#endif
|
||||
#ifdef FLAG_TRANSFORM
|
||||
#define TEXELS_PER_MATRIX 4
|
||||
void getModelTransform(inout mat4 transform, out float invisible, int id, int matrix_offset)
|
||||
void getModelTransform(inout mat4 transform, out bool invisible, int id, int matrix_offset)
|
||||
{
|
||||
transform[0] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX);
|
||||
transform[1] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 1);
|
||||
transform[2] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 2);
|
||||
transform[3] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 3);
|
||||
invisible = transform[3].w;
|
||||
invisible = transform[3].w >= 0.9;
|
||||
transform[3].w = 1.0;
|
||||
}
|
||||
#endif
|
||||
@@ -88,13 +155,10 @@ void main()
|
||||
mat4 orient = mat4(1.0);
|
||||
mat4 scale = mat4(1.0);
|
||||
#ifdef FLAG_TRANSFORM
|
||||
float invisible;
|
||||
getModelTransform(orient, invisible, int(vertModelID), buffer_matrix_offset);
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
geoNotVisible = invisible;
|
||||
#else
|
||||
fragNotVisible = invisible;
|
||||
#endif
|
||||
bool clipModel;
|
||||
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
|
||||
#else
|
||||
bool clipModel = false;
|
||||
#endif
|
||||
texCoord = textureMatrix * vertTexCoord;
|
||||
vec4 vertex = vertPosition;
|
||||
@@ -108,11 +172,15 @@ void main()
|
||||
position = modelViewMatrix * orient * vertex;
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
gl_Position = position;
|
||||
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
#ifdef APPLE
|
||||
geoInstance = float(gl_InstanceIDARB);
|
||||
geoInstance = float(gl_InstanceIDARB);
|
||||
#else
|
||||
geoInstance = float(gl_InstanceID);
|
||||
geoInstance = float(gl_InstanceID);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
gl_Position = projMatrix * position;
|
||||
#endif
|
||||
@@ -141,11 +209,15 @@ void main()
|
||||
fragFogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
|
||||
#endif
|
||||
#ifdef FLAG_CLIP
|
||||
if(use_clip_plane == 1) {
|
||||
if (clipModel) {
|
||||
gl_ClipDistance[0] = -1.0;
|
||||
} else if(use_clip_plane) {
|
||||
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
|
||||
} else {
|
||||
gl_ClipDistance[0] = -1.0f;
|
||||
gl_ClipDistance[0] = 1.0;
|
||||
}
|
||||
#elif defined(FLAG_TRANSFORM)
|
||||
gl_ClipDistance[0] = clipModel ? -1.0 : 1.0;
|
||||
#endif
|
||||
#ifndef FLAG_SHADOW_MAP
|
||||
fragPosition = position;
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
|
||||
// Enabled at all times but the define is kept here in case this should be configurable in the future
|
||||
#define EDGE_AA
|
||||
|
||||
layout(std140) uniform NanoVGUniformData {
|
||||
mat3 scissorMat;
|
||||
|
||||
mat3 paintMat;
|
||||
|
||||
vec4 innerCol;
|
||||
|
||||
vec4 outerCol;
|
||||
|
||||
vec2 scissorExt;
|
||||
vec2 scissorScale;
|
||||
|
||||
vec2 extent;
|
||||
float radius;
|
||||
float feather;
|
||||
|
||||
float strokeMult;
|
||||
float strokeThr;
|
||||
int texType;
|
||||
int type;
|
||||
|
||||
vec2 viewSize;
|
||||
int texArrayIndex;
|
||||
};
|
||||
|
||||
uniform sampler2DArray nvg_tex;
|
||||
|
||||
in vec2 ftcoord;
|
||||
in vec2 fpos;
|
||||
out vec4 outColor;
|
||||
|
||||
float sdroundrect(vec2 pt, vec2 ext, float rad) {
|
||||
vec2 ext2 = ext - vec2(rad,rad);
|
||||
vec2 d = abs(pt) - ext2;
|
||||
return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad;
|
||||
}
|
||||
|
||||
// Scissoring
|
||||
float scissorMask(vec2 p) {
|
||||
vec2 sc = (abs((scissorMat * vec3(p,1.0)).xy) - scissorExt);
|
||||
sc = vec2(0.5,0.5) - sc * scissorScale;
|
||||
return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);
|
||||
}
|
||||
#ifdef EDGE_AA
|
||||
// Stroke - from [0..1] to clipped pyramid, where the slope is 1px.
|
||||
float strokeMask() {
|
||||
return min(1.0, (1.0-abs(ftcoord.x*2.0-1.0))*strokeMult) * min(1.0, ftcoord.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
// The value the distance field has when the pixel is exactly on the edge. This needs to match the values in fontstash.h!
|
||||
const float ON_EDGE_DISTANCE = 180.0 / 255.0;
|
||||
|
||||
void main(void) {
|
||||
vec4 result;
|
||||
float scissor = scissorMask(fpos);
|
||||
#ifdef EDGE_AA
|
||||
float strokeAlpha = strokeMask();
|
||||
#else
|
||||
float strokeAlpha = 1.0;
|
||||
#endif
|
||||
#ifdef EDGE_AA
|
||||
if (strokeAlpha < strokeThr) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
if (type == 0) { // Gradient
|
||||
// Calculate gradient color using box gradient
|
||||
vec2 pt = (paintMat * vec3(fpos,1.0)).xy;
|
||||
float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);
|
||||
vec4 color = mix(innerCol,outerCol,d);
|
||||
// Combine alpha
|
||||
color *= strokeAlpha * scissor;
|
||||
result = color;
|
||||
} else if (type == 1) { // Image
|
||||
// Calculate color fron texture
|
||||
vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;
|
||||
vec4 color = texture(nvg_tex, vec3(pt, float(texArrayIndex)));
|
||||
// Apply color tint and alpha.
|
||||
if (texType == 1) color = vec4(color.xyz*color.w,color.w);
|
||||
if (texType == 2) color = vec4(color.r);
|
||||
color *= innerCol;
|
||||
// Combine alpha
|
||||
color *= strokeAlpha * scissor;
|
||||
result = color;
|
||||
} else if (type == 2) { // Stencil fill
|
||||
result = vec4(1,1,1,1);
|
||||
} else if (type == 3) { // Textured tris
|
||||
vec4 color = texture(nvg_tex, vec3(ftcoord, float(texArrayIndex)));
|
||||
if (texType == 1) color = vec4(color.xyz*color.w,color.w); if (texType == 2) color = vec4(color.x); color *= scissor;
|
||||
result = color * innerCol;
|
||||
} else if (type == 4) { // Distance vector text
|
||||
vec4 color = texture(nvg_tex, vec3(ftcoord, float(texArrayIndex)));
|
||||
float dist = color.r;
|
||||
|
||||
float width = fwidth(dist) / 2.0;
|
||||
float alpha = smoothstep(ON_EDGE_DISTANCE - width, ON_EDGE_DISTANCE + width, dist);
|
||||
|
||||
color = innerCol * alpha;
|
||||
|
||||
result = color * scissor;
|
||||
}
|
||||
outColor = result;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
layout(std140) uniform NanoVGUniformData {
|
||||
mat3 scissorMat;
|
||||
|
||||
mat3 paintMat;
|
||||
|
||||
vec4 innerCol;
|
||||
|
||||
vec4 outerCol;
|
||||
|
||||
vec2 scissorExt;
|
||||
vec2 scissorScale;
|
||||
|
||||
vec2 extent;
|
||||
float radius;
|
||||
float feather;
|
||||
|
||||
float strokeMult;
|
||||
float strokeThr;
|
||||
int texType;
|
||||
int type;
|
||||
|
||||
vec2 viewSize;
|
||||
int texArrayIndex;
|
||||
};
|
||||
|
||||
in vec2 vertPosition;
|
||||
in vec2 vertTexCoord;
|
||||
|
||||
out vec2 ftcoord;
|
||||
out vec2 fpos;
|
||||
|
||||
void main(void) {
|
||||
ftcoord = vertTexCoord;
|
||||
fpos = vertPosition;
|
||||
gl_Position = vec4(2.0*vertPosition.x/viewSize.x - 1.0, 1.0 - 2.0*vertPosition.y/viewSize.y, 0, 1);
|
||||
}
|
||||
@@ -2,17 +2,14 @@ in vec4 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2D baseMap;
|
||||
uniform int alphaTexture;
|
||||
uniform int noTexturing;
|
||||
uniform int srgb;
|
||||
uniform float intensity;
|
||||
uniform float alphaThreshold;
|
||||
#define SRGB_GAMMA 2.2
|
||||
void main()
|
||||
{
|
||||
vec4 baseColor = texture(baseMap, fragTexCoord.xy);
|
||||
if(alphaThreshold > baseColor.a) discard;
|
||||
|
||||
baseColor.rgb = (srgb == 1) ? pow(baseColor.rgb, vec3(SRGB_GAMMA)) : baseColor.rgb;
|
||||
vec4 blendColor = (srgb == 1) ? vec4(pow(fragColor.rgb, vec3(SRGB_GAMMA)), fragColor.a) : fragColor;
|
||||
fragOut0 = mix(mix(baseColor * blendColor, vec4(blendColor.rgb, baseColor.r * blendColor.a), float(alphaTexture)), blendColor, float(noTexturing)) * intensity;
|
||||
}
|
||||
fragOut0 = mix(baseColor * blendColor, blendColor, float(noTexturing));
|
||||
}
|
||||
@@ -26,6 +26,9 @@ uniform float cutoff;
|
||||
#ifdef FLAG_DITH
|
||||
uniform float dither;
|
||||
#endif
|
||||
#ifdef FLAG_TINT
|
||||
uniform vec3 tint;
|
||||
#endif
|
||||
uniform sampler2D blurred_tex;
|
||||
uniform sampler2D depth_tex;
|
||||
void main()
|
||||
@@ -98,7 +101,10 @@ void main()
|
||||
float downsampling_factor = 4;
|
||||
float bias = 0.5;
|
||||
color_out.rgb = floor(color_out.rgb * downsampling_factor + bias) / downsampling_factor;
|
||||
#endif
|
||||
#ifdef FLAG_TINT
|
||||
color_out.rgb += tint;
|
||||
#endif
|
||||
color_out.a = 1.0;
|
||||
fragOut0 = color_out;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
in vec4 fragImpactUV;
|
||||
in float fragNormOffset;
|
||||
uniform vec4 color;
|
||||
uniform sampler2D shieldMap;
|
||||
uniform sampler2DArray shieldMap;
|
||||
uniform int shieldMapIndex;
|
||||
uniform int srgb;
|
||||
out vec4 fragOut0;
|
||||
#define SRGB_GAMMA 2.2
|
||||
@@ -10,9 +11,9 @@ void main()
|
||||
{
|
||||
if(fragNormOffset < 0.0) discard;
|
||||
if(fragImpactUV.x < 0.0 || fragImpactUV.x > 1.0 || fragImpactUV.y < 0.0 || fragImpactUV.y > 1.0) discard;
|
||||
vec4 shieldColor = texture(shieldMap, fragImpactUV.xy);
|
||||
vec4 shieldColor = texture(shieldMap, vec3(fragImpactUV.xy, float(shieldMapIndex)));
|
||||
shieldColor.rgb = (srgb == 1) ? pow(shieldColor.rgb, vec3(SRGB_GAMMA)) * EMISSIVE_GAIN : shieldColor.rgb;
|
||||
vec4 blendColor = color;
|
||||
blendColor.rgb = (srgb == 1) ? pow(blendColor.rgb, vec3(SRGB_GAMMA)) * EMISSIVE_GAIN : blendColor.rgb;
|
||||
fragOut0 = shieldColor * blendColor;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2D ytex;
|
||||
uniform sampler2D utex;
|
||||
uniform sampler2D vtex;
|
||||
uniform sampler2DArray ytex;
|
||||
uniform sampler2DArray utex;
|
||||
uniform sampler2DArray vtex;
|
||||
void main()
|
||||
{
|
||||
vec3 val = vec3(texture(ytex, fragTexCoord.st).r - 0.0625, texture(utex, fragTexCoord.st).r - 0.5, texture(vtex, fragTexCoord.st).r - 0.5);
|
||||
float y = texture(ytex, vec3(fragTexCoord.st, 0.0)).r;
|
||||
float u = texture(utex, vec3(fragTexCoord.st, 0.0)).r;
|
||||
float v = texture(vtex, vec3(fragTexCoord.st, 0.0)).r;
|
||||
vec3 val = vec3(y - 0.0625, u - 0.5, v - 0.5);
|
||||
fragOut0.r = dot(val, vec3(1.1640625, 0.0, 1.59765625));
|
||||
fragOut0.g = dot(val, vec3(1.1640625, -0.390625, -0.8125));
|
||||
fragOut0.b = dot(val, vec3(1.1640625, 2.015625, 0.0));
|
||||
fragOut0.a = 1.0;
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ void fireball_play_warphole_open_sound(int ship_class, fireball *fb)
|
||||
}
|
||||
}
|
||||
|
||||
snd_play_3d(&Snds[sound_index], &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, range_multiplier); // play warp sound effect
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, range_multiplier); // play warp sound effect
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +111,7 @@ void fireball_play_warphole_close_sound(fireball *fb)
|
||||
return;
|
||||
}
|
||||
|
||||
snd_play_3d(&Snds[sound_index], &fireball_objp->pos, &Eye_position, fireball_objp->radius); // play warp sound effect
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius); // play warp sound effect
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,12 +27,21 @@
|
||||
#include <unistd.h>
|
||||
#include <cerrno>
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#ifdef SCP_SOLARIS
|
||||
#include <sys/filio.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
|
||||
#define WSAGetLastError() (errno)
|
||||
#define RESTART(syscall) \
|
||||
({ \
|
||||
__typeof__(syscall) _res; \
|
||||
do \
|
||||
_res = syscall; \
|
||||
while (_res == -1 && errno == EINTR); \
|
||||
_res; \
|
||||
})
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
@@ -109,6 +118,18 @@ int FS2NetD_ConnectToServer(const char *host, const char *port)
|
||||
ulong arg = 1;
|
||||
ioctlsocket(mySocket, FIONBIO, &arg);
|
||||
|
||||
// Where SO_NOSIGPIPE is defined (currently OS X):
|
||||
// prevent SIGPIPE, which is generated when sending after receiver disconnected
|
||||
// on other *nix use MSG_NOSIGNAL flag when sending data, or, failing that, use signal masking
|
||||
// see FS2NetD_SendData()
|
||||
#if defined(SCP_UNIX) && defined(SO_NOSIGPIPE)
|
||||
int nosigpipe = 1;
|
||||
if (setsockopt(mySocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nosigpipe, sizeof(nosigpipe)) == -1) {
|
||||
my_error = errno;
|
||||
ml_printf("FS2NetD ERROR: Couldn't set SO_NOSIGPIPE on socket (\"%s\")!", strerror(my_error));
|
||||
}
|
||||
#endif // SCP_UNIX && SO_NOSIGPIPE
|
||||
|
||||
// blasted MS, probably need to use getaddrinfo() here for Win32, but I
|
||||
// want to keep this as clean and simple as possible and that means
|
||||
// using an actual standard :)
|
||||
@@ -237,9 +258,74 @@ int FS2NetD_SendData(char *buffer, int blen)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
// on Unix with MSG_NOSIGNAL, prevent SIGPIPE, which is generated if receiver has disconnected
|
||||
// the MSG_NOSIGNAL flag doesn't work on OS X or Solaris
|
||||
// on OS X, use setsockopt() with SO_NOSIGPIPE instead, see above
|
||||
#if defined(SCP_UNIX) && defined(MSG_NOSIGNAL)
|
||||
flags |= MSG_NOSIGNAL;
|
||||
#endif // SCP_UNIX && MSG_NOSIGNAL
|
||||
|
||||
socklen_t to_len = sizeof(sockaddr);
|
||||
|
||||
return sendto(mySocket, buffer, blen, flags, (sockaddr*)&FS2NetD_addr, to_len);
|
||||
// Borrowed from Kroki:
|
||||
// https://github.com/kroki/XProbes/blob/1447f3d93b6dbf273919af15e59f35cca58fcc23/src/libxprobes.c#L156
|
||||
#if defined(SCP_UNIX) && !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE)
|
||||
/*
|
||||
We want to ignore possible SIGPIPE that we can generate on write.
|
||||
SIGPIPE is delivered *synchronously* and *only* to the thread
|
||||
doing the write. So if it is reported as already pending (which
|
||||
means the thread blocks it), then we do nothing: if we generate
|
||||
SIGPIPE, it will be merged with the pending one (there's no
|
||||
queuing), and that suits us well. If it is not pending, we block
|
||||
it in this thread (and we avoid changing signal action, because it
|
||||
is per-process).
|
||||
*/
|
||||
sigset_t pending;
|
||||
sigset_t sigpipe_mask;
|
||||
bool sigpipe_pending;
|
||||
bool sigpipe_unblock;
|
||||
sigemptyset(&pending);
|
||||
sigpending(&pending);
|
||||
sigpipe_pending = sigismember(&pending, SIGPIPE);
|
||||
if (!sigpipe_pending) {
|
||||
sigset_t blocked;
|
||||
sigemptyset(&blocked);
|
||||
pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &blocked);
|
||||
|
||||
/* Maybe is was blocked already? */
|
||||
sigpipe_unblock = ! sigismember(&blocked, SIGPIPE);
|
||||
}
|
||||
#endif /* defined(SCP_UNIX) && ! defined(MSG_NOSIGNAL) && ! defined(SO_NOSIGPIPE) */
|
||||
|
||||
auto sent_chars = sendto(mySocket, buffer, blen, flags, (sockaddr*)&FS2NetD_addr, to_len);
|
||||
|
||||
#if defined(SCP_UNIX) && !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE)
|
||||
/*
|
||||
If SIGPIPE was pending already we do nothing. Otherwise, if it
|
||||
become pending (i.e., we generated it), then we sigwait() it (thus
|
||||
clearing pending status). Then we unblock SIGPIPE, but only if it
|
||||
were us who blocked it.
|
||||
*/
|
||||
if (!sigpipe_pending) {
|
||||
sigemptyset(&pending);
|
||||
sigpending(&pending);
|
||||
if (sigismember(&pending, SIGPIPE)) {
|
||||
/*
|
||||
Protect ourselves from a situation when SIGPIPE was sent
|
||||
by the user to the whole process, and was delivered to
|
||||
other thread before we had a chance to wait for it.
|
||||
*/
|
||||
static const struct timespec nowait = { 0, 0 };
|
||||
RESTART(sigtimedwait(&sigpipe_mask, NULL, &nowait));
|
||||
}
|
||||
|
||||
if (sigpipe_unblock) {
|
||||
pthread_sigmask(SIG_UNBLOCK, &sigpipe_mask, NULL);
|
||||
}
|
||||
}
|
||||
#endif /* defined(SCP_UNIX) && ! defined(MSG_NOSIGNAL) && ! defined(SO_NOSIGPIPE) */
|
||||
|
||||
return sent_chars;
|
||||
}
|
||||
|
||||
bool FS2NetD_DataReady()
|
||||
|
||||
@@ -1186,7 +1186,9 @@ void parse_soundtrack()
|
||||
}
|
||||
|
||||
//Track doesn't exist and has nocreate, so don't create it
|
||||
Assertion(skip_to_start_of_string_either("#SoundTrack Start", "#Menu Music Start") || skip_to_string("#SoundTrack End"), "Couldn't find #Soundtrack Start, #Menu Music Start or #Soundtrack End. Music.tbl or -mus.tbm is invalid.\n");
|
||||
if ( !skip_to_start_of_string_either("#SoundTrack Start", "#Menu Music Start") && !skip_to_string("#SoundTrack End")) {
|
||||
error_display(1, "Couldn't find #Soundtrack Start, #Menu Music Start or #Soundtrack End.");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1281,7 +1283,7 @@ void parse_soundtrack()
|
||||
}
|
||||
|
||||
//We're done here.
|
||||
//required_string("#SoundTrack End");
|
||||
required_string("#SoundTrack End");
|
||||
|
||||
|
||||
// Goober5000 - set the valid flag according to whether we can load all our patterns
|
||||
@@ -1370,12 +1372,11 @@ void event_music_parse_musictbl(const char *filename)
|
||||
read_file_text(filename, CF_TYPE_TABLES);
|
||||
reset_parse();
|
||||
|
||||
while ( skip_to_start_of_string_either("#Soundtrack Start", "#Menu Music Start", NULL ) )
|
||||
while ( check_for_string("#Soundtrack Start") || check_for_string("#Menu Music Start") )
|
||||
{
|
||||
if ( optional_string("#Soundtrack Start") )
|
||||
{
|
||||
parse_soundtrack( );
|
||||
required_string("#Soundtrack End");
|
||||
}
|
||||
if ( optional_string("#Menu Music Start") )
|
||||
{
|
||||
|
||||
+245
-52
@@ -263,7 +263,7 @@ void gamesnd_play_iface(int n)
|
||||
if (Snds_iface_handle[n] >= 0)
|
||||
snd_stop(Snds_iface_handle[n]);
|
||||
|
||||
Snds_iface_handle[n] = snd_play(&Snds_iface[n]);
|
||||
Snds_iface_handle[n] = snd_play(gamesnd_get_interface_sound(n));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,16 +310,22 @@ int gamesnd_get_by_name(const char* name)
|
||||
int i = 0;
|
||||
for(SCP_vector<game_snd>::iterator snd = Snds.begin(); snd != Snds.end(); ++snd)
|
||||
{
|
||||
char *p = strrchr( snd->filename, '.' );
|
||||
if (snd->sound_entries.size() != 1) {
|
||||
// Ignore game sounds with more than one sound entry
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& entry = snd->sound_entries.front();
|
||||
char *p = strrchr( entry.filename, '.' );
|
||||
if(p == NULL)
|
||||
{
|
||||
if(!stricmp(snd->filename, name))
|
||||
if(!stricmp(entry.filename, name))
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(!strnicmp(snd->filename, name, p-snd->filename))
|
||||
else if(!strnicmp(entry.filename, name, p - entry.filename))
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
@@ -344,16 +350,22 @@ int gamesnd_get_by_iface_name(const char* name)
|
||||
int i = 0;
|
||||
for(SCP_vector<game_snd>::iterator snd = Snds_iface.begin(); snd != Snds_iface.end(); ++snd)
|
||||
{
|
||||
char *p = strrchr( snd->filename, '.' );
|
||||
if (snd->sound_entries.size() != 1) {
|
||||
// Ignore game sounds with more than one sound entry
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& entry = snd->sound_entries.front();
|
||||
char *p = strrchr( entry.filename, '.' );
|
||||
if(p == NULL)
|
||||
{
|
||||
if(!stricmp(snd->filename, name))
|
||||
if(!stricmp(entry.filename, name))
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(!strnicmp(snd->filename, name, p-snd->filename))
|
||||
else if(!strnicmp(entry.filename, name, p - entry.filename))
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
@@ -515,10 +527,12 @@ void gamesnd_preload_common_sounds()
|
||||
|
||||
Assert( Snds.size() <= INT_MAX );
|
||||
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
|
||||
if ( gs->filename[0] != 0 && strnicmp(gs->filename, NOX("none.wav"), 4) ) {
|
||||
if ( gs->preload ) {
|
||||
game_busy( NOX("** preloading common game sounds **") ); // Animate loading cursor... does nothing if loading screen not active.
|
||||
gs->id = snd_load(&(*gs));
|
||||
if ( gs->preload ) {
|
||||
for (auto& entry : gs->sound_entries) {
|
||||
if ( entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) ) {
|
||||
game_busy( NOX("** preloading common game sounds **") ); // Animate loading cursor... does nothing if loading screen not active.
|
||||
entry.id = snd_load(&entry, gs->flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -534,10 +548,12 @@ void gamesnd_load_gameplay_sounds()
|
||||
|
||||
Assert( Snds.size() <= INT_MAX );
|
||||
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
|
||||
if ( gs->filename[0] != 0 && strnicmp(gs->filename, NOX("none.wav"), 4) ) {
|
||||
if ( !gs->preload ) { // don't try to load anything that's already preloaded
|
||||
game_busy( NOX("** preloading gameplay sounds **") ); // Animate loading cursor... does nothing if loading screen not active.
|
||||
gs->id = snd_load(&(*gs));
|
||||
if ( !gs->preload ) { // don't try to load anything that's already preloaded
|
||||
for (auto& entry : gs->sound_entries) {
|
||||
if (entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4)) {
|
||||
game_busy(NOX("** preloading gameplay sounds **")); // Animate loading cursor... does nothing if loading screen not active.
|
||||
entry.id = snd_load(&entry, gs->flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -550,9 +566,11 @@ void gamesnd_unload_gameplay_sounds()
|
||||
{
|
||||
Assert( Snds.size() <= INT_MAX );
|
||||
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
|
||||
if ( gs->id != -1 ) {
|
||||
snd_unload( gs->id );
|
||||
gs->id = -1;
|
||||
for (auto& entry : gs->sound_entries) {
|
||||
if (entry.id != -1) {
|
||||
snd_unload(entry.id);
|
||||
entry.id = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -567,8 +585,10 @@ void gamesnd_load_interface_sounds()
|
||||
|
||||
Assert( Snds_iface.size() < INT_MAX );
|
||||
for (SCP_vector<game_snd>::iterator si = Snds_iface.begin(); si != Snds_iface.end(); ++si) {
|
||||
if ( si->filename[0] != 0 && strnicmp(si->filename, NOX("none.wav"), 4) ) {
|
||||
si->id = snd_load(&(*si));
|
||||
for (auto& entry : si->sound_entries) {
|
||||
if ( entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) ) {
|
||||
entry.id = snd_load(&entry, si->flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -580,10 +600,12 @@ void gamesnd_unload_interface_sounds()
|
||||
{
|
||||
Assert( Snds_iface.size() < INT_MAX );
|
||||
for (SCP_vector<game_snd>::iterator si = Snds_iface.begin(); si != Snds_iface.end(); ++si) {
|
||||
if ( si->id != -1 ) {
|
||||
snd_unload( si->id );
|
||||
si->id = -1;
|
||||
si->id_sig = -1;
|
||||
for (auto& entry : si->sound_entries) {
|
||||
if ( entry.id != -1 ) {
|
||||
snd_unload( entry.id );
|
||||
entry.id = -1;
|
||||
entry.id_sig = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -593,11 +615,15 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
int is_3d;
|
||||
int temp;
|
||||
|
||||
stuff_string(gs->filename, F_NAME, MAX_FILENAME_LEN, ",");
|
||||
// An old sound is just a single entry sound set
|
||||
gs->sound_entries.resize(1);
|
||||
auto& entry = gs->sound_entries.back();
|
||||
|
||||
if (!stricmp(gs->filename, NOX("empty")))
|
||||
stuff_string(entry.filename, F_NAME, MAX_FILENAME_LEN, ",");
|
||||
|
||||
if (!stricmp(entry.filename, NOX("empty")))
|
||||
{
|
||||
gs->filename[0] = 0;
|
||||
entry.filename[0] = 0;
|
||||
advance_to_eoln(NULL);
|
||||
return;
|
||||
}
|
||||
@@ -610,7 +636,9 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
gs->preload = true;
|
||||
}
|
||||
|
||||
stuff_float(&gs->default_volume);
|
||||
float default_volume;
|
||||
stuff_float(&default_volume);
|
||||
gs->volume_range = util::UniformFloatRange(default_volume);
|
||||
|
||||
stuff_int(&is_3d);
|
||||
|
||||
@@ -626,7 +654,7 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
gs->max = 0;
|
||||
|
||||
// silly retail, not abiding by its own format...
|
||||
if (!stricmp(gs->filename, "l_hit.wav") || !stricmp(gs->filename, "m_hit.wav"))
|
||||
if (!stricmp(entry.filename, "l_hit.wav") || !stricmp(entry.filename, "m_hit.wav"))
|
||||
{
|
||||
int temp_min, temp_max;
|
||||
|
||||
@@ -636,7 +664,7 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
ignore_gray_space();
|
||||
if (stuff_int_optional(&temp_max, true) == 2)
|
||||
{
|
||||
mprintf(("Dutifully converting retail sound %s, '%s' to a 3D sound...\n", gs->name.c_str(), gs->filename));
|
||||
mprintf(("Dutifully converting retail sound %s, '%s' to a 3D sound...\n", gs->name.c_str(), entry.filename));
|
||||
is_3d = 1;
|
||||
|
||||
gs->flags |= GAME_SND_USE_DS3D;
|
||||
@@ -647,11 +675,14 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
}
|
||||
}
|
||||
|
||||
// Default pitch is 1.0
|
||||
gs->pitch_range = util::UniformFloatRange(1.0f);
|
||||
|
||||
// check for extra values per Mantis #2408
|
||||
ignore_gray_space();
|
||||
if (stuff_int_optional(&temp, true) == 2)
|
||||
{
|
||||
Warning(LOCATION, "Unexpected extra value %d found for sound '%s' (filename '%s')! Check the format of the sounds.tbl (or .tbm) entry.", temp, gs->name.c_str(), gs->filename);
|
||||
Warning(LOCATION, "Unexpected extra value %d found for sound '%s' (filename '%s')! Check the format of the sounds.tbl (or .tbm) entry.", temp, gs->name.c_str(), entry.filename);
|
||||
}
|
||||
|
||||
advance_to_eoln(NULL);
|
||||
@@ -703,28 +734,32 @@ bool required_string_no_create(const char* token, bool no_create)
|
||||
return true;
|
||||
}
|
||||
|
||||
void parse_gamesnd_new(game_snd* gs, bool no_create)
|
||||
{
|
||||
char name[MAX_FILENAME_LEN];
|
||||
// New extended format found
|
||||
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
if (!stricmp(name, NOX("empty")))
|
||||
{
|
||||
gs->filename[0] = 0;
|
||||
return;
|
||||
static GameSoundCycleType parse_cycle_type() {
|
||||
if (optional_string("Sequential")) {
|
||||
return GameSoundCycleType::Sequential;
|
||||
} else if (optional_string("Random")) {
|
||||
return GameSoundCycleType::Random;
|
||||
} else {
|
||||
error_display(0, "Failed to parse sound cycle type. Expected 'sequential' or 'random'. Got [%.32s]", next_tokens());
|
||||
// Ignore everything until the end of the line. That should hopefully skip the bad token.
|
||||
advance_to_eoln(nullptr);
|
||||
return GameSoundCycleType::Sequential;
|
||||
}
|
||||
}
|
||||
|
||||
// If the name _doesn't_ match <same> put it into gs->filename;
|
||||
if (stricmp(name, "<same>"))
|
||||
{
|
||||
strcpy_s(gs->filename, name);
|
||||
}
|
||||
else if (!no_create)
|
||||
{
|
||||
// Throw an error if <same> was specified but we are creating a new entry
|
||||
error_display(1, "'<same>' is only allowed if +nocreate was specified!");
|
||||
return;
|
||||
void parse_gamesnd_soundset(game_snd* gs, bool no_create) {
|
||||
// If this gets called then we just saw "+Entry:" so we can begin processing the first entry immediately
|
||||
|
||||
do {
|
||||
// For now there is no way to change an existing entry so ever +Entry statement creates a new sound entry
|
||||
gs->sound_entries.resize(gs->sound_entries.size() + 1);
|
||||
auto& entry = gs->sound_entries.back();
|
||||
|
||||
stuff_string(entry.filename, F_NAME, MAX_FILENAME_LEN);
|
||||
} while (optional_string("+Entry:"));
|
||||
|
||||
if (required_string_no_create("+Cycle type:", no_create)) {
|
||||
gs->cycle_type = parse_cycle_type();
|
||||
}
|
||||
|
||||
if (required_string_no_create("+Preload:", no_create))
|
||||
@@ -734,7 +769,7 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
|
||||
|
||||
if (required_string_no_create("+Volume:", no_create))
|
||||
{
|
||||
stuff_float(&gs->default_volume);
|
||||
gs->volume_range = util::parseUniformRange(0.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (optional_string("+3D Sound:"))
|
||||
@@ -781,6 +816,109 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
|
||||
error_display(1, "Invalid enhanced sound limit: %d\n", temp_limit);
|
||||
}
|
||||
}
|
||||
|
||||
if (optional_string("+Pitch:")) {
|
||||
gs->pitch_range = util::parseUniformRange(0.0001f);
|
||||
} else if (!no_create) {
|
||||
// Default pitch is 1.0
|
||||
gs->pitch_range = util::UniformFloatRange(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void parse_gamesnd_new(game_snd* gs, bool no_create)
|
||||
{
|
||||
game_snd_entry* entry = nullptr;
|
||||
if (!no_create) {
|
||||
gs->sound_entries.resize(1);
|
||||
entry = &gs->sound_entries.back();
|
||||
} else {
|
||||
if (gs->sound_entries.size() != 1) {
|
||||
error_display(1, "The SCP syntax cannot be used to modify an existing sound that has more than one entry! Use the soundset syntax for adding new entries.");
|
||||
}
|
||||
entry = &gs->sound_entries.back();
|
||||
}
|
||||
|
||||
char name[MAX_FILENAME_LEN];
|
||||
// New extended format found
|
||||
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
if (!stricmp(name, NOX("empty")))
|
||||
{
|
||||
entry->filename[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the name _doesn't_ match <same> put it into gs->filename;
|
||||
if (stricmp(name, "<same>"))
|
||||
{
|
||||
strcpy_s(entry->filename, name);
|
||||
}
|
||||
else if (!no_create)
|
||||
{
|
||||
// Throw an error if <same> was specified but we are creating a new entry
|
||||
error_display(1, "'<same>' is only allowed if +nocreate was specified!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (required_string_no_create("+Preload:", no_create))
|
||||
{
|
||||
stuff_boolean(&gs->preload);
|
||||
}
|
||||
|
||||
if (required_string_no_create("+Volume:", no_create))
|
||||
{
|
||||
float default_volume;
|
||||
stuff_float(&default_volume);
|
||||
gs->volume_range = util::UniformFloatRange(default_volume);
|
||||
}
|
||||
|
||||
if (optional_string("+3D Sound:"))
|
||||
{
|
||||
gs->flags |= GAME_SND_USE_DS3D;
|
||||
required_string("+Attenuation start:");
|
||||
|
||||
stuff_int(&gs->min);
|
||||
|
||||
required_string("+Attenuation end:");
|
||||
|
||||
stuff_int(&gs->max);
|
||||
}
|
||||
else
|
||||
{
|
||||
gs->min = 0;
|
||||
gs->max = 0;
|
||||
}
|
||||
|
||||
// jg18 - enhanced sound parameters
|
||||
if (optional_string("+Priority:"))
|
||||
{
|
||||
SCP_string priority_string;
|
||||
stuff_string(priority_string, F_NAME);
|
||||
EnhancedSoundPriority priority = convert_to_enhanced_priority(priority_string.c_str());
|
||||
if (priority != SND_ENHANCED_PRIORITY_INVALID)
|
||||
{
|
||||
gs->enhanced_sound_data.priority= priority;
|
||||
}
|
||||
// else case not needed since conversion function displays message on error
|
||||
}
|
||||
|
||||
if (optional_string("+Limit:"))
|
||||
{
|
||||
int temp_limit;
|
||||
stuff_int(&temp_limit);
|
||||
|
||||
if ((temp_limit > 0) && (static_cast<uint>(temp_limit) <= SND_ENHANCED_MAX_LIMIT))
|
||||
{
|
||||
gs->enhanced_sound_data.limit = (unsigned int)temp_limit;
|
||||
}
|
||||
else
|
||||
{
|
||||
error_display(1, "Invalid enhanced sound limit: %d\n", temp_limit);
|
||||
}
|
||||
}
|
||||
|
||||
// Default pitch is 1.0
|
||||
gs->pitch_range = util::UniformFloatRange(1.0f);
|
||||
}
|
||||
|
||||
void gamesnd_parse_entry(game_snd *gs, bool no_create, SCP_vector<game_snd> *lookupVector)
|
||||
@@ -820,6 +958,8 @@ void gamesnd_parse_entry(game_snd *gs, bool no_create, SCP_vector<game_snd> *loo
|
||||
if (optional_string("+Filename:"))
|
||||
{
|
||||
parse_gamesnd_new(gs, no_create);
|
||||
} else if (optional_string("+Entry:")) {
|
||||
parse_gamesnd_soundset(gs, no_create);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1161,3 +1301,56 @@ void gamesnd_play_error_beep()
|
||||
{
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
}
|
||||
|
||||
game_snd* gamesnd_get_game_sound(int handle) {
|
||||
Assertion(handle >= 0 && handle < (int) Snds.size(), "Invalid game sound handle %d detected!", handle);
|
||||
return &Snds[handle];
|
||||
}
|
||||
game_snd* gamesnd_get_interface_sound(int handle) {
|
||||
Assertion(handle >= 0 && handle < (int) Snds_iface.size(), "Invalid interface sound handle %d detected!", handle);
|
||||
return &Snds_iface[handle];
|
||||
}
|
||||
|
||||
bool gamesnd_game_sound_valid(int sound) {
|
||||
return sound >= 0 && sound < (int) Snds.size();
|
||||
}
|
||||
bool gamesnd_interface_sound_valid(int sound) {
|
||||
return sound >= 0 && sound < (int) Snds_iface.size();
|
||||
}
|
||||
|
||||
float gamesnd_get_max_duration(game_snd* gs) {
|
||||
int max_length = 0;
|
||||
|
||||
for (auto& entry : gs->sound_entries) {
|
||||
Assertion(entry.id != -1, "Game sound must be loaded to determine maximum duration!");
|
||||
|
||||
max_length = std::max(max_length, snd_get_duration(entry.id));
|
||||
}
|
||||
|
||||
return max_length / gs->pitch_range.max();
|
||||
}
|
||||
game_snd_entry* gamesnd_choose_entry(game_snd* gs) {
|
||||
Assertion(!gs->sound_entries.empty(), "No sound entries found in game sound! This may not happen!");
|
||||
|
||||
size_t index = 0;
|
||||
switch(gs->cycle_type) {
|
||||
case GameSoundCycleType::Random:
|
||||
if (gs->sound_entries.size() == 1) {
|
||||
index = 0;
|
||||
} else {
|
||||
index = util::UniformRange<size_t>(0, gs->sound_entries.size() - 1).next();
|
||||
}
|
||||
break;
|
||||
case GameSoundCycleType::Sequential:
|
||||
if (gs->last_entry_index == std::numeric_limits<size_t>::max()) {
|
||||
// If this is the first time we must return the first sound to keep everything consistent
|
||||
index = 0;
|
||||
} else {
|
||||
index = (gs->last_entry_index + 1) % gs->sound_entries.size();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
gs->last_entry_index = index;
|
||||
return &gs->sound_entries[index];
|
||||
}
|
||||
+49
-3
@@ -49,9 +49,6 @@ void parse_sound_list(const char* tag, SCP_vector<int>& destination, const char*
|
||||
// this is a callback, so it needs to be a real function
|
||||
void common_play_highlight_sound();
|
||||
|
||||
extern SCP_vector<game_snd> Snds;
|
||||
extern SCP_vector<game_snd> Snds_iface;
|
||||
|
||||
/**
|
||||
* symbolic names for misc. game sounds.
|
||||
*
|
||||
@@ -356,4 +353,53 @@ enum InterfaceSoundsIndex {
|
||||
MIN_INTERFACE_SOUNDS =70 //!< MIN_INTERFACE_SOUNDS
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Gets a pointer to the game sound with the specified handle
|
||||
* @param handle The sound handle
|
||||
* @return The game sound handle
|
||||
*/
|
||||
game_snd* gamesnd_get_game_sound(int handle);
|
||||
|
||||
/**
|
||||
* @brief Gets a pointer to the interface sound with the specified handle
|
||||
* @param handle The sound handle
|
||||
* @return The interface sound handle
|
||||
*/
|
||||
game_snd* gamesnd_get_interface_sound(int handle);
|
||||
|
||||
/**
|
||||
* @brief Checks if the given sound handle is a valid game sound handle
|
||||
* @param sound The handle to check
|
||||
* @return @c true if the handle is valid
|
||||
*/
|
||||
bool gamesnd_game_sound_valid(int sound);
|
||||
|
||||
/**
|
||||
* @brief Checks if the given sound handle is a valid interface sound handle
|
||||
* @param sound The handle to check
|
||||
* @return @c true if the handle is valid
|
||||
*/
|
||||
bool gamesnd_interface_sound_valid(int sound);
|
||||
|
||||
/**
|
||||
* @brief Determines the maximum time this game sound may take to be played.
|
||||
*
|
||||
* @details Use this instead of snd_get_duration since a game sound may have multiple sounds with different durations.
|
||||
* This function also accounts for pitch changes which also changes the length of a sound.
|
||||
*
|
||||
* @param gs The game sound to check
|
||||
* @return The length of the sound in milliseconds
|
||||
*/
|
||||
float gamesnd_get_max_duration(game_snd* gs);
|
||||
|
||||
/**
|
||||
* @brief Chooses a sound entry for the specified game sound according to the rules specified by the game data
|
||||
*
|
||||
* @warning The returned pointer is temporary and may not be valid forever. Do no store this pointer anywhere!
|
||||
*
|
||||
* @param gs The game sound to choose the entry from
|
||||
* @return The chosen entry
|
||||
*/
|
||||
game_snd_entry* gamesnd_choose_entry(game_snd* gs);
|
||||
|
||||
#endif
|
||||
+30
-11
@@ -75,11 +75,22 @@ typedef struct vec4 {
|
||||
};
|
||||
} vec4;
|
||||
|
||||
struct bvec4 {
|
||||
bool x;
|
||||
bool y;
|
||||
bool z;
|
||||
bool w;
|
||||
};
|
||||
|
||||
// sometimes, you just need some integers
|
||||
typedef struct ivec3 {
|
||||
int x, y, z;
|
||||
} ivec3;
|
||||
|
||||
struct ivec2 {
|
||||
int x, y;
|
||||
};
|
||||
|
||||
/** Represents a point in 3d space.
|
||||
|
||||
Note: this is a struct, not a class, so no member functions. */
|
||||
@@ -426,10 +437,8 @@ public:
|
||||
SCP_string dump_stacktrace();
|
||||
|
||||
// DEBUG compile time catch for dangerous uses of memset/memcpy/memmove
|
||||
// would prefer std::is_trivially_copyable but it's not supported by gcc yet
|
||||
// ref: http://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html
|
||||
#ifndef NDEBUG
|
||||
#if SCP_COMPILER_CXX_STATIC_ASSERT && SCP_COMPILER_CXX_AUTO_TYPE
|
||||
#if SCP_COMPILER_CXX_AUTO_TYPE && SCP_COMPILER_CXX_STATIC_ASSERT && defined(HAVE_STD_IS_TRIVIALLY_COPYABLE)
|
||||
// feature support seems to be: gcc clang msvc
|
||||
// auto 4.4 2.9 2010
|
||||
// std::is_trivial 4.5 ? 2012 (2010 only duplicates std::is_pod)
|
||||
@@ -444,10 +453,20 @@ SCP_string dump_stacktrace();
|
||||
// Put into std to be compatible with code that uses std::mem*
|
||||
namespace std
|
||||
{
|
||||
|
||||
// This is a separate check which also checks if arrays are trivially copyable since Visual Studio 2013 thinks they are not
|
||||
#if SCP_COMPILER_IS_MSVC && _MSC_VER <= 1800
|
||||
template<typename T>
|
||||
using trivial_check = std::is_trivial<T>;
|
||||
#else
|
||||
template<typename T>
|
||||
using trivial_check = std::is_trivially_copyable<T>;
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
void *memset_if_trivial_else_error(T *memset_data, int ch, size_t count)
|
||||
{
|
||||
static_assert(std::is_trivial<T>::value, "memset on non-trivial object");
|
||||
static_assert(trivial_check<T>::value, "memset on non-trivial object");
|
||||
return ptr_memset(memset_data, ch, count);
|
||||
}
|
||||
|
||||
@@ -465,8 +484,8 @@ namespace std
|
||||
template<typename T, typename U>
|
||||
void *memcpy_if_trivial_else_error(T *memcpy_dest, U *src, size_t count)
|
||||
{
|
||||
static_assert(std::is_trivial<T>::value, "memcpy on non-trivial object T");
|
||||
static_assert(std::is_trivial<U>::value, "memcpy on non-trivial object U");
|
||||
static_assert(trivial_check<T>::value, "memcpy on non-trivial object T");
|
||||
static_assert(trivial_check<U>::value, "memcpy on non-trivial object U");
|
||||
return ptr_memcpy(memcpy_dest, src, count);
|
||||
}
|
||||
|
||||
@@ -481,20 +500,20 @@ namespace std
|
||||
template<typename U>
|
||||
void *memcpy_if_trivial_else_error(void *memcpy_dest, U *memcpy_src, size_t count)
|
||||
{
|
||||
static_assert(std::is_trivial<U>::value, "memcpy on non-trivial object U");
|
||||
static_assert(trivial_check<U>::value, "memcpy on non-trivial object U");
|
||||
return ptr_memcpy(memcpy_dest, memcpy_src, count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void *memcpy_if_trivial_else_error(T *memcpy_dest, void *memcpy_src, size_t count)
|
||||
{
|
||||
static_assert(std::is_trivial<T>::value, "memcpy on non-trivial object T");
|
||||
static_assert(trivial_check<T>::value, "memcpy on non-trivial object T");
|
||||
return ptr_memcpy(memcpy_dest, memcpy_src, count);
|
||||
}
|
||||
template<typename T>
|
||||
void *memcpy_if_trivial_else_error(T *memcpy_dest, const void *memcpy_src, size_t count)
|
||||
{
|
||||
static_assert(std::is_trivial<T>::value, "memcpy on non-trivial object T");
|
||||
static_assert(trivial_check<T>::value, "memcpy on non-trivial object T");
|
||||
return ptr_memcpy(memcpy_dest, memcpy_src, count);
|
||||
}
|
||||
|
||||
@@ -510,8 +529,8 @@ namespace std
|
||||
template<typename T, typename U>
|
||||
void *memmove_if_trivial_else_error(T *memmove_dest, U *memmove_src, size_t count)
|
||||
{
|
||||
static_assert(std::is_trivial<T>::value, "memmove on non-trivial object T");
|
||||
static_assert(std::is_trivial<U>::value, "memmove on non-trivial object U");
|
||||
static_assert(trivial_check<T>::value, "memmove on non-trivial object T");
|
||||
static_assert(trivial_check<U>::value, "memmove on non-trivial object U");
|
||||
return ptr_memmove(memmove_dest, memmove_src, count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,3 +67,11 @@
|
||||
#define unlikely(x) __builtin_expect((long) !!(x), 0L)
|
||||
|
||||
#define USED_VARIABLE __attribute__((used))
|
||||
|
||||
#if __has_cpp_attribute(fallthough)
|
||||
#define FALLTHROUGH [[fallthrough]]
|
||||
#elif __has_cpp_attribute(clang::fallthough)
|
||||
#define FALLTHROUGH [[clang::fallthrough]]
|
||||
#else
|
||||
#define FALLTHROUGH
|
||||
#endif
|
||||
@@ -51,3 +51,10 @@
|
||||
* This can be used to ensure that a static variable is present even if it isn't referenced in the translation unit
|
||||
*/
|
||||
#define USED_VARIABLE
|
||||
|
||||
/**
|
||||
* @brief For use in a case statement which falls through
|
||||
*
|
||||
* Some compilers issue a warning if a fallthrough is detected. This define can be used to suppress that warning.
|
||||
*/
|
||||
#define FALLTHROUGH
|
||||
@@ -65,4 +65,10 @@
|
||||
#define likely(x) __builtin_expect((long) !!(x), 1L)
|
||||
#define unlikely(x) __builtin_expect((long) !!(x), 0L)
|
||||
|
||||
#define USED_VARIABLE __attribute__((used))
|
||||
#define USED_VARIABLE __attribute__((used))
|
||||
|
||||
#if SCP_COMPILER_VERSION_MAJOR >= 7
|
||||
#define FALLTHROUGH [[fallthrough]]
|
||||
#else
|
||||
#define FALLTHROUGH
|
||||
#endif
|
||||
@@ -62,4 +62,10 @@
|
||||
|
||||
#define __STDC_FORMAT_MACROS 1
|
||||
|
||||
#define USED_VARIABLE __attribute__((used))
|
||||
#define USED_VARIABLE __attribute__((used))
|
||||
|
||||
#if SCP_COMPILER_VERSION_MAJOR >= 7
|
||||
#define FALLTHROUGH [[fallthough]]
|
||||
#else
|
||||
#define FALLTHROUGH
|
||||
#endif
|
||||
@@ -85,3 +85,5 @@
|
||||
#define unlikely(x)
|
||||
|
||||
#define USED_VARIABLE
|
||||
|
||||
#define FALLTHROUGH
|
||||
+117
-72
@@ -5,85 +5,130 @@
|
||||
* or otherwise commercially exploit the source or things you created based on the
|
||||
* source.
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "globalincs/version.h"
|
||||
|
||||
namespace gameversion
|
||||
{
|
||||
bool check_at_least(int major, int minor, int build, int revision)
|
||||
{
|
||||
if (FS_VERSION_MAJOR < major)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (FS_VERSION_MAJOR > major)
|
||||
{
|
||||
// Major is greater than the given version => the rest doesn't matter
|
||||
return true;
|
||||
}
|
||||
// major is now equal to our major version
|
||||
|
||||
if (FS_VERSION_MINOR < minor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (FS_VERSION_MINOR > minor)
|
||||
{
|
||||
// Minor is greater than the given version => the rest doesn't matter
|
||||
return true;
|
||||
}
|
||||
// minor is now equal to our minor version
|
||||
|
||||
if (FS_VERSION_BUILD < build)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (FS_VERSION_BUILD > build)
|
||||
{
|
||||
// build is greater than the given version => the rest doesn't matter
|
||||
return true;
|
||||
}
|
||||
// build is now equal to our build version
|
||||
|
||||
if (revision == 0)
|
||||
{
|
||||
// Special case, if there is no revision info, skip it
|
||||
return true;
|
||||
}
|
||||
if (FS_VERSION_REVIS == 0)
|
||||
{
|
||||
// Special case, when there is no revision ignore it
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FS_VERSION_REVIS < revision)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (FS_VERSION_REVIS > revision)
|
||||
{
|
||||
// build is greater than the given version => the rest doesn't matter
|
||||
return true;
|
||||
}
|
||||
|
||||
// revision is now equal to our revision version
|
||||
#include "parse/parselo.h"
|
||||
|
||||
namespace gameversion {
|
||||
|
||||
bool check_at_least(const version& v) {
|
||||
return get_executable_version() >= v;
|
||||
}
|
||||
|
||||
SCP_string format_version(const version& v) {
|
||||
SCP_stringstream ss;
|
||||
|
||||
ss << v.major << "." << v.minor << "." << v.build;
|
||||
|
||||
if (v.revision != 0) {
|
||||
ss << "." << v.revision;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
version parse_version() {
|
||||
version v;
|
||||
|
||||
required_string("+Major:");
|
||||
stuff_int(&v.major);
|
||||
|
||||
required_string("+Minor:");
|
||||
stuff_int(&v.minor);
|
||||
|
||||
required_string("+Build:");
|
||||
stuff_int(&v.build);
|
||||
|
||||
if (optional_string("+Revision:")) {
|
||||
stuff_int(&v.revision);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
version get_executable_version() {
|
||||
version v;
|
||||
v.major = FS_VERSION_MAJOR;
|
||||
v.minor = FS_VERSION_MINOR;
|
||||
v.build = FS_VERSION_BUILD;
|
||||
v.revision = FS_VERSION_REVIS;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
version::version(int major_in, int minor_in, int build_in, int revision_in) :
|
||||
major(major_in), minor(minor_in), build(build_in), revision(revision_in) {
|
||||
}
|
||||
bool version::operator<(const version& v) const {
|
||||
|
||||
if (major < v.major) {
|
||||
return true;
|
||||
}
|
||||
if (major > v.major) {
|
||||
// Major is greater than the given version => the rest doesn't matter
|
||||
return false;
|
||||
}
|
||||
// major is now equal to our major version
|
||||
|
||||
if (minor < v.minor) {
|
||||
return true;
|
||||
}
|
||||
if (minor > v.minor) {
|
||||
// Minor is greater than the given version => the rest doesn't matter
|
||||
return false;
|
||||
}
|
||||
// minor is now equal to our minor version
|
||||
|
||||
if (build < v.build) {
|
||||
return true;
|
||||
}
|
||||
if (build > v.build) {
|
||||
// build is greater than the given version => the rest doesn't matter
|
||||
return false;
|
||||
}
|
||||
// build is now equal to our build version
|
||||
|
||||
if (revision == 0 || v.revision == 0) {
|
||||
// Special case, if there is no revision info, then the versions are equal which means they are not less than each other
|
||||
return false;
|
||||
}
|
||||
|
||||
if (revision < v.revision) {
|
||||
return true;
|
||||
}
|
||||
if (revision > v.revision) {
|
||||
// build is greater than the given version => the rest doesn't matter
|
||||
return false;
|
||||
}
|
||||
|
||||
SCP_string format_version(int major, int minor, int build, int revision)
|
||||
{
|
||||
SCP_stringstream ss;
|
||||
|
||||
ss << major << "." << minor << "." << build;
|
||||
|
||||
if (revision != 0)
|
||||
{
|
||||
ss << "." << revision;
|
||||
|
||||
// revision is now equal to our revision version
|
||||
return false;
|
||||
}
|
||||
bool version::operator==(const version& other) const {
|
||||
if (major == other.major && minor == other.minor && build == other.build) {
|
||||
if (revision == 0 || other.revision == 0) {
|
||||
// Zero revisions always means that these are equal
|
||||
return true;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
|
||||
return revision == other.revision;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool version::operator>(const version& other) const {
|
||||
return other < *this;
|
||||
}
|
||||
bool version::operator<=(const version& other) const {
|
||||
return !(other < *this);
|
||||
}
|
||||
bool version::operator>=(const version& other) const {
|
||||
return !(*this < other);
|
||||
}
|
||||
bool version::operator!=(const version& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+50
-24
@@ -5,7 +5,7 @@
|
||||
* or otherwise commercially exploit the source or things you created based on the
|
||||
* source.
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -36,29 +36,55 @@
|
||||
|
||||
#include "project.h"
|
||||
|
||||
namespace gameversion
|
||||
{
|
||||
/**
|
||||
* @brief Checks if the current version is at least the given version
|
||||
*
|
||||
* @param major The major version to check
|
||||
* @param minor The minor version to check
|
||||
* @param build The build version to check
|
||||
* @param revision The revision version to check
|
||||
*
|
||||
* @returns @c true when we are at least the given version, @c false otherwise
|
||||
*/
|
||||
bool check_at_least(int major, int minor, int build, int revision);
|
||||
|
||||
/**
|
||||
* @brief Returns the string representation of the passed version
|
||||
* @param major The major version to format
|
||||
* @param minor The minor version to format
|
||||
* @param build The build version to format
|
||||
* @param revision The revision version to format
|
||||
* @returns A string representation of the version number
|
||||
*/
|
||||
SCP_string format_version(int major, int minor, int build, int revision);
|
||||
// The GCC POSIX headers seem to think defining a common word like "major" is a good idea...
|
||||
// FYI, no it isn't.
|
||||
#ifdef major
|
||||
#undef major
|
||||
#endif
|
||||
#ifdef minor
|
||||
#undef minor
|
||||
#endif
|
||||
|
||||
namespace gameversion {
|
||||
|
||||
struct version {
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
int build = 0;
|
||||
int revision = 0;
|
||||
|
||||
version() {}
|
||||
|
||||
version(int major, int minor, int build, int revision);
|
||||
|
||||
bool operator<(const version& other) const;
|
||||
bool operator==(const version& other) const;
|
||||
bool operator!=(const version& other) const;
|
||||
bool operator>(const version& rhs) const;
|
||||
bool operator<=(const version& rhs) const;
|
||||
bool operator>=(const version& rhs) const;
|
||||
};
|
||||
|
||||
version parse_version();
|
||||
|
||||
version get_executable_version();
|
||||
|
||||
/**
|
||||
* @brief Checks if the current version is at least the given version
|
||||
*
|
||||
* @param v The version to check
|
||||
*
|
||||
* @returns @c true when we are at least the given version, @c false otherwise
|
||||
*/
|
||||
bool check_at_least(const version& v);
|
||||
|
||||
/**
|
||||
* @brief Returns the string representation of the passed version
|
||||
* @param major The version to format
|
||||
* @returns A string representation of the version number
|
||||
*/
|
||||
SCP_string format_version(const version& v);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+185
-34
@@ -22,6 +22,8 @@
|
||||
#include "gamesequence/gamesequence.h" //WMC - for scripting hooks in gr_flip()
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/matrix.h"
|
||||
#include "graphics/light.h"
|
||||
#include "graphics/font.h"
|
||||
#include "graphics/grbatch.h"
|
||||
#include "graphics/grinternal.h"
|
||||
@@ -29,6 +31,8 @@
|
||||
#include "graphics/opengl/gropengldraw.h"
|
||||
#include "graphics/grstub.h"
|
||||
#include "graphics/paths/PathRenderer.h"
|
||||
#include "graphics/util/UniformBuffer.h"
|
||||
#include "graphics/util/UniformBufferManager.h"
|
||||
#include "io/keycontrol.h" // m!m
|
||||
#include "io/timer.h"
|
||||
#include "osapi/osapi.h"
|
||||
@@ -36,6 +40,7 @@
|
||||
#include "parse/parselo.h"
|
||||
#include "render/3d.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "utils/boost/hash_combine.h"
|
||||
|
||||
#if ( SDL_VERSION_ATLEAST(1, 2, 7) )
|
||||
#include "SDL_cpuinfo.h"
|
||||
@@ -96,6 +101,11 @@ float Gr_save_menu_zoomed_offset_X = 0.0f, Gr_save_menu_zoomed_offset_Y = 0.0f;
|
||||
|
||||
bool Save_custom_screen_size;
|
||||
|
||||
// Forward definitions
|
||||
static void uniform_buffer_managers_init();
|
||||
static void uniform_buffer_managers_deinit();
|
||||
static void uniform_buffer_managers_retire_buffers();
|
||||
|
||||
void gr_set_screen_scale(int w, int h, int zoom_w, int zoom_h, int max_w, int max_h, int center_w, int center_h, bool force_stretch)
|
||||
{
|
||||
bool do_zoom = zoom_w > 0 && zoom_h > 0 && (zoom_w != w || zoom_h != h);
|
||||
@@ -634,9 +644,16 @@ void gr_close()
|
||||
if ( !Gr_inited ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cleanup uniform buffer managers
|
||||
uniform_buffer_managers_deinit();
|
||||
|
||||
font::close();
|
||||
|
||||
gr_light_shutdown();
|
||||
|
||||
graphics::paths::PathRenderer::shutdown();
|
||||
|
||||
switch (gr_screen.mode) {
|
||||
case GR_OPENGL:
|
||||
gr_opengl_cleanup(true);
|
||||
@@ -649,6 +666,8 @@ void gr_close()
|
||||
Int3(); // Invalid graphics mode
|
||||
}
|
||||
|
||||
bm_close();
|
||||
|
||||
Gr_inited = 0;
|
||||
}
|
||||
|
||||
@@ -742,10 +761,7 @@ void gr_screen_resize(int width, int height)
|
||||
gr_screen.save_max_w_unscaled_zoomed = gr_screen.max_w_unscaled_zoomed;
|
||||
gr_screen.save_max_h_unscaled_zoomed = gr_screen.max_h_unscaled_zoomed;
|
||||
|
||||
if (gr_screen.mode == GR_OPENGL) {
|
||||
extern void opengl_setup_viewport();
|
||||
opengl_setup_viewport();
|
||||
}
|
||||
gr_setup_viewport();
|
||||
}
|
||||
|
||||
int gr_get_resolution_class(int width, int height)
|
||||
@@ -828,6 +844,7 @@ static bool gr_init_sub(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, i
|
||||
gr_screen.bytes_per_pixel= depth / 8;
|
||||
gr_screen.rendering_to_texture = -1;
|
||||
gr_screen.envmap_render_target = -1;
|
||||
gr_screen.line_width = 1.0f;
|
||||
gr_screen.mode = mode;
|
||||
gr_screen.res = res;
|
||||
gr_screen.aspect = 1.0f; // Normal PC screen
|
||||
@@ -1050,14 +1067,19 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
return false;
|
||||
}
|
||||
|
||||
mprintf(("Initializing path renderer...\n"));
|
||||
graphics::paths::PathRenderer::init();
|
||||
gr_light_init();
|
||||
|
||||
gr_set_palette_internal(Gr_current_palette_name, NULL, 0);
|
||||
|
||||
bm_init();
|
||||
io::mouse::CursorManager::init();
|
||||
|
||||
mprintf(("Initializing path renderer...\n"));
|
||||
graphics::paths::PathRenderer::init();
|
||||
|
||||
// Initialize uniform buffer managers
|
||||
uniform_buffer_managers_init();
|
||||
|
||||
bool missing_installation = false;
|
||||
if (!running_unittests && Web_cursor == nullptr) {
|
||||
if (Is_standalone) {
|
||||
@@ -2074,34 +2096,6 @@ void gr_shield_icon(coord2d coords[6], int resize_mode)
|
||||
g3_render_shield_icon(&gr_screen.current_color, coords, resize_mode);
|
||||
}
|
||||
|
||||
void gr_rect(int x, int y, int w, int h, int resize_mode)
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
return;
|
||||
}
|
||||
|
||||
g3_render_colored_rect(&gr_screen.current_color, x, y, w, h, resize_mode);
|
||||
}
|
||||
|
||||
void gr_shade(int x, int y, int w, int h, int resize_mode)
|
||||
{
|
||||
int r, g, b, a;
|
||||
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
return;
|
||||
}
|
||||
|
||||
r = (int)gr_screen.current_shader.r;
|
||||
g = (int)gr_screen.current_shader.g;
|
||||
b = (int)gr_screen.current_shader.b;
|
||||
a = (int)gr_screen.current_shader.c;
|
||||
|
||||
color clr;
|
||||
gr_init_alphacolor(&clr, r, g, b, a);
|
||||
|
||||
g3_render_colored_rect(&clr, x, y, w, h, resize_mode);
|
||||
}
|
||||
|
||||
void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha)
|
||||
{
|
||||
gr_screen.current_alpha = alpha;
|
||||
@@ -2123,6 +2117,11 @@ void gr_flip(bool execute_scripting)
|
||||
Script_system.EndFrame();
|
||||
}
|
||||
|
||||
gr_reset_immediate_buffer();
|
||||
|
||||
// Use this opportunity for retiring the uniform buffers
|
||||
uniform_buffer_managers_retire_buffers();
|
||||
|
||||
gr_screen.gf_flip();
|
||||
}
|
||||
|
||||
@@ -2242,3 +2241,155 @@ void gr_print_timestamp(int x, int y, fix timestamp, int resize_mode)
|
||||
|
||||
gr_string(x, y, time, resize_mode);
|
||||
}
|
||||
|
||||
static std::unique_ptr<graphics::util::UniformBufferManager>
|
||||
uniform_buffer_managers[static_cast<size_t>(uniform_block_type::NUM_BLOCK_TYPES)];
|
||||
|
||||
static void uniform_buffer_managers_init() {
|
||||
for (size_t i = 0; i < static_cast<size_t>(uniform_block_type::NUM_BLOCK_TYPES); ++i) {
|
||||
auto enumVal = static_cast<uniform_block_type>(i);
|
||||
|
||||
uniform_buffer_managers[i].reset(new graphics::util::UniformBufferManager(enumVal));
|
||||
}
|
||||
}
|
||||
static void uniform_buffer_managers_deinit() {
|
||||
for (auto& manager: uniform_buffer_managers) {
|
||||
manager.reset();
|
||||
}
|
||||
}
|
||||
static void uniform_buffer_managers_retire_buffers() {
|
||||
GR_DEBUG_SCOPE("Retiring unused uniform buffers");
|
||||
|
||||
for (auto& manager: uniform_buffer_managers) {
|
||||
manager->retireBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
graphics::util::UniformBuffer* gr_get_uniform_buffer(uniform_block_type type) {
|
||||
return uniform_buffer_managers[static_cast<size_t>(type)]->getBuffer();
|
||||
}
|
||||
|
||||
SCP_vector<DisplayData> gr_enumerate_displays()
|
||||
{
|
||||
// It seems that linux cannot handle having the video subsystem inited
|
||||
// too late
|
||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
|
||||
return SCP_vector<DisplayData>();
|
||||
}
|
||||
|
||||
SCP_vector<DisplayData> data;
|
||||
|
||||
auto num_displays = SDL_GetNumVideoDisplays();
|
||||
for (auto i = 0; i < num_displays; ++i) {
|
||||
DisplayData display;
|
||||
display.index = i;
|
||||
|
||||
SDL_Rect bounds;
|
||||
if (SDL_GetDisplayBounds(i, &bounds) == 0) {
|
||||
display.x = bounds.x;
|
||||
display.y = bounds.y;
|
||||
display.width = bounds.w;
|
||||
display.height = bounds.h;
|
||||
}
|
||||
|
||||
auto name = SDL_GetDisplayName(i);
|
||||
if (name != nullptr) {
|
||||
display.name = name;
|
||||
}
|
||||
|
||||
auto num_mods = SDL_GetNumDisplayModes(i);
|
||||
for (auto j = 0; j < num_mods; ++j) {
|
||||
SDL_DisplayMode mode;
|
||||
if (SDL_GetDisplayMode(i, j, &mode) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
VideoModeData videoMode;
|
||||
videoMode.width = mode.w;
|
||||
videoMode.height = mode.h;
|
||||
|
||||
int sdlBits = SDL_BITSPERPIXEL(mode.format);
|
||||
|
||||
if (SDL_ISPIXELFORMAT_ALPHA(mode.format)) {
|
||||
videoMode.bit_depth = sdlBits;
|
||||
} else {
|
||||
// Fix a few values
|
||||
if (sdlBits == 24) {
|
||||
videoMode.bit_depth = 32;
|
||||
} else if (sdlBits == 15) {
|
||||
videoMode.bit_depth = 16;
|
||||
} else {
|
||||
videoMode.bit_depth = sdlBits;
|
||||
}
|
||||
}
|
||||
|
||||
display.video_modes.push_back(videoMode);
|
||||
}
|
||||
|
||||
data.push_back(display);
|
||||
}
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
namespace std {
|
||||
|
||||
size_t hash<vertex_format_data>::operator()(const vertex_format_data& data) const {
|
||||
size_t seed = 0;
|
||||
boost::hash_combine(seed, (size_t)data.format_type);
|
||||
boost::hash_combine(seed, data.offset);
|
||||
boost::hash_combine(seed, data.stride);
|
||||
return seed;
|
||||
}
|
||||
size_t hash<vertex_layout>::operator()(const vertex_layout& data) const {
|
||||
return data.hash();
|
||||
}
|
||||
|
||||
}
|
||||
bool vertex_layout::resident_vertex_format(vertex_format_data::vertex_format format_type) const {
|
||||
return ( Vertex_mask & vertex_format_data::mask(format_type) ) ? true : false;
|
||||
}
|
||||
void vertex_layout::add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset) {
|
||||
// A stride value of 0 is not handled consistently by the graphics API so we must enforce that that does not happen
|
||||
Assertion(stride != 0, "The stride of a vertex component may not be zero!");
|
||||
|
||||
if ( resident_vertex_format(format_type) ) {
|
||||
// we already have a vertex component of this format type
|
||||
return;
|
||||
}
|
||||
|
||||
if (Vertex_mask == 0) {
|
||||
// This is the first element so we need to initialize the global stride here
|
||||
Vertex_stride = stride;
|
||||
}
|
||||
|
||||
Assertion(Vertex_stride == stride, "The strides of all elements must be the same in a vertex layout!");
|
||||
|
||||
Vertex_mask |= (1 << format_type);
|
||||
Vertex_components.push_back(vertex_format_data(format_type, stride, offset));
|
||||
}
|
||||
bool vertex_layout::operator==(const vertex_layout& other) const {
|
||||
if (Vertex_mask != other.Vertex_mask) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Vertex_components.size() != other.Vertex_components.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::equal(Vertex_components.cbegin(),
|
||||
Vertex_components.cend(),
|
||||
other.Vertex_components.cbegin());
|
||||
}
|
||||
size_t vertex_layout::hash() const {
|
||||
size_t seed = 0;
|
||||
boost::hash_combine(seed, Vertex_mask);
|
||||
|
||||
for (auto& comp : Vertex_components) {
|
||||
boost::hash_combine(seed, comp);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
+207
-263
@@ -5,7 +5,7 @@
|
||||
* or otherwise commercially exploit the source or things you created based on the
|
||||
* source.
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define _GRAPHICS_H
|
||||
|
||||
#include "graphics/grinternal.h"
|
||||
#include <osapi/osapi.h>
|
||||
#include "osapi/osapi.h"
|
||||
#include "bmpman/bmpman.h"
|
||||
#include "cfile/cfile.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
@@ -22,6 +22,13 @@
|
||||
#include "math/vecmat.h"
|
||||
#include "io/cursor.h"
|
||||
|
||||
// Forward definition
|
||||
namespace graphics {
|
||||
namespace util {
|
||||
class UniformBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
extern const float Default_min_draw_distance;
|
||||
extern const float Default_max_draw_distance;
|
||||
extern float Min_draw_distance;
|
||||
@@ -37,9 +44,12 @@ class model_material;
|
||||
class particle_material;
|
||||
class distortion_material;
|
||||
class shield_material;
|
||||
class movie_material;
|
||||
class batched_bitmap_material;
|
||||
class nanovg_material;
|
||||
|
||||
class transform_stack {
|
||||
|
||||
|
||||
matrix4 Current_transform;
|
||||
SCP_vector<matrix4> Stack;
|
||||
public:
|
||||
@@ -100,7 +110,7 @@ public:
|
||||
vm_matrix4_x_matrix4(&Current_transform, ¤t_transform_copy, &new_transform);
|
||||
Stack.push_back(Current_transform);
|
||||
}
|
||||
|
||||
|
||||
void pop()
|
||||
{
|
||||
if ( Stack.size() > 1 ) {
|
||||
@@ -109,6 +119,10 @@ public:
|
||||
|
||||
Current_transform = Stack.back();
|
||||
}
|
||||
|
||||
size_t depth() {
|
||||
return Stack.size();
|
||||
}
|
||||
};
|
||||
|
||||
enum primitive_type {
|
||||
@@ -138,8 +152,11 @@ enum shader_type {
|
||||
SDR_TYPE_DEFERRED_LIGHTING,
|
||||
SDR_TYPE_DEFERRED_CLEAR,
|
||||
SDR_TYPE_VIDEO_PROCESS,
|
||||
SDR_TYPE_PASSTHROUGH_RENDER,
|
||||
SDR_TYPE_PASSTHROUGH_RENDER, //!< Shader for doing the old style fixed-function rendering. Only used internally, use SDR_TYPE_DEFAULT_MATERIAL.
|
||||
SDR_TYPE_SHIELD_DECAL,
|
||||
SDR_TYPE_BATCHED_BITMAP,
|
||||
SDR_TYPE_DEFAULT_MATERIAL,
|
||||
SDR_TYPE_NANOVG,
|
||||
NUM_SHADER_TYPES
|
||||
};
|
||||
|
||||
@@ -172,6 +189,16 @@ enum shader_type {
|
||||
#define SDR_FLAG_BLUR_HORIZONTAL (1<<0)
|
||||
#define SDR_FLAG_BLUR_VERTICAL (1<<1)
|
||||
|
||||
#define SDR_FLAG_NANOVG_EDGE_AA (1<<0)
|
||||
|
||||
enum class uniform_block_type {
|
||||
Lights = 0,
|
||||
ModelData = 1,
|
||||
NanoVGData = 2,
|
||||
|
||||
NUM_BLOCK_TYPES
|
||||
};
|
||||
|
||||
struct vertex_format_data
|
||||
{
|
||||
enum vertex_format {
|
||||
@@ -181,74 +208,59 @@ struct vertex_format_data
|
||||
SCREEN_POS,
|
||||
COLOR3,
|
||||
COLOR4,
|
||||
TEX_COORD,
|
||||
TEX_COORD2,
|
||||
TEX_COORD3,
|
||||
NORMAL,
|
||||
TANGENT,
|
||||
MODEL_ID,
|
||||
RADIUS,
|
||||
UVEC
|
||||
UVEC,
|
||||
};
|
||||
|
||||
vertex_format format_type;
|
||||
size_t stride;
|
||||
void *data_src;
|
||||
int offset;
|
||||
size_t offset;
|
||||
|
||||
vertex_format_data(vertex_format i_format_type, size_t i_stride, void *i_data_src) :
|
||||
format_type(i_format_type), stride(i_stride), data_src(i_data_src), offset(-1) {}
|
||||
|
||||
vertex_format_data(vertex_format i_format_type, size_t i_stride, int i_offset) :
|
||||
format_type(i_format_type), stride(i_stride), data_src(NULL), offset(i_offset) {}
|
||||
vertex_format_data(vertex_format i_format_type, size_t i_stride, size_t i_offset) :
|
||||
format_type(i_format_type), stride(i_stride), offset(i_offset) {}
|
||||
|
||||
static inline uint mask(vertex_format v_format) { return 1 << v_format; }
|
||||
};
|
||||
|
||||
bool operator==(const vertex_format_data& other) const {
|
||||
return format_type == other.format_type && stride == other.stride && offset == other.offset;
|
||||
}
|
||||
};
|
||||
class vertex_layout
|
||||
{
|
||||
SCP_vector<vertex_format_data> Vertex_components;
|
||||
|
||||
uint Vertex_mask;
|
||||
uint Vertex_mask = 0;
|
||||
size_t Vertex_stride = 0;
|
||||
public:
|
||||
vertex_layout(): Vertex_mask(0) {}
|
||||
vertex_layout() {}
|
||||
|
||||
vertex_layout(void* init_ptr): Vertex_mask(0) {}
|
||||
size_t get_num_vertex_components() const { return Vertex_components.size(); }
|
||||
|
||||
size_t get_num_vertex_components() { return Vertex_components.size(); }
|
||||
|
||||
vertex_format_data* get_vertex_component(size_t index) { return &Vertex_components[index]; }
|
||||
const vertex_format_data* get_vertex_component(size_t index) const { return &Vertex_components[index]; }
|
||||
|
||||
bool resident_vertex_format(vertex_format_data::vertex_format format_type)
|
||||
{
|
||||
return ( Vertex_mask & vertex_format_data::mask(format_type) ) ? true : false;
|
||||
}
|
||||
bool resident_vertex_format(vertex_format_data::vertex_format format_type) const;
|
||||
|
||||
void add_vertex_component(vertex_format_data::vertex_format format_type, void* src)
|
||||
{
|
||||
add_vertex_component(format_type, 0, src);
|
||||
}
|
||||
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset);
|
||||
|
||||
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, void* src)
|
||||
{
|
||||
if ( resident_vertex_format(format_type) ) {
|
||||
// we already have a vertex component of this format type
|
||||
return;
|
||||
}
|
||||
size_t get_vertex_stride() { return Vertex_stride; }
|
||||
|
||||
Vertex_mask |= (1 << format_type);
|
||||
Vertex_components.push_back(vertex_format_data(format_type, stride, src));
|
||||
}
|
||||
bool operator==(const vertex_layout& other) const;
|
||||
|
||||
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, int offset)
|
||||
{
|
||||
if ( resident_vertex_format(format_type) ) {
|
||||
// we already have a vertex component of this format type
|
||||
return;
|
||||
}
|
||||
|
||||
Vertex_mask |= (1 << format_type);
|
||||
Vertex_components.push_back(vertex_format_data(format_type, stride, offset));
|
||||
}
|
||||
size_t hash() const;
|
||||
};
|
||||
namespace std {
|
||||
template<> struct hash<vertex_format_data> {
|
||||
size_t operator()(const vertex_format_data& data) const;
|
||||
};
|
||||
template<> struct hash<vertex_layout> {
|
||||
size_t operator()(const vertex_layout& data) const;
|
||||
};
|
||||
}
|
||||
|
||||
typedef enum gr_capability {
|
||||
CAPABILITY_ENVIRONMENT_MAP,
|
||||
@@ -264,6 +276,10 @@ typedef enum gr_capability {
|
||||
CAPABILITY_TIMESTAMP_QUERY,
|
||||
} gr_capability;
|
||||
|
||||
enum class gr_property {
|
||||
UNIFORM_BUFFER_OFFSET_ALIGNMENT
|
||||
};
|
||||
|
||||
// stencil buffering stuff
|
||||
extern int gr_stencil_mode;
|
||||
|
||||
@@ -372,7 +388,7 @@ public:
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
uint i_first, i_last;
|
||||
|
||||
void release()
|
||||
@@ -412,7 +428,7 @@ public:
|
||||
index = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Copy-constructor
|
||||
buffer_data(const buffer_data& other)
|
||||
{
|
||||
@@ -425,17 +441,17 @@ public:
|
||||
} else {
|
||||
index = NULL;
|
||||
}
|
||||
|
||||
|
||||
flags = other.flags;
|
||||
texture = other.texture;
|
||||
n_verts = other.n_verts;
|
||||
|
||||
i_first = other.i_first;
|
||||
i_last = other.i_last;
|
||||
|
||||
|
||||
index_offset = other.index_offset;
|
||||
}
|
||||
|
||||
|
||||
// Copy-assignment operator
|
||||
buffer_data& operator=(const buffer_data& rhs)
|
||||
{
|
||||
@@ -452,19 +468,19 @@ public:
|
||||
index[i] = rhs.index[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
flags = rhs.flags;
|
||||
texture = rhs.texture;
|
||||
n_verts = rhs.n_verts;
|
||||
|
||||
|
||||
i_first = rhs.i_first;
|
||||
i_last = rhs.i_last;
|
||||
|
||||
|
||||
index_offset = rhs.index_offset;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Destructor
|
||||
~buffer_data()
|
||||
{
|
||||
@@ -520,8 +536,8 @@ public:
|
||||
};
|
||||
|
||||
struct indexed_vertex_source {
|
||||
float *Vertex_list; // interleaved array
|
||||
ubyte *Index_list;
|
||||
void *Vertex_list;
|
||||
void *Index_list;
|
||||
|
||||
int Vbuffer_handle;
|
||||
int Ibuffer_handle;
|
||||
@@ -554,6 +570,23 @@ enum class QueryType {
|
||||
Timestamp
|
||||
};
|
||||
|
||||
enum class BufferType {
|
||||
Vertex,
|
||||
Index,
|
||||
Uniform
|
||||
};
|
||||
|
||||
enum class BufferUsageHint {
|
||||
Static,
|
||||
Dynamic,
|
||||
Streaming
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Type of a graphics sync object
|
||||
*/
|
||||
typedef void* gr_sync;
|
||||
|
||||
typedef struct screen {
|
||||
uint signature; // changes when mode or palette or width or height changes
|
||||
int max_w, max_h; // Width and height
|
||||
@@ -604,13 +637,11 @@ typedef struct screen {
|
||||
|
||||
int envmap_render_target;
|
||||
|
||||
float line_width;
|
||||
|
||||
//switch onscreen, offscreen
|
||||
void (*gf_flip)();
|
||||
|
||||
// Flash the screen
|
||||
void (*gf_flash)( int r, int g, int b );
|
||||
void (*gf_flash_alpha)(int r, int g, int b, int a);
|
||||
|
||||
// sets the clipping region
|
||||
void (*gf_set_clip)(int x, int y, int w, int h, int resize_mode);
|
||||
|
||||
@@ -620,43 +651,9 @@ typedef struct screen {
|
||||
// clears entire clipping region to current color
|
||||
void (*gf_clear)();
|
||||
|
||||
// void (*gf_bitmap)(int x, int y, int resize_mode);
|
||||
void (*gf_bitmap_ex)(int x, int y, int w, int h, int sx, int sy, int resize_mode);
|
||||
|
||||
void (*gf_aabitmap)(int x, int y, int resize_mode, bool mirror);
|
||||
void (*gf_aabitmap_ex)(int x, int y, int w, int h, int sx, int sy, int resize_mode, bool mirror);
|
||||
|
||||
void(*gf_string)(float x, float y, const char * text, int resize_mode, int length);
|
||||
|
||||
// Draw a gradient line... x1,y1 is bright, x2,y2 is transparent.
|
||||
void (*gf_gradient)(int x1, int y1, int x2, int y2, int resize_mode);
|
||||
|
||||
void (*gf_circle)(int x, int y, int r, int resize_mode);
|
||||
void (*gf_unfilled_circle)(int x, int y, int r, int resize_mode);
|
||||
void (*gf_arc)(int x, int y, float r, float angle_start, float angle_end, bool fill, int resize_mode);
|
||||
void (*gf_curve)(int x, int y, int r, int direction, int resize_mode);
|
||||
|
||||
// Integer line. Used to draw a fast but pixely line.
|
||||
void (*gf_line)(int x1, int y1, int x2, int y2, int resize_mode);
|
||||
|
||||
// Draws an antialiased line is the current color is an
|
||||
// alphacolor, otherwise just draws a fast line. This
|
||||
// gets called internally by g3_draw_line. This assumes
|
||||
// the vertex's are already clipped, so call g3_draw_line
|
||||
// not this if you have two 3d points.
|
||||
void (*gf_aaline)(vertex *v1, vertex *v2);
|
||||
|
||||
void (*gf_pixel)( int x, int y, int resize_mode );
|
||||
|
||||
// dumps the current screen to a file
|
||||
void (*gf_print_screen)(const char * filename);
|
||||
|
||||
// Call once before rendering anything.
|
||||
void (*gf_start_frame)();
|
||||
|
||||
// Call after rendering is over.
|
||||
void (*gf_stop_frame)();
|
||||
|
||||
// Retrieves the zbuffer mode.
|
||||
int (*gf_zbuffer_get)();
|
||||
|
||||
@@ -673,24 +670,24 @@ typedef struct screen {
|
||||
void (*gf_stencil_clear)();
|
||||
|
||||
int (*gf_alpha_mask_set)(int mode, float alpha);
|
||||
|
||||
|
||||
// Saves screen. Returns an id you pass to restore and free.
|
||||
int (*gf_save_screen)();
|
||||
|
||||
|
||||
// Resets clip region and copies entire saved screen to the screen.
|
||||
void (*gf_restore_screen)(int id);
|
||||
|
||||
// Frees up a saved screen.
|
||||
void (*gf_free_screen)(int id);
|
||||
|
||||
|
||||
// Sets the gamma
|
||||
void (*gf_set_gamma)(float gamma);
|
||||
|
||||
|
||||
// grab a region of the screen. assumes data is large enough
|
||||
void (*gf_get_region)(int front, int w, int h, ubyte *data);
|
||||
|
||||
// set fog attributes
|
||||
void (*gf_fog_set)(int fog_mode, int r, int g, int b, float fog_near, float fog_far);
|
||||
void (*gf_fog_set)(int fog_mode, int r, int g, int b, float fog_near, float fog_far);
|
||||
|
||||
// poly culling
|
||||
int (*gf_set_cull)(int cull);
|
||||
@@ -720,36 +717,15 @@ typedef struct screen {
|
||||
|
||||
void (*gf_set_texture_addressing)(int);
|
||||
|
||||
int (*gf_create_vertex_buffer)(bool static_buffer);
|
||||
int (*gf_create_index_buffer)(bool static_buffer);
|
||||
int (*gf_create_buffer)(BufferType type, BufferUsageHint usage);
|
||||
void (*gf_delete_buffer)(int handle);
|
||||
|
||||
void (*gf_update_buffer_data)(int handle, size_t size, void* data);
|
||||
void (*gf_update_buffer_data_offset)(int handle, size_t offset, size_t size, void* data);
|
||||
void (*gf_update_transform_buffer)(void* data, size_t size);
|
||||
void (*gf_set_transform_buffer_offset)(size_t offset);
|
||||
|
||||
void (*gf_render_stream_buffer)(int buffer_handle, size_t offset, size_t n_verts, int flags);
|
||||
|
||||
//the projection matrix; fov, aspect ratio, near, far
|
||||
void (*gf_set_proj_matrix)(float, float, float, float);
|
||||
void (*gf_end_proj_matrix)();
|
||||
//the view matrix
|
||||
void (*gf_set_view_matrix)(const vec3d*, const matrix*);
|
||||
void (*gf_end_view_matrix)();
|
||||
//object scaleing
|
||||
void (*gf_push_scale_matrix)(const vec3d*);
|
||||
void (*gf_pop_scale_matrix)();
|
||||
//object position and orientation
|
||||
void (*gf_start_instance_matrix)(const vec3d*, const matrix*);
|
||||
void (*gf_start_angles_instance_matrix)(const vec3d*, const angles*);
|
||||
void (*gf_end_instance_matrix)();
|
||||
|
||||
void (*gf_set_light)(light*);
|
||||
void (*gf_reset_lighting)();
|
||||
void (*gf_set_ambient_light)(int,int,int);
|
||||
|
||||
// postprocessing effects
|
||||
void (*gf_post_process_set_effect)(const char*, int);
|
||||
void (*gf_post_process_set_effect)(const char*, int, const vec3d*);
|
||||
void (*gf_post_process_set_defaults)();
|
||||
|
||||
void (*gf_post_process_begin)();
|
||||
@@ -765,24 +741,18 @@ typedef struct screen {
|
||||
void (*gf_scene_texture_end)();
|
||||
void (*gf_copy_effect_texture)();
|
||||
|
||||
void (*gf_lighting)(bool,bool);
|
||||
|
||||
void (*gf_start_clip_plane)();
|
||||
void (*gf_end_clip_plane)();
|
||||
|
||||
void (*gf_zbias)(int zbias);
|
||||
|
||||
void (*gf_set_fill_mode)(int);
|
||||
void (*gf_set_texture_panning)(float u, float v, bool enable);
|
||||
|
||||
|
||||
void (*gf_set_line_width)(float width);
|
||||
|
||||
void (*gf_sphere)(material *material_def, float rad);
|
||||
|
||||
int (*gf_maybe_create_shader)(shader_type type, unsigned int flags);
|
||||
|
||||
|
||||
void (*gf_clear_states)();
|
||||
|
||||
|
||||
void (*gf_update_texture)(int bitmap_handle, int bpp, const ubyte* data, int width, int height);
|
||||
void (*gf_get_bitmap_from_texture)(void* data_out, int bitmap_num);
|
||||
|
||||
@@ -792,14 +762,15 @@ typedef struct screen {
|
||||
// new drawing functions
|
||||
void (*gf_render_model)(model_material* material_info, indexed_vertex_source *vert_source, vertex_buffer* bufferp, size_t texi);
|
||||
void (*gf_render_shield_impact)(shield_material *material_info, primitive_type prim_type, vertex_layout *layout, int buffer_handle, int n_verts);
|
||||
void (*gf_render_primitives)(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void (*gf_render_primitives_immediate)(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size);
|
||||
void (*gf_render_primitives)(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle, size_t buffer_offset);
|
||||
void (*gf_render_primitives_particle)(particle_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void (*gf_render_primitives_distortion)(distortion_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void (*gf_render_primitives_2d)(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void (*gf_render_primitives_2d_immediate)(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size);
|
||||
void (*gf_render_movie)(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer);
|
||||
void (*gf_render_primitives_batched)(batched_bitmap_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void (*gf_render_nanovg)(nanovg_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
|
||||
bool (*gf_is_capable)(gr_capability capability);
|
||||
bool (*gf_get_property)(gr_property property, void* destination);
|
||||
|
||||
void (*gf_push_debug_group)(const char* name);
|
||||
void (*gf_pop_debug_group)();
|
||||
@@ -812,6 +783,14 @@ typedef struct screen {
|
||||
|
||||
std::unique_ptr<os::Viewport> (*gf_create_viewport)(const os::ViewPortProperties& props);
|
||||
void (*gf_use_viewport)(os::Viewport* view);
|
||||
|
||||
void (*gf_bind_uniform_buffer)(uniform_block_type bind_point, size_t offset, size_t size, int buffer);
|
||||
|
||||
gr_sync (*gf_sync_fence)();
|
||||
bool (*gf_sync_wait)(gr_sync sync, uint64_t timeoutns);
|
||||
void (*gf_sync_delete)(gr_sync sync);
|
||||
|
||||
void (*gf_set_viewport)(int x, int y, int width, int height);
|
||||
} screen;
|
||||
|
||||
// handy macro
|
||||
@@ -823,7 +802,7 @@ typedef struct screen {
|
||||
|
||||
// # Software Re-added by Kazan --- THIS HAS TO STAY -- It is used by standalone!
|
||||
#define GR_DEFAULT (-1) // set to use default settings
|
||||
#define GR_STUB (100)
|
||||
#define GR_STUB (100)
|
||||
#define GR_OPENGL (104) // Use OpenGl hardware renderer
|
||||
|
||||
// resolution constants - always keep resolutions in ascending order and starting from 0
|
||||
@@ -917,71 +896,8 @@ __inline void gr_set_clip(int x, int y, int w, int h, int resize_mode=GR_RESIZE_
|
||||
void gr_set_bitmap(int bitmap_num, int alphablend = GR_ALPHABLEND_NONE, int bitbltmode = GR_BITBLT_MODE_NORMAL, float alpha = 1.0f);
|
||||
|
||||
#define gr_clear GR_CALL(gr_screen.gf_clear)
|
||||
__inline void gr_aabitmap(int x, int y, int resize_mode = GR_RESIZE_FULL, bool mirror = false)
|
||||
{
|
||||
(*gr_screen.gf_aabitmap)(x,y,resize_mode,mirror);
|
||||
}
|
||||
|
||||
__inline void gr_aabitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode = GR_RESIZE_FULL, bool mirror = false)
|
||||
{
|
||||
(*gr_screen.gf_aabitmap_ex)(x,y,w,h,sx,sy,resize_mode,mirror);
|
||||
}
|
||||
|
||||
__inline void gr_bitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode = GR_RESIZE_FULL)
|
||||
{
|
||||
(*gr_screen.gf_bitmap_ex)(x, y, w, h, sx, sy, resize_mode);
|
||||
}
|
||||
|
||||
void gr_shield_icon(coord2d coords[6], const int resize_mode = GR_RESIZE_FULL);
|
||||
void gr_rect(int x, int y, int w, int h, int resize_mode = GR_RESIZE_FULL);
|
||||
void gr_shade(int x, int y, int w, int h, int resize_mode = GR_RESIZE_FULL);
|
||||
|
||||
__inline void gr_string(float x, float y, const char* string, int resize_mode = GR_RESIZE_FULL, int length = -1)
|
||||
{
|
||||
(*gr_screen.gf_string)(x, y, string, resize_mode, length);
|
||||
}
|
||||
|
||||
__inline void gr_string(int x, int y, const char* string, int resize_mode = GR_RESIZE_FULL, int length = -1)
|
||||
{
|
||||
gr_string(i2fl(x), i2fl(y), string, resize_mode, length);
|
||||
}
|
||||
|
||||
__inline void gr_circle(int xc, int yc, int d, int resize_mode = GR_RESIZE_FULL)
|
||||
{
|
||||
(*gr_screen.gf_circle)(xc,yc,d,resize_mode);
|
||||
}
|
||||
|
||||
__inline void gr_unfilled_circle(int xc, int yc, int d, int resize_mode = GR_RESIZE_FULL)
|
||||
{
|
||||
(*gr_screen.gf_unfilled_circle)(xc,yc,d,resize_mode);
|
||||
}
|
||||
|
||||
__inline void gr_arc(int xc, int yc, float r, float angle_start, float angle_end, bool fill, int resize_mode = GR_RESIZE_FULL)
|
||||
{
|
||||
(*gr_screen.gf_arc)(xc,yc,r,angle_start,angle_end,fill,resize_mode);
|
||||
}
|
||||
|
||||
#define gr_curve GR_CALL(gr_screen.gf_curve)
|
||||
|
||||
__inline void gr_line(int x1, int y1, int x2, int y2, int resize_mode = GR_RESIZE_FULL)
|
||||
{
|
||||
(*gr_screen.gf_line)(x1, y1, x2, y2, resize_mode);
|
||||
}
|
||||
|
||||
#define gr_aaline GR_CALL(gr_screen.gf_aaline)
|
||||
|
||||
__inline void gr_pixel(int x, int y, int resize_mode = GR_RESIZE_FULL)
|
||||
{
|
||||
(*gr_screen.gf_pixel)(x, y, resize_mode);
|
||||
}
|
||||
|
||||
__inline void gr_gradient(int x1, int y1, int x2, int y2, int resize_mode = GR_RESIZE_FULL)
|
||||
{
|
||||
(*gr_screen.gf_gradient)(x1, y1, x2, y2, resize_mode);
|
||||
}
|
||||
|
||||
#define gr_flash GR_CALL(gr_screen.gf_flash)
|
||||
#define gr_flash_alpha GR_CALL(gr_screen.gf_flash_alpha)
|
||||
|
||||
#define gr_zbuffer_get GR_CALL(gr_screen.gf_zbuffer_get)
|
||||
#define gr_zbuffer_set GR_CALL(gr_screen.gf_zbuffer_set)
|
||||
@@ -1025,43 +941,24 @@ __inline void gr_fog_set(int fog_mode, int r, int g, int b, float fog_near = -1.
|
||||
#define gr_bm_page_in_start GR_CALL(*gr_screen.gf_bm_page_in_start)
|
||||
#define gr_bm_data GR_CALL(*gr_screen.gf_bm_data)
|
||||
|
||||
#define gr_bm_make_render_target GR_CALL(*gr_screen.gf_bm_make_render_target)
|
||||
|
||||
#define gr_bm_make_render_target GR_CALL(*gr_screen.gf_bm_make_render_target)
|
||||
|
||||
__inline int gr_bm_set_render_target(int n, int face = -1)
|
||||
{
|
||||
return (*gr_screen.gf_bm_set_render_target)(n, face);
|
||||
}
|
||||
|
||||
#define gr_set_texture_addressing GR_CALL(*gr_screen.gf_set_texture_addressing)
|
||||
#define gr_set_texture_addressing GR_CALL(*gr_screen.gf_set_texture_addressing)
|
||||
|
||||
__inline int gr_create_vertex_buffer(bool static_buffer = false)
|
||||
inline int gr_create_buffer(BufferType type, BufferUsageHint usage)
|
||||
{
|
||||
return (*gr_screen.gf_create_vertex_buffer)(static_buffer);
|
||||
}
|
||||
|
||||
__inline int gr_create_index_buffer(bool static_buffer = false)
|
||||
{
|
||||
return (*gr_screen.gf_create_index_buffer)(static_buffer);
|
||||
return (*gr_screen.gf_create_buffer)(type, usage);
|
||||
}
|
||||
|
||||
#define gr_delete_buffer GR_CALL(*gr_screen.gf_delete_buffer)
|
||||
#define gr_update_buffer_data GR_CALL(*gr_screen.gf_update_buffer_data)
|
||||
#define gr_update_buffer_data_offset GR_CALL(*gr_screen.gf_update_buffer_data_offset)
|
||||
#define gr_update_transform_buffer GR_CALL(*gr_screen.gf_update_transform_buffer)
|
||||
#define gr_set_transform_buffer_offset GR_CALL(*gr_screen.gf_set_transform_buffer_offset)
|
||||
|
||||
#define gr_set_proj_matrix GR_CALL(*gr_screen.gf_set_proj_matrix)
|
||||
#define gr_end_proj_matrix GR_CALL(*gr_screen.gf_end_proj_matrix)
|
||||
#define gr_set_view_matrix GR_CALL(*gr_screen.gf_set_view_matrix)
|
||||
#define gr_end_view_matrix GR_CALL(*gr_screen.gf_end_view_matrix)
|
||||
#define gr_push_scale_matrix GR_CALL(*gr_screen.gf_push_scale_matrix)
|
||||
#define gr_pop_scale_matrix GR_CALL(*gr_screen.gf_pop_scale_matrix)
|
||||
#define gr_start_instance_matrix GR_CALL(*gr_screen.gf_start_instance_matrix)
|
||||
#define gr_start_angles_instance_matrix GR_CALL(*gr_screen.gf_start_angles_instance_matrix)
|
||||
#define gr_end_instance_matrix GR_CALL(*gr_screen.gf_end_instance_matrix)
|
||||
|
||||
#define gr_set_light GR_CALL(*gr_screen.gf_set_light)
|
||||
#define gr_reset_lighting GR_CALL(*gr_screen.gf_reset_lighting)
|
||||
#define gr_set_ambient_light GR_CALL(*gr_screen.gf_set_ambient_light)
|
||||
|
||||
#define gr_scene_texture_begin GR_CALL(*gr_screen.gf_scene_texture_begin)
|
||||
#define gr_scene_texture_end GR_CALL(*gr_screen.gf_scene_texture_end)
|
||||
@@ -1080,14 +977,8 @@ inline void gr_post_process_restore_zbuffer() {
|
||||
#define gr_deferred_lighting_end GR_CALL(*gr_screen.gf_deferred_lighting_end)
|
||||
#define gr_deferred_lighting_finish GR_CALL(*gr_screen.gf_deferred_lighting_finish)
|
||||
|
||||
#define gr_set_lighting GR_CALL(*gr_screen.gf_lighting)
|
||||
|
||||
#define gr_start_clip GR_CALL(*gr_screen.gf_start_clip_plane)
|
||||
#define gr_end_clip GR_CALL(*gr_screen.gf_end_clip_plane)
|
||||
|
||||
#define gr_zbias GR_CALL(*gr_screen.gf_zbias)
|
||||
#define gr_set_fill_mode GR_CALL(*gr_screen.gf_set_fill_mode)
|
||||
#define gr_set_texture_panning GR_CALL(*gr_screen.gf_set_texture_panning)
|
||||
|
||||
#define gr_set_line_width GR_CALL(*gr_screen.gf_set_line_width)
|
||||
|
||||
@@ -1105,14 +996,9 @@ inline void gr_post_process_restore_zbuffer() {
|
||||
#define gr_shadow_map_end GR_CALL(*gr_screen.gf_shadow_map_end)
|
||||
#define gr_render_shield_impact GR_CALL(*gr_screen.gf_render_shield_impact)
|
||||
|
||||
__inline void gr_render_primitives(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle = -1)
|
||||
__inline void gr_render_primitives(material* material_info, primitive_type prim_type, vertex_layout* layout, int vert_offset, int n_verts, int buffer_handle = -1, size_t buffer_offset = 0)
|
||||
{
|
||||
(*gr_screen.gf_render_primitives)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
|
||||
}
|
||||
|
||||
__inline void gr_render_primitives_immediate(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size)
|
||||
{
|
||||
(*gr_screen.gf_render_primitives_immediate)(material_info, prim_type, layout, n_verts, data, size);
|
||||
(*gr_screen.gf_render_primitives)(material_info, prim_type, layout, vert_offset, n_verts, buffer_handle, buffer_offset);
|
||||
}
|
||||
|
||||
__inline void gr_render_primitives_particle(particle_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle = -1)
|
||||
@@ -1120,19 +1006,24 @@ __inline void gr_render_primitives_particle(particle_material* material_info, pr
|
||||
(*gr_screen.gf_render_primitives_particle)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
|
||||
}
|
||||
|
||||
__inline void gr_render_primitives_batched(batched_bitmap_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle = -1)
|
||||
{
|
||||
(*gr_screen.gf_render_primitives_batched)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
|
||||
}
|
||||
|
||||
__inline void gr_render_nanovg(nanovg_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle)
|
||||
{
|
||||
(*gr_screen.gf_render_nanovg)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
|
||||
}
|
||||
|
||||
__inline void gr_render_primitives_distortion(distortion_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle = -1)
|
||||
{
|
||||
(*gr_screen.gf_render_primitives_distortion)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
|
||||
}
|
||||
|
||||
__inline void gr_render_primitives_2d(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle = -1)
|
||||
inline void gr_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer)
|
||||
{
|
||||
(*gr_screen.gf_render_primitives_2d)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
|
||||
}
|
||||
|
||||
__inline void gr_render_primitives_2d_immediate(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size)
|
||||
{
|
||||
(*gr_screen.gf_render_primitives_2d_immediate)(material_info, prim_type, layout, n_verts, data, size);
|
||||
(*gr_screen.gf_render_movie)(material_info, prim_type, layout, n_verts, buffer);
|
||||
}
|
||||
|
||||
__inline void gr_render_model(model_material* material_info, indexed_vertex_source *vert_source, vertex_buffer* bufferp, size_t texi)
|
||||
@@ -1145,6 +1036,11 @@ __inline bool gr_is_capable(gr_capability capability)
|
||||
return (*gr_screen.gf_is_capable)(capability);
|
||||
}
|
||||
|
||||
inline bool gr_get_property(gr_property property, void* destination)
|
||||
{
|
||||
return (*gr_screen.gf_get_property)(property, destination);
|
||||
}
|
||||
|
||||
inline void gr_push_debug_group(const char* name)
|
||||
{
|
||||
(*gr_screen.gf_push_debug_group)(name);
|
||||
@@ -1186,6 +1082,23 @@ inline std::unique_ptr<os::Viewport> gr_create_viewport(const os::ViewPortProper
|
||||
inline void gr_use_viewport(os::Viewport* view) {
|
||||
(*gr_screen.gf_use_viewport)(view);
|
||||
}
|
||||
inline void gr_set_viewport(int x, int y, int width, int height) {
|
||||
(*gr_screen.gf_set_viewport)(x, y, width, height);
|
||||
}
|
||||
|
||||
inline void gr_bind_uniform_buffer(uniform_block_type bind_point, size_t offset, size_t size, int buffer) {
|
||||
(*gr_screen.gf_bind_uniform_buffer)(bind_point, offset, size, buffer);
|
||||
}
|
||||
|
||||
inline gr_sync gr_sync_fence() {
|
||||
return (*gr_screen.gf_sync_fence)();
|
||||
}
|
||||
inline bool gr_sync_wait(gr_sync sync, uint64_t timeoutns) {
|
||||
return (*gr_screen.gf_sync_wait)(sync, timeoutns);
|
||||
}
|
||||
inline void gr_sync_delete(gr_sync sync) {
|
||||
(*gr_screen.gf_sync_delete)(sync);
|
||||
}
|
||||
|
||||
// color functions
|
||||
void gr_get_color( int *r, int *g, int b );
|
||||
@@ -1199,17 +1112,17 @@ void gr_create_shader(shader *shade, ubyte r, ubyte g, ubyte b, ubyte c);
|
||||
void gr_set_shader(shader *shade);
|
||||
|
||||
uint gr_determine_model_shader_flags(
|
||||
bool lighting,
|
||||
bool fog,
|
||||
bool textured,
|
||||
bool in_shadow_map,
|
||||
bool thruster_scale,
|
||||
bool lighting,
|
||||
bool fog,
|
||||
bool textured,
|
||||
bool in_shadow_map,
|
||||
bool thruster_scale,
|
||||
bool transform,
|
||||
bool team_color_set,
|
||||
int tmap_flags,
|
||||
int spec_map,
|
||||
int glow_map,
|
||||
int normal_map,
|
||||
int tmap_flags,
|
||||
int spec_map,
|
||||
int glow_map,
|
||||
int normal_map,
|
||||
int height_map,
|
||||
int ambient_map,
|
||||
int env_map,
|
||||
@@ -1231,14 +1144,14 @@ void gr_opengl_update_texture(int bitmap_handle, int bpp, const ubyte* data, int
|
||||
// Moreover, it is _really_ intended for use with 45 degree angles.
|
||||
void gr_pline_special(SCP_vector<vec3d> *pts, int thickness,int resize_mode=GR_RESIZE_FULL);
|
||||
|
||||
#define VB_FLAG_POSITION (1<<0)
|
||||
#define VB_FLAG_POSITION (1<<0)
|
||||
#define VB_FLAG_RHW (1<<1) //incompatable with the next normal
|
||||
#define VB_FLAG_NORMAL (1<<2)
|
||||
#define VB_FLAG_DIFUSE (1<<3)
|
||||
#define VB_FLAG_SPECULAR (1<<4)
|
||||
#define VB_FLAG_NORMAL (1<<2)
|
||||
#define VB_FLAG_DIFUSE (1<<3)
|
||||
#define VB_FLAG_SPECULAR (1<<4)
|
||||
#define VB_FLAG_UV1 (1<<5) //how many UV coords, only use one of these
|
||||
#define VB_FLAG_UV2 (1<<6)
|
||||
#define VB_FLAG_UV3 (1<<7)
|
||||
#define VB_FLAG_UV2 (1<<6)
|
||||
#define VB_FLAG_UV3 (1<<7)
|
||||
#define VB_FLAG_UV4 (1<<8)
|
||||
#define VB_FLAG_TANGENT (1<<9)
|
||||
#define VB_FLAG_LARGE_INDEX (1<<10)
|
||||
@@ -1275,4 +1188,35 @@ class DebugScope {
|
||||
#define GR_DEBUG_SCOPE(name) do {} while(0)
|
||||
#endif
|
||||
|
||||
enum AnimatedShader {
|
||||
ANIMATED_SHADER_LOADOUTSELECT_FS1= 0,
|
||||
ANIMATED_SHADER_LOADOUTSELECT_FS2= 1,
|
||||
ANIMATED_SHADER_CLOAK = 2,
|
||||
};
|
||||
|
||||
graphics::util::UniformBuffer* gr_get_uniform_buffer(uniform_block_type type);
|
||||
|
||||
struct VideoModeData {
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
uint32_t bit_depth = 0;
|
||||
};
|
||||
|
||||
struct DisplayData {
|
||||
uint32_t index;
|
||||
SCP_string name;
|
||||
|
||||
int32_t x = 0;
|
||||
int32_t y = 0;
|
||||
int32_t width = 0;
|
||||
int32_t height = 0;
|
||||
|
||||
SCP_vector<VideoModeData> video_modes;
|
||||
};
|
||||
|
||||
SCP_vector<DisplayData> gr_enumerate_displays();
|
||||
|
||||
// Include this last to make the 2D rendering function available everywhere
|
||||
#include "graphics/render.h"
|
||||
|
||||
#endif
|
||||
@@ -251,13 +251,19 @@ int generic_anim_stream(generic_anim *ga, const bool cache)
|
||||
if ( p )
|
||||
*p = 0;
|
||||
char frame_name[MAX_FILENAME_LEN];
|
||||
snprintf(frame_name, MAX_FILENAME_LEN, "%s_0000", ga->filename);
|
||||
if (snprintf(frame_name, MAX_FILENAME_LEN, "%s_0000", ga->filename) >= MAX_FILENAME_LEN) {
|
||||
// Make sure the string is null terminated
|
||||
frame_name[MAX_FILENAME_LEN - 1] = '\0';
|
||||
}
|
||||
ga->bitmap_id = bm_load(frame_name);
|
||||
if(ga->bitmap_id < 0) {
|
||||
mprintf(("Cannot find first frame for eff streaming. eff Filename: %s", ga->filename));
|
||||
return -1;
|
||||
}
|
||||
snprintf(frame_name, MAX_FILENAME_LEN, "%s_0001", ga->filename);
|
||||
if (snprintf(frame_name, MAX_FILENAME_LEN, "%s_0001", ga->filename) >= MAX_FILENAME_LEN) {
|
||||
// Make sure the string is null terminated
|
||||
frame_name[MAX_FILENAME_LEN - 1] = '\0';
|
||||
}
|
||||
ga->eff.next_frame = bm_load(frame_name);
|
||||
bm_get_info(ga->bitmap_id, &ga->width, &ga->height);
|
||||
ga->previous_frame = 0;
|
||||
@@ -369,7 +375,10 @@ void generic_render_eff_stream(generic_anim *ga)
|
||||
mprintf(("frame: %d\n", ga->current_frame));
|
||||
#endif
|
||||
char frame_name[MAX_FILENAME_LEN];
|
||||
snprintf(frame_name, MAX_FILENAME_LEN, "%s_%.4d", ga->filename, ga->current_frame);
|
||||
if (snprintf(frame_name, MAX_FILENAME_LEN, "%s_%.4d", ga->filename, ga->current_frame) >= MAX_FILENAME_LEN) {
|
||||
// Make sure the string is null terminated
|
||||
frame_name[MAX_FILENAME_LEN - 1] = '\0';
|
||||
}
|
||||
if(bm_reload(ga->eff.next_frame, frame_name) == ga->eff.next_frame)
|
||||
{
|
||||
bitmap* next_frame_bmp = bm_lock(ga->eff.next_frame, bpp, (bpp==8)?BMP_AABITMAP:BMP_TEX_NONCOMP, true);
|
||||
@@ -379,7 +388,10 @@ void generic_render_eff_stream(generic_anim *ga)
|
||||
bm_unload(ga->eff.next_frame, 0, true);
|
||||
if (ga->current_frame == ga->num_frames-1)
|
||||
{
|
||||
snprintf(frame_name, MAX_FILENAME_LEN, "%s_0001", ga->filename);
|
||||
if (snprintf(frame_name, MAX_FILENAME_LEN, "%s_0001", ga->filename) >= MAX_FILENAME_LEN) {
|
||||
// Make sure the string is null terminated
|
||||
frame_name[MAX_FILENAME_LEN - 1] = '\0';
|
||||
}
|
||||
bm_reload(ga->eff.next_frame, frame_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/grbatch.h"
|
||||
#include "graphics/opengl/gropengldraw.h"
|
||||
#include "graphics/opengl/gropenglstate.h"
|
||||
#include "render/3d.h"
|
||||
|
||||
geometry_batcher::~geometry_batcher()
|
||||
|
||||
@@ -69,10 +69,4 @@ typedef enum gr_zbuffer_type {
|
||||
ZBUFFER_TYPE_DEFAULT
|
||||
} gr_zbuffer_type;
|
||||
|
||||
typedef enum gr_stencil_type {
|
||||
STENCIL_TYPE_NONE,
|
||||
STENCIL_TYPE_READ,
|
||||
STENCIL_TYPE_WRITE
|
||||
} gr_stencil_type;
|
||||
|
||||
#endif
|
||||
+30
-200
@@ -23,12 +23,7 @@ uint gr_stub_lock()
|
||||
return 1;
|
||||
}
|
||||
|
||||
int gr_stub_create_vertex_buffer(bool static_buffer)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gr_stub_create_index_buffer(bool static_buffer)
|
||||
int gr_stub_create_buffer(BufferType, BufferUsageHint)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -62,37 +57,10 @@ void gr_set_fill_mode_stub(int mode)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_aabitmap_ex(int x,int y,int w,int h,int sx,int sy,int resize_mode,bool mirror)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_aabitmap(int x, int y,int resize_mode, bool mirror)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_aaline(vertex *v1, vertex *v2)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_activate(int active)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_bitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_bitmap(int x, int y)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_circle( int xc, int yc, int d, int resize_mode )
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_unfilled_circle( int xc, int yc, int d, int resize_mode )
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_cleanup(int minimize)
|
||||
{
|
||||
@@ -102,34 +70,6 @@ void gr_stub_clear()
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_curve(int xc, int yc, int r, int direction, int resize_mode)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_end_clip_plane()
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_end_instance_matrix()
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_end_projection_matrix()
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_end_view_matrix()
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_flash_alpha(int r, int g, int b, int a)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_flash(int r, int g, int b)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_flip()
|
||||
{
|
||||
}
|
||||
@@ -146,22 +86,6 @@ void gr_stub_get_region(int front, int w, int h, ubyte *data)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_gradient(int x1,int y1,int x2,int y2, int resize_mode)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_line(int x1,int y1,int x2,int y2, int resize_mode = GR_RESIZE_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_pixel(int x, int y, int resize_mode)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_pop_scale_matrix()
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_pop_texture_matrix(int unit)
|
||||
{
|
||||
}
|
||||
@@ -174,10 +98,6 @@ void gr_stub_print_screen(const char *filename)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_push_scale_matrix(const vec3d *scale_factor)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_push_texture_matrix(int unit)
|
||||
{
|
||||
}
|
||||
@@ -190,10 +110,6 @@ void gr_stub_reset_clip()
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_reset_lighting()
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_restore_screen(int id)
|
||||
{
|
||||
}
|
||||
@@ -204,7 +120,10 @@ void gr_stub_save_mouse_area(int x, int y, int w, int h)
|
||||
|
||||
void gr_stub_update_buffer_data(int handle, size_t size, void* data)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_update_buffer_data_offset(int handle, size_t offset, size_t size, void* data)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_update_transform_buffer(void* data, size_t size)
|
||||
@@ -212,15 +131,6 @@ void gr_stub_update_transform_buffer(void* data, size_t size)
|
||||
|
||||
}
|
||||
|
||||
void gr_stub_set_transform_buffer_offset(size_t offset)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void gr_stub_render_stream_buffer(int buffer_handle, size_t offset, size_t n_verts, int flags)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_set_clear_color(int r, int g, int b)
|
||||
{
|
||||
}
|
||||
@@ -243,18 +153,6 @@ void gr_stub_set_gamma(float gamma)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_set_lighting(bool set, bool state)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_set_light(light *light)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_set_projection_matrix(float fov, float aspect, float z_near, float z_far)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_set_tex_env_scale(float scale)
|
||||
{
|
||||
}
|
||||
@@ -263,26 +161,6 @@ void gr_stub_set_texture_addressing(int mode)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_set_view_matrix(const vec3d *pos, const matrix* orient)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_start_clip_plane()
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_start_instance_angles(const vec3d *pos, const angles *rotation)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_start_instance_matrix(const vec3d *offset, const matrix *rotation)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_string( float sx, float sy, const char *s, int resize_mode = GR_RESIZE_NONE, int length = -1)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_stuff_fog_coord(vertex *v)
|
||||
{
|
||||
}
|
||||
@@ -321,7 +199,7 @@ int gr_stub_alpha_mask_set(int mode, float alpha)
|
||||
{
|
||||
}*/
|
||||
|
||||
void gr_stub_post_process_set_effect(const char *name, int x)
|
||||
void gr_stub_post_process_set_effect(const char *name, int x, const vec3d *rgb)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -369,14 +247,6 @@ void gr_stub_deferred_lighting_finish()
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_set_ambient_light(int red, int green, int blue)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_set_texture_panning(float u, float v, bool enable)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_set_line_width(float width)
|
||||
{
|
||||
}
|
||||
@@ -451,22 +321,7 @@ void gr_stub_render_model(model_material* material_info, indexed_vertex_source *
|
||||
|
||||
}
|
||||
|
||||
void gr_stub_render_primitives(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void gr_stub_render_primitives_immediate(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void gr_stub_render_primitives_2d(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void gr_stub_render_primitives_2d_immediate(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size)
|
||||
void gr_stub_render_primitives(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle, size_t buffer_offset)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -479,6 +334,21 @@ void gr_stub_render_primitives_particle(particle_material* material_info, primit
|
||||
void gr_stub_render_primitives_distortion(distortion_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle)
|
||||
{
|
||||
|
||||
}
|
||||
void gr_stub_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer)
|
||||
{
|
||||
}
|
||||
|
||||
void gr_stub_render_nanovg(nanovg_material* material_info,
|
||||
primitive_type prim_type,
|
||||
vertex_layout* layout,
|
||||
int offset,
|
||||
int n_verts,
|
||||
int buffer_handle) {
|
||||
}
|
||||
|
||||
void gr_stub_render_primitives_batched(batched_bitmap_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle)
|
||||
{
|
||||
}
|
||||
|
||||
bool gr_stub_is_capable(gr_capability capability)
|
||||
@@ -547,29 +417,12 @@ bool gr_stub_init()
|
||||
gr_screen.gf_reset_clip = gr_stub_reset_clip;
|
||||
|
||||
gr_screen.gf_clear = gr_stub_clear;
|
||||
// gr_screen.gf_bitmap = gr_stub_bitmap;
|
||||
gr_screen.gf_bitmap_ex = gr_stub_bitmap_ex;
|
||||
gr_screen.gf_aabitmap = gr_stub_aabitmap;
|
||||
gr_screen.gf_aabitmap_ex = gr_stub_aabitmap_ex;
|
||||
|
||||
|
||||
// gr_screen.gf_rect = gr_stub_rect;
|
||||
// gr_screen.gf_shade = gr_stub_shade;
|
||||
gr_screen.gf_string = gr_stub_string;
|
||||
gr_screen.gf_circle = gr_stub_circle;
|
||||
gr_screen.gf_unfilled_circle = gr_stub_unfilled_circle;
|
||||
gr_screen.gf_curve = gr_stub_curve;
|
||||
|
||||
gr_screen.gf_line = gr_stub_line;
|
||||
gr_screen.gf_aaline = gr_stub_aaline;
|
||||
gr_screen.gf_pixel = gr_stub_pixel;
|
||||
|
||||
gr_screen.gf_gradient = gr_stub_gradient;
|
||||
|
||||
gr_screen.gf_print_screen = gr_stub_print_screen;
|
||||
|
||||
gr_screen.gf_flash = gr_stub_flash;
|
||||
gr_screen.gf_flash_alpha = gr_stub_flash_alpha;
|
||||
|
||||
gr_screen.gf_zbuffer_get = gr_stub_zbuffer_get;
|
||||
gr_screen.gf_zbuffer_set = gr_stub_zbuffer_set;
|
||||
gr_screen.gf_zbuffer_clear = gr_stub_zbuffer_clear;
|
||||
@@ -613,25 +466,13 @@ bool gr_stub_init()
|
||||
gr_screen.gf_set_texture_addressing = gr_stub_set_texture_addressing;
|
||||
gr_screen.gf_zbias = gr_stub_zbias_stub;
|
||||
gr_screen.gf_set_fill_mode = gr_set_fill_mode_stub;
|
||||
gr_screen.gf_set_texture_panning = gr_stub_set_texture_panning;
|
||||
|
||||
gr_screen.gf_create_vertex_buffer = gr_stub_create_vertex_buffer;
|
||||
gr_screen.gf_create_index_buffer = gr_stub_create_index_buffer;
|
||||
gr_screen.gf_create_buffer = gr_stub_create_buffer;
|
||||
gr_screen.gf_delete_buffer = gr_stub_delete_buffer;
|
||||
|
||||
gr_screen.gf_update_transform_buffer = gr_stub_update_transform_buffer;
|
||||
gr_screen.gf_update_buffer_data = gr_stub_update_buffer_data;
|
||||
gr_screen.gf_set_transform_buffer_offset = gr_stub_set_transform_buffer_offset;
|
||||
|
||||
gr_screen.gf_render_stream_buffer = gr_stub_render_stream_buffer;
|
||||
|
||||
gr_screen.gf_start_instance_matrix = gr_stub_start_instance_matrix;
|
||||
gr_screen.gf_end_instance_matrix = gr_stub_end_instance_matrix;
|
||||
gr_screen.gf_start_angles_instance_matrix = gr_stub_start_instance_angles;
|
||||
|
||||
gr_screen.gf_set_light = gr_stub_set_light;
|
||||
gr_screen.gf_reset_lighting = gr_stub_reset_lighting;
|
||||
gr_screen.gf_set_ambient_light = gr_stub_set_ambient_light;
|
||||
gr_screen.gf_update_buffer_data_offset = gr_stub_update_buffer_data_offset;
|
||||
|
||||
gr_screen.gf_post_process_set_effect = gr_stub_post_process_set_effect;
|
||||
gr_screen.gf_post_process_set_defaults = gr_stub_post_process_set_defaults;
|
||||
@@ -649,20 +490,6 @@ bool gr_stub_init()
|
||||
gr_screen.gf_deferred_lighting_end = gr_stub_deferred_lighting_end;
|
||||
gr_screen.gf_deferred_lighting_finish = gr_stub_deferred_lighting_finish;
|
||||
|
||||
gr_screen.gf_start_clip_plane = gr_stub_start_clip_plane;
|
||||
gr_screen.gf_end_clip_plane = gr_stub_end_clip_plane;
|
||||
|
||||
gr_screen.gf_lighting = gr_stub_set_lighting;
|
||||
|
||||
gr_screen.gf_set_proj_matrix = gr_stub_set_projection_matrix;
|
||||
gr_screen.gf_end_proj_matrix = gr_stub_end_projection_matrix;
|
||||
|
||||
gr_screen.gf_set_view_matrix = gr_stub_set_view_matrix;
|
||||
gr_screen.gf_end_view_matrix = gr_stub_end_view_matrix;
|
||||
|
||||
gr_screen.gf_push_scale_matrix = gr_stub_push_scale_matrix;
|
||||
gr_screen.gf_pop_scale_matrix = gr_stub_pop_scale_matrix;
|
||||
|
||||
gr_screen.gf_set_line_width = gr_stub_set_line_width;
|
||||
|
||||
gr_screen.gf_sphere = gr_stub_draw_sphere;
|
||||
@@ -681,13 +508,14 @@ bool gr_stub_init()
|
||||
|
||||
gr_screen.gf_render_model = gr_stub_render_model;
|
||||
gr_screen.gf_render_primitives = gr_stub_render_primitives;
|
||||
gr_screen.gf_render_primitives_immediate = gr_stub_render_primitives_immediate;
|
||||
gr_screen.gf_render_primitives_2d = gr_stub_render_primitives_2d;
|
||||
gr_screen.gf_render_primitives_2d_immediate = gr_stub_render_primitives_2d_immediate;
|
||||
gr_screen.gf_render_primitives_particle = gr_stub_render_primitives_particle;
|
||||
gr_screen.gf_render_primitives_distortion = gr_stub_render_primitives_distortion;
|
||||
gr_screen.gf_render_movie = gr_stub_render_movie;
|
||||
gr_screen.gf_render_nanovg = gr_stub_render_nanovg;
|
||||
gr_screen.gf_render_primitives_batched = gr_stub_render_primitives_batched;
|
||||
|
||||
gr_screen.gf_is_capable = gr_stub_is_capable;
|
||||
gr_screen.gf_get_property = [](gr_property,void*) { return false; };
|
||||
|
||||
gr_screen.gf_push_debug_group = gr_stub_push_debug_group;
|
||||
gr_screen.gf_pop_debug_group = gr_stub_pop_debug_group;
|
||||
@@ -704,5 +532,7 @@ bool gr_stub_init()
|
||||
gr_screen.gf_use_viewport = [](os::Viewport*) {
|
||||
};
|
||||
|
||||
gr_screen.gf_bind_uniform_buffer = [](uniform_block_type, size_t, size_t, int) {};
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
||||
*
|
||||
* All source code herein is the property of Volition, Inc. You may not sell
|
||||
* or otherwise commercially exploit the source or things you created based on the
|
||||
* source.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include <math/bitarray.h>
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "light.h"
|
||||
#include "matrix.h"
|
||||
#include "render/3d.h"
|
||||
|
||||
// Structures
|
||||
struct gr_light
|
||||
{
|
||||
vec4 Ambient;
|
||||
vec4 Diffuse;
|
||||
vec4 Specular;
|
||||
|
||||
// light position
|
||||
vec4 Position;
|
||||
|
||||
// spotlight direction (for tube lights)
|
||||
vec3d SpotDir;
|
||||
|
||||
float SpotExp, SpotCutOff;
|
||||
float ConstantAtten, LinearAtten, QuadraticAtten;
|
||||
|
||||
bool occupied;
|
||||
int type;
|
||||
};
|
||||
|
||||
// Variables
|
||||
gr_light* gr_lights = NULL;
|
||||
graphics::model_light gr_light_uniforms[graphics::MAX_UNIFORM_LIGHTS];
|
||||
|
||||
int Num_active_gr_lights = 0;
|
||||
|
||||
// OGL defaults
|
||||
const float gr_light_color[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
|
||||
const float gr_light_zero[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
const float gr_light_emission[4] = { 0.09f, 0.09f, 0.09f, 1.0f };
|
||||
float gr_light_ambient[4] = { 0.47f, 0.47f, 0.47f, 1.0f };
|
||||
|
||||
void FSLight2GLLight(light* FSLight, gr_light* GLLight) {
|
||||
GLLight->Ambient.xyzw.x = 0.0f;
|
||||
GLLight->Ambient.xyzw.y = 0.0f;
|
||||
GLLight->Ambient.xyzw.z = 0.0f;
|
||||
GLLight->Ambient.xyzw.w = 1.0f;
|
||||
|
||||
GLLight->Diffuse.xyzw.x = FSLight->r * FSLight->intensity;
|
||||
GLLight->Diffuse.xyzw.y = FSLight->g * FSLight->intensity;
|
||||
GLLight->Diffuse.xyzw.z = FSLight->b * FSLight->intensity;
|
||||
GLLight->Diffuse.xyzw.w = 1.0f;
|
||||
|
||||
GLLight->Specular.xyzw.x = FSLight->spec_r * FSLight->intensity;
|
||||
GLLight->Specular.xyzw.y = FSLight->spec_g * FSLight->intensity;
|
||||
GLLight->Specular.xyzw.z = FSLight->spec_b * FSLight->intensity;
|
||||
GLLight->Specular.xyzw.w = 1.0f;
|
||||
|
||||
GLLight->type = FSLight->type;
|
||||
|
||||
// GL default values...
|
||||
// spot direction
|
||||
GLLight->SpotDir.xyz.x = 0.0f;
|
||||
GLLight->SpotDir.xyz.y = 0.0f;
|
||||
GLLight->SpotDir.xyz.z = -1.0f;
|
||||
// spot exponent
|
||||
GLLight->SpotExp = Cmdline_ogl_spec * 0.5f;
|
||||
// spot cutoff
|
||||
GLLight->SpotCutOff = 180.0f; // special value, light in all directions
|
||||
// defaults to disable attenuation
|
||||
GLLight->ConstantAtten = 1.0f;
|
||||
GLLight->LinearAtten = 0.0f;
|
||||
GLLight->QuadraticAtten = 0.0f;
|
||||
// position
|
||||
GLLight->Position.xyzw.x = FSLight->vec.xyz.x;
|
||||
GLLight->Position.xyzw.y = FSLight->vec.xyz.y;
|
||||
GLLight->Position.xyzw.z = FSLight->vec.xyz.z; // flipped axis for FS2
|
||||
GLLight->Position.xyzw.w = 1.0f;
|
||||
|
||||
|
||||
switch (FSLight->type) {
|
||||
case LT_POINT: {
|
||||
// this crap still needs work...
|
||||
GLLight->ConstantAtten = 1.0f;
|
||||
GLLight->LinearAtten = (1.0f / MAX(FSLight->rada, FSLight->radb)) * 1.25f;
|
||||
|
||||
GLLight->Specular.xyzw.x *= static_point_factor;
|
||||
GLLight->Specular.xyzw.y *= static_point_factor;
|
||||
GLLight->Specular.xyzw.z *= static_point_factor;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LT_TUBE: {
|
||||
GLLight->ConstantAtten = 1.0f;
|
||||
GLLight->LinearAtten = (1.0f / MAX(FSLight->rada, FSLight->radb)) * 1.25f;
|
||||
GLLight->QuadraticAtten = (1.0f / MAX(FSLight->rada_squared, FSLight->radb_squared)) * 1.25f;
|
||||
|
||||
GLLight->Specular.xyzw.x *= static_tube_factor;
|
||||
GLLight->Specular.xyzw.y *= static_tube_factor;
|
||||
GLLight->Specular.xyzw.z *= static_tube_factor;
|
||||
|
||||
GLLight->Position.xyzw.x = FSLight->vec2.xyz.x; // Valathil: Use endpoint of tube as light position
|
||||
GLLight->Position.xyzw.y = FSLight->vec2.xyz.y;
|
||||
GLLight->Position.xyzw.z = FSLight->vec2.xyz.z;
|
||||
GLLight->Position.xyzw.w = 1.0f;
|
||||
|
||||
// Valathil: When using shaders pass the beam direction (not normalized IMPORTANT for calculation of tube)
|
||||
vec3d a;
|
||||
vm_vec_sub(&a, &FSLight->vec2, &FSLight->vec);
|
||||
GLLight->SpotDir.xyz.x = a.xyz.x;
|
||||
GLLight->SpotDir.xyz.y = a.xyz.y;
|
||||
GLLight->SpotDir.xyz.z = a.xyz.z;
|
||||
GLLight->SpotCutOff = 90.0f; // Valathil: So shader dectects tube light
|
||||
break;
|
||||
}
|
||||
|
||||
case LT_DIRECTIONAL: {
|
||||
GLLight->Position.xyzw.x = -FSLight->vec.xyz.x;
|
||||
GLLight->Position.xyzw.y = -FSLight->vec.xyz.y;
|
||||
GLLight->Position.xyzw.z = -FSLight->vec.xyz.z;
|
||||
GLLight->Position.xyzw.w = 0.0f; // This is a direction so the w part must be 0
|
||||
|
||||
GLLight->Specular.xyzw.x *= static_light_factor;
|
||||
GLLight->Specular.xyzw.y *= static_light_factor;
|
||||
GLLight->Specular.xyzw.z *= static_light_factor;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LT_CONE:
|
||||
break;
|
||||
|
||||
default:
|
||||
Int3();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_light(int light_num, gr_light* ltp) {
|
||||
Assert(light_num < (int)graphics::MAX_UNIFORM_LIGHTS);
|
||||
|
||||
vm_vec_transform(&gr_light_uniforms[light_num].position, <p->Position, &gr_view_matrix);
|
||||
vm_vec_transform(&gr_light_uniforms[light_num].direction, <p->SpotDir, &gr_view_matrix, false);
|
||||
|
||||
gr_light_uniforms[light_num].diffuse_color = vm_vec4_to_vec3(ltp->Diffuse);
|
||||
|
||||
gr_light_uniforms[light_num].spec_color = vm_vec4_to_vec3(ltp->Specular);
|
||||
|
||||
gr_light_uniforms[light_num].light_type = ltp->type;
|
||||
|
||||
gr_light_uniforms[light_num].attenuation = ltp->LinearAtten;
|
||||
}
|
||||
|
||||
static bool sort_active_lights(const gr_light& la, const gr_light& lb) {
|
||||
// directional lights always go first
|
||||
if ((la.type != LT_DIRECTIONAL) && (lb.type == LT_DIRECTIONAL)) {
|
||||
return false;
|
||||
} else if ((la.type == LT_DIRECTIONAL) && (lb.type != LT_DIRECTIONAL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// tube lights go next, they are generally large and intense
|
||||
if ((la.type != LT_TUBE) && (lb.type == LT_TUBE)) {
|
||||
return false;
|
||||
} else if ((la.type == LT_TUBE) && (lb.type != LT_TUBE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// everything else is sorted by linear atten (light size)
|
||||
// NOTE: smaller atten is larger light radius!
|
||||
if (la.LinearAtten > lb.LinearAtten) {
|
||||
return false;
|
||||
} else if (la.LinearAtten < lb.LinearAtten) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// as one extra check, if we're still here, go with overall brightness of light
|
||||
|
||||
float la_value = la.Diffuse.xyzw.x + la.Diffuse.xyzw.y + la.Diffuse.xyzw.z;
|
||||
float lb_value = lb.Diffuse.xyzw.x + lb.Diffuse.xyzw.y + lb.Diffuse.xyzw.z;
|
||||
|
||||
if (la_value < lb_value) {
|
||||
return false;
|
||||
} else if (la_value > lb_value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// the two are equal
|
||||
return false;
|
||||
}
|
||||
|
||||
static void pre_render_init_lights() {
|
||||
// sort the lights to try and get the most visible lights on the first pass
|
||||
std::sort(gr_lights, gr_lights + Num_active_gr_lights, sort_active_lights);
|
||||
}
|
||||
|
||||
void gr_set_light(light* fs_light) {
|
||||
if (Num_active_gr_lights >= MAX_LIGHTS) {
|
||||
return;
|
||||
}
|
||||
|
||||
//if (fs_light->type == LT_POINT)
|
||||
// return;
|
||||
|
||||
// init the light
|
||||
FSLight2GLLight(fs_light, &gr_lights[Num_active_gr_lights]);
|
||||
gr_lights[Num_active_gr_lights++].occupied = true;
|
||||
}
|
||||
|
||||
void gr_set_center_alpha(int type) {
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Num_active_gr_lights == MAX_LIGHTS) {
|
||||
return;
|
||||
}
|
||||
gr_light glight;
|
||||
|
||||
vec3d dir;
|
||||
vm_vec_sub(&dir, &Eye_position, &Object_position);
|
||||
vm_vec_normalize(&dir);
|
||||
|
||||
if (type == 1) {
|
||||
glight.Diffuse.xyzw.x = 0.0f;
|
||||
glight.Diffuse.xyzw.y = 0.0f;
|
||||
glight.Diffuse.xyzw.z = 0.0f;
|
||||
glight.Ambient.xyzw.x = gr_screen.current_alpha;
|
||||
glight.Ambient.xyzw.y = gr_screen.current_alpha;
|
||||
glight.Ambient.xyzw.z = gr_screen.current_alpha;
|
||||
} else {
|
||||
glight.Diffuse.xyzw.x = gr_screen.current_alpha;
|
||||
glight.Diffuse.xyzw.y = gr_screen.current_alpha;
|
||||
glight.Diffuse.xyzw.z = gr_screen.current_alpha;
|
||||
glight.Ambient.xyzw.x = 0.0f;
|
||||
glight.Ambient.xyzw.y = 0.0f;
|
||||
glight.Ambient.xyzw.z = 0.0f;
|
||||
}
|
||||
glight.type = type;
|
||||
|
||||
glight.Specular.xyzw.x = 0.0f;
|
||||
glight.Specular.xyzw.y = 0.0f;
|
||||
glight.Specular.xyzw.z = 0.0f;
|
||||
glight.Specular.xyzw.w = 0.0f;
|
||||
|
||||
glight.Ambient.xyzw.w = 1.0f;
|
||||
glight.Diffuse.xyzw.w = 1.0f;
|
||||
|
||||
glight.Position.xyzw.x = -dir.xyz.x;
|
||||
glight.Position.xyzw.y = -dir.xyz.y;
|
||||
glight.Position.xyzw.z = -dir.xyz.z;
|
||||
glight.Position.xyzw.w = 0.0f;
|
||||
|
||||
// defaults
|
||||
glight.SpotDir.xyz.x = 0.0f;
|
||||
glight.SpotDir.xyz.y = 0.0f;
|
||||
glight.SpotDir.xyz.z = -1.0f;
|
||||
glight.SpotExp = Cmdline_ogl_spec * 0.5f;
|
||||
glight.SpotCutOff = 180.0f;
|
||||
glight.ConstantAtten = 1.0f;
|
||||
glight.LinearAtten = 0.0f;
|
||||
glight.QuadraticAtten = 0.0f;
|
||||
glight.occupied = false;
|
||||
|
||||
// first light
|
||||
memcpy(&gr_lights[Num_active_gr_lights], &glight, sizeof(gr_light));
|
||||
gr_lights[Num_active_gr_lights++].occupied = true;
|
||||
|
||||
// second light
|
||||
glight.Position.xyzw.x = dir.xyz.x;
|
||||
glight.Position.xyzw.y = dir.xyz.y;
|
||||
glight.Position.xyzw.z = dir.xyz.z;
|
||||
|
||||
memcpy(&gr_lights[Num_active_gr_lights], &glight, sizeof(gr_light));
|
||||
gr_lights[Num_active_gr_lights++].occupied = true;
|
||||
}
|
||||
|
||||
void gr_reset_lighting() {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (int)graphics::MAX_UNIFORM_LIGHTS; i++) {
|
||||
gr_lights[i].occupied = false;
|
||||
}
|
||||
|
||||
Num_active_gr_lights = 0;
|
||||
}
|
||||
|
||||
static void calculate_ambient_factor() {
|
||||
float amb_user = 0.0f;
|
||||
|
||||
// assuming that the default is "128", just skip this if not a user setting
|
||||
if (Cmdline_ambient_factor == 128) {
|
||||
return;
|
||||
}
|
||||
|
||||
amb_user = (float) ((Cmdline_ambient_factor * 2) - 255) / 255.0f;
|
||||
|
||||
// set the ambient light
|
||||
gr_light_ambient[0] += amb_user;
|
||||
gr_light_ambient[1] += amb_user;
|
||||
gr_light_ambient[2] += amb_user;
|
||||
|
||||
CLAMP(gr_light_ambient[0], 0.02f, 1.0f);
|
||||
CLAMP(gr_light_ambient[1], 0.02f, 1.0f);
|
||||
CLAMP(gr_light_ambient[2], 0.02f, 1.0f);
|
||||
|
||||
gr_light_ambient[3] = 1.0f;
|
||||
}
|
||||
|
||||
void gr_light_shutdown() {
|
||||
if (gr_lights != NULL) {
|
||||
vm_free(gr_lights);
|
||||
gr_lights = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void gr_light_init() {
|
||||
calculate_ambient_factor();
|
||||
|
||||
// allocate memory for enabled lights
|
||||
if (gr_lights == NULL) {
|
||||
gr_lights = (gr_light*) vm_malloc(MAX_LIGHTS * sizeof(gr_light), memory::quiet_alloc);
|
||||
}
|
||||
|
||||
if (gr_lights == NULL) {
|
||||
Error(LOCATION, "Unable to allocate memory for lights!\n");
|
||||
}
|
||||
|
||||
memset(gr_lights, 0, MAX_LIGHTS * sizeof(gr_light));
|
||||
}
|
||||
|
||||
void gr_set_lighting(bool set, bool state) {
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Valathil: Sort lights by priority
|
||||
extern bool Deferred_lighting;
|
||||
if (!Deferred_lighting) {
|
||||
pre_render_init_lights();
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < (int)graphics::MAX_UNIFORM_LIGHTS; i++) {
|
||||
if (i >= Num_active_gr_lights) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (gr_lights[i].occupied) {
|
||||
set_light(i, &gr_lights[i]);
|
||||
}
|
||||
}
|
||||
|
||||
gr_light zero;
|
||||
memset(&zero, 0, sizeof(gr_light));
|
||||
zero.Position.xyzw.x = 1.0f;
|
||||
|
||||
// make sure that we turn off any lights that we aren't using right now
|
||||
for (; i < (int)graphics::MAX_UNIFORM_LIGHTS; i++) {
|
||||
set_light(i, &zero);
|
||||
}
|
||||
}
|
||||
|
||||
void gr_set_ambient_light(int red, int green, int blue) {
|
||||
gr_light_ambient[0] = i2fl(red) / 255.0f;
|
||||
gr_light_ambient[1] = i2fl(green) / 255.0f;
|
||||
gr_light_ambient[2] = i2fl(blue) / 255.0f;
|
||||
gr_light_ambient[3] = 1.0f;
|
||||
|
||||
calculate_ambient_factor();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "lighting/lighting.h"
|
||||
#include "graphics/util/uniform_structs.h"
|
||||
|
||||
//Variables
|
||||
extern graphics::model_light gr_light_uniforms[graphics::MAX_UNIFORM_LIGHTS];
|
||||
|
||||
//Variables
|
||||
extern int Num_active_gr_lights;
|
||||
|
||||
extern const float gr_light_color[4];
|
||||
extern const float gr_light_zero[4];
|
||||
extern const float gr_light_emission[4];
|
||||
extern float gr_light_ambient[4];
|
||||
|
||||
//Functions
|
||||
void gr_set_light(light *fs_light);
|
||||
void gr_reset_lighting();
|
||||
void gr_set_lighting(bool set, bool state);
|
||||
void gr_set_center_alpha(int type);
|
||||
void gr_set_ambient_light(int red, int green, int blue);
|
||||
|
||||
void gr_light_init();
|
||||
void gr_light_shutdown();
|
||||
+151
-35
@@ -124,8 +124,42 @@ void material_set_distortion(distortion_material *mat_info, int texture, bool th
|
||||
mat_info->set_color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void material_set_movie(movie_material* mat_info, int y_bm, int u_bm, int v_bm) {
|
||||
mat_info->set_depth_mode(ZBUFFER_TYPE_NONE);
|
||||
mat_info->set_blend_mode(ALPHA_BLEND_ALPHA_BLEND_ALPHA);
|
||||
|
||||
mat_info->set_cull_mode(false);
|
||||
mat_info->set_color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
mat_info->setYtex(y_bm);
|
||||
mat_info->setUtex(u_bm);
|
||||
mat_info->setVtex(v_bm);
|
||||
|
||||
mat_info->set_texture_type(material::TEX_TYPE_AABITMAP);
|
||||
}
|
||||
|
||||
void material_set_batched_bitmap(batched_bitmap_material* mat_info, int base_tex, float alpha, float color_scale) {
|
||||
material_set_unlit(mat_info, base_tex, alpha, true, true);
|
||||
|
||||
mat_info->set_color_scale(color_scale);
|
||||
}
|
||||
void material_set_nanovg(nanovg_material* mat_info, int base_tex) {
|
||||
material_set_unlit(mat_info, base_tex, 1.0f, true, false);
|
||||
|
||||
mat_info->set_cull_mode(false);
|
||||
|
||||
mat_info->set_color_mask(true, true, true, true);
|
||||
|
||||
mat_info->set_blend_mode(ALPHA_BLEND_PREMULTIPLIED);
|
||||
|
||||
mat_info->set_stencil_mask(0xFFFFFFFF);
|
||||
mat_info->set_stencil_func(ComparisionFunction::Always, 0, 0xFFFFFFFF);
|
||||
mat_info->set_front_stencil_op(StencilOperation::Keep, StencilOperation::Keep, StencilOperation::Keep);
|
||||
mat_info->set_back_stencil_op(StencilOperation::Keep, StencilOperation::Keep, StencilOperation::Keep);
|
||||
}
|
||||
|
||||
material::material():
|
||||
Sdr_type(SDR_TYPE_PASSTHROUGH_RENDER),
|
||||
Sdr_type(SDR_TYPE_DEFAULT_MATERIAL),
|
||||
Tex_type(TEX_TYPE_NORMAL),
|
||||
Texture_addressing(TMAP_ADDRESS_WRAP),
|
||||
Depth_mode(ZBUFFER_TYPE_NONE),
|
||||
@@ -158,7 +192,10 @@ Depth_bias(0)
|
||||
|
||||
Clip_params.enabled = false;
|
||||
|
||||
|
||||
Color_mask.x = true;
|
||||
Color_mask.y = true;
|
||||
Color_mask.z = true;
|
||||
Color_mask.w = true;
|
||||
};
|
||||
|
||||
void material::set_shader_type(shader_type init_sdr_type)
|
||||
@@ -166,12 +203,12 @@ void material::set_shader_type(shader_type init_sdr_type)
|
||||
Sdr_type = init_sdr_type;
|
||||
}
|
||||
|
||||
uint material::get_shader_flags()
|
||||
uint material::get_shader_flags() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int material::get_shader_handle()
|
||||
int material::get_shader_handle() const
|
||||
{
|
||||
return gr_maybe_create_shader(Sdr_type, get_shader_flags());
|
||||
}
|
||||
@@ -183,14 +220,14 @@ void material::set_texture_map(int tex_type, int texture_num)
|
||||
Texture_maps[tex_type] = texture_num;
|
||||
}
|
||||
|
||||
int material::get_texture_map(int tex_type)
|
||||
int material::get_texture_map(int tex_type) const
|
||||
{
|
||||
Assert(tex_type > -1 && tex_type < TM_NUM_TYPES);
|
||||
|
||||
return Texture_maps[tex_type];
|
||||
}
|
||||
|
||||
bool material::is_textured()
|
||||
bool material::is_textured() const
|
||||
{
|
||||
return
|
||||
Texture_maps[TM_BASE_TYPE] > -1 ||
|
||||
@@ -206,7 +243,7 @@ void material::set_texture_type(texture_type t_type)
|
||||
Tex_type = t_type;
|
||||
}
|
||||
|
||||
int material::get_texture_type()
|
||||
int material::get_texture_type() const
|
||||
{
|
||||
switch ( Tex_type ) {
|
||||
default:
|
||||
@@ -221,7 +258,7 @@ int material::get_texture_type()
|
||||
}
|
||||
}
|
||||
|
||||
bool material::is_clipped()
|
||||
bool material::is_clipped() const
|
||||
{
|
||||
return Clip_params.enabled;
|
||||
}
|
||||
@@ -238,7 +275,7 @@ void material::set_clip_plane()
|
||||
Clip_params.enabled = false;
|
||||
}
|
||||
|
||||
material::clip_plane& material::get_clip_plane()
|
||||
const material::clip_plane& material::get_clip_plane() const
|
||||
{
|
||||
return Clip_params;
|
||||
}
|
||||
@@ -248,7 +285,7 @@ void material::set_texture_addressing(int addressing)
|
||||
Texture_addressing = addressing;
|
||||
}
|
||||
|
||||
int material::get_texture_addressing()
|
||||
int material::get_texture_addressing() const
|
||||
{
|
||||
return Texture_addressing;
|
||||
}
|
||||
@@ -268,12 +305,12 @@ void material::set_fog()
|
||||
Fog_params.enabled = false;
|
||||
}
|
||||
|
||||
bool material::is_fogged()
|
||||
bool material::is_fogged() const
|
||||
{
|
||||
return Fog_params.enabled;
|
||||
}
|
||||
|
||||
material::fog& material::get_fog()
|
||||
const material::fog& material::get_fog() const
|
||||
{
|
||||
return Fog_params;
|
||||
}
|
||||
@@ -283,7 +320,7 @@ void material::set_depth_mode(gr_zbuffer_type mode)
|
||||
Depth_mode = mode;
|
||||
}
|
||||
|
||||
gr_zbuffer_type material::get_depth_mode()
|
||||
gr_zbuffer_type material::get_depth_mode() const
|
||||
{
|
||||
return Depth_mode;
|
||||
}
|
||||
@@ -293,7 +330,7 @@ void material::set_cull_mode(bool mode)
|
||||
Cull_mode = mode;
|
||||
}
|
||||
|
||||
bool material::get_cull_mode()
|
||||
bool material::get_cull_mode() const
|
||||
{
|
||||
return Cull_mode;
|
||||
}
|
||||
@@ -303,7 +340,7 @@ void material::set_fill_mode(int mode)
|
||||
Fill_mode = mode;
|
||||
}
|
||||
|
||||
int material::get_fill_mode()
|
||||
int material::get_fill_mode() const
|
||||
{
|
||||
return Fill_mode;
|
||||
}
|
||||
@@ -313,7 +350,7 @@ void material::set_blend_mode(gr_alpha_blend mode)
|
||||
Blend_mode = mode;
|
||||
}
|
||||
|
||||
gr_alpha_blend material::get_blend_mode()
|
||||
gr_alpha_blend material::get_blend_mode() const
|
||||
{
|
||||
return Blend_mode;
|
||||
}
|
||||
@@ -323,7 +360,7 @@ void material::set_depth_bias(int bias)
|
||||
Depth_bias = bias;
|
||||
}
|
||||
|
||||
int material::get_depth_bias()
|
||||
int material::get_depth_bias() const
|
||||
{
|
||||
return Depth_bias;
|
||||
}
|
||||
@@ -364,7 +401,7 @@ void material::set_color(color &clr_in)
|
||||
}
|
||||
}
|
||||
|
||||
const vec4& material::get_color()
|
||||
const vec4& material::get_color() const
|
||||
{
|
||||
return Clr;
|
||||
}
|
||||
@@ -374,10 +411,59 @@ void material::set_color_scale(float scale)
|
||||
Clr_scale = scale;
|
||||
}
|
||||
|
||||
float material::get_color_scale()
|
||||
float material::get_color_scale() const
|
||||
{
|
||||
return Clr_scale;
|
||||
}
|
||||
void material::set_stencil_test(bool stencil) {
|
||||
Stencil_test = stencil;
|
||||
}
|
||||
bool material::is_stencil_enabled() const {
|
||||
return Stencil_test;
|
||||
}
|
||||
void material::set_stencil_mask(uint32_t mask) {
|
||||
Stencil_mask = mask;
|
||||
}
|
||||
uint32_t material::get_stencil_mask() const {
|
||||
return Stencil_mask;
|
||||
}
|
||||
void material::set_stencil_func(ComparisionFunction compare, int ref, uint32_t mask) {
|
||||
Stencil_func.compare = compare;
|
||||
Stencil_func.ref = ref;
|
||||
Stencil_func.mask = mask;
|
||||
}
|
||||
const material::StencilFunc& material::get_stencil_func() const {
|
||||
return Stencil_func;
|
||||
}
|
||||
void material::set_front_stencil_op(StencilOperation stencilFailOperation,
|
||||
StencilOperation depthFailOperation,
|
||||
StencilOperation successOperation) {
|
||||
Front_stencil_op.stencilFailOperation = stencilFailOperation;
|
||||
Front_stencil_op.depthFailOperation = depthFailOperation;
|
||||
Front_stencil_op.successOperation = successOperation;
|
||||
}
|
||||
const material::StencilOp& material::get_front_stencil_op() const {
|
||||
return Front_stencil_op;
|
||||
}
|
||||
void material::set_back_stencil_op(StencilOperation stencilFailOperation,
|
||||
StencilOperation depthFailOperation,
|
||||
StencilOperation successOperation) {
|
||||
Back_stencil_op.stencilFailOperation = stencilFailOperation;
|
||||
Back_stencil_op.depthFailOperation = depthFailOperation;
|
||||
Back_stencil_op.successOperation = successOperation;
|
||||
}
|
||||
const material::StencilOp& material::get_back_stencil_op() const {
|
||||
return Back_stencil_op;
|
||||
}
|
||||
void material::set_color_mask(bool red, bool green, bool blue, bool alpha) {
|
||||
Color_mask.x = red;
|
||||
Color_mask.y = green;
|
||||
Color_mask.z = blue;
|
||||
Color_mask.w = alpha;
|
||||
}
|
||||
const bvec4& material::get_color_mask() const {
|
||||
return Color_mask;
|
||||
}
|
||||
|
||||
model_material::model_material() : material() {
|
||||
set_shader_type(SDR_TYPE_MODEL);
|
||||
@@ -388,7 +474,7 @@ void model_material::set_desaturation(bool enabled)
|
||||
Desaturate = enabled;
|
||||
}
|
||||
|
||||
bool model_material::is_desaturated()
|
||||
bool model_material::is_desaturated() const
|
||||
{
|
||||
return Desaturate;
|
||||
}
|
||||
@@ -403,7 +489,7 @@ void model_material::set_light_factor(float factor)
|
||||
Light_factor = factor;
|
||||
}
|
||||
|
||||
float model_material::get_light_factor()
|
||||
float model_material::get_light_factor() const
|
||||
{
|
||||
return Light_factor;
|
||||
}
|
||||
@@ -413,7 +499,7 @@ void model_material::set_lighting(bool mode)
|
||||
lighting = mode;
|
||||
}
|
||||
|
||||
bool model_material::is_lit()
|
||||
bool model_material::is_lit() const
|
||||
{
|
||||
return lighting;
|
||||
}
|
||||
@@ -433,7 +519,7 @@ void model_material::set_center_alpha(int c_alpha)
|
||||
Center_alpha = c_alpha;
|
||||
}
|
||||
|
||||
int model_material::get_center_alpha()
|
||||
int model_material::get_center_alpha() const
|
||||
{
|
||||
return Center_alpha;
|
||||
}
|
||||
@@ -443,7 +529,7 @@ void model_material::set_thrust_scale(float scale)
|
||||
Thrust_scale = scale;
|
||||
}
|
||||
|
||||
float model_material::get_thrust_scale()
|
||||
float model_material::get_thrust_scale() const
|
||||
{
|
||||
return Thrust_scale;
|
||||
}
|
||||
@@ -459,7 +545,7 @@ void model_material::set_team_color()
|
||||
Team_color_set = false;
|
||||
}
|
||||
|
||||
team_color& model_material::get_team_color()
|
||||
const team_color& model_material::get_team_color() const
|
||||
{
|
||||
return Tm_color;
|
||||
}
|
||||
@@ -476,12 +562,12 @@ void model_material::set_animated_effect()
|
||||
Animated_timer = 0.0f;
|
||||
}
|
||||
|
||||
int model_material::get_animated_effect()
|
||||
int model_material::get_animated_effect() const
|
||||
{
|
||||
return Animated_effect;
|
||||
}
|
||||
|
||||
float model_material::get_animated_effect_time()
|
||||
float model_material::get_animated_effect_time() const
|
||||
{
|
||||
return Animated_timer;
|
||||
}
|
||||
@@ -491,7 +577,7 @@ void model_material::set_batching(bool enabled)
|
||||
Batched = enabled;
|
||||
}
|
||||
|
||||
bool model_material::is_batched()
|
||||
bool model_material::is_batched() const
|
||||
{
|
||||
return Batched;
|
||||
}
|
||||
@@ -508,17 +594,17 @@ void model_material::set_normal_alpha()
|
||||
Normal_alpha = false;
|
||||
}
|
||||
|
||||
bool model_material::is_normal_alpha_active()
|
||||
bool model_material::is_normal_alpha_active() const
|
||||
{
|
||||
return Normal_alpha;
|
||||
}
|
||||
|
||||
float model_material::get_normal_alpha_min()
|
||||
float model_material::get_normal_alpha_min() const
|
||||
{
|
||||
return Normal_alpha_min;
|
||||
}
|
||||
|
||||
float model_material::get_normal_alpha_max()
|
||||
float model_material::get_normal_alpha_max() const
|
||||
{
|
||||
return Normal_alpha_max;
|
||||
}
|
||||
@@ -534,17 +620,17 @@ void model_material::set_normal_extrude()
|
||||
Normal_extrude = false;
|
||||
}
|
||||
|
||||
bool model_material::is_normal_extrude_active()
|
||||
bool model_material::is_normal_extrude_active() const
|
||||
{
|
||||
return Normal_extrude;
|
||||
}
|
||||
|
||||
float model_material::get_normal_extrude_width()
|
||||
float model_material::get_normal_extrude_width() const
|
||||
{
|
||||
return Normal_extrude_width;
|
||||
}
|
||||
|
||||
uint model_material::get_shader_flags()
|
||||
uint model_material::get_shader_flags() const
|
||||
{
|
||||
uint Shader_flags = 0;
|
||||
|
||||
@@ -654,7 +740,7 @@ bool particle_material::get_point_sprite_mode()
|
||||
return Point_sprite;
|
||||
}
|
||||
|
||||
uint particle_material::get_shader_flags()
|
||||
uint particle_material::get_shader_flags() const
|
||||
{
|
||||
uint flags = 0;
|
||||
|
||||
@@ -720,3 +806,33 @@ float shield_material::get_impact_radius()
|
||||
{
|
||||
return Impact_radius;
|
||||
}
|
||||
|
||||
movie_material::movie_material() : material() {
|
||||
set_shader_type(SDR_TYPE_VIDEO_PROCESS);
|
||||
}
|
||||
int movie_material::getYtex() const {
|
||||
return Ytex;
|
||||
}
|
||||
int movie_material::getUtex() const {
|
||||
return Utex;
|
||||
}
|
||||
int movie_material::getVtex() const {
|
||||
return Vtex;
|
||||
}
|
||||
void movie_material::setYtex(int _Ytex) {
|
||||
this->Ytex = _Ytex;
|
||||
}
|
||||
void movie_material::setUtex(int _Utex) {
|
||||
this->Utex = _Utex;
|
||||
}
|
||||
void movie_material::setVtex(int _Vtex) {
|
||||
movie_material::Vtex = _Vtex;
|
||||
}
|
||||
|
||||
batched_bitmap_material::batched_bitmap_material() {
|
||||
set_shader_type(SDR_TYPE_BATCHED_BITMAP);
|
||||
}
|
||||
|
||||
nanovg_material::nanovg_material() {
|
||||
set_shader_type(SDR_TYPE_NANOVG);
|
||||
}
|
||||
+127
-34
@@ -4,6 +4,29 @@
|
||||
#include "graphics/grinternal.h"
|
||||
#include "model/model.h"
|
||||
|
||||
enum class ComparisionFunction
|
||||
{
|
||||
Never,
|
||||
Always,
|
||||
Less,
|
||||
Greater,
|
||||
Equal,
|
||||
NotEqual,
|
||||
LessOrEqual,
|
||||
GreaterOrEqual
|
||||
};
|
||||
|
||||
enum class StencilOperation {
|
||||
Keep,
|
||||
Zero,
|
||||
Replace,
|
||||
Increment,
|
||||
IncrementWrap,
|
||||
Decrement,
|
||||
DecrementWrap,
|
||||
Invert
|
||||
};
|
||||
|
||||
class material
|
||||
{
|
||||
public:
|
||||
@@ -31,6 +54,18 @@ public:
|
||||
TEX_TYPE_INTERFACE
|
||||
};
|
||||
|
||||
struct StencilFunc {
|
||||
ComparisionFunction compare = ComparisionFunction::Always;
|
||||
int ref = 1;
|
||||
uint32_t mask = 0xFFFFFFFF;
|
||||
};
|
||||
|
||||
struct StencilOp {
|
||||
StencilOperation stencilFailOperation = StencilOperation::Keep;
|
||||
StencilOperation depthFailOperation = StencilOperation::Keep;
|
||||
StencilOperation successOperation = StencilOperation::Keep;
|
||||
};
|
||||
|
||||
private:
|
||||
shader_type Sdr_type;
|
||||
|
||||
@@ -47,57 +82,85 @@ private:
|
||||
vec4 Clr;
|
||||
float Clr_scale;
|
||||
int Depth_bias;
|
||||
bvec4 Color_mask;
|
||||
bool Stencil_test = false;
|
||||
uint32_t Stencil_mask = 0xFF;
|
||||
StencilFunc Stencil_func;
|
||||
StencilOp Front_stencil_op;
|
||||
StencilOp Back_stencil_op;
|
||||
|
||||
protected:
|
||||
void set_shader_type(shader_type init_sdr_type = SDR_TYPE_NONE);
|
||||
public:
|
||||
material();
|
||||
|
||||
int get_shader_handle();
|
||||
virtual uint get_shader_flags();
|
||||
int get_shader_handle() const;
|
||||
virtual uint get_shader_flags() const;
|
||||
|
||||
void set_texture_map(int tex_type, int texture_num);
|
||||
int get_texture_map(int tex_type);
|
||||
bool is_textured();
|
||||
int get_texture_map(int tex_type) const;
|
||||
bool is_textured() const;
|
||||
|
||||
void set_texture_type(texture_type t_type);
|
||||
int get_texture_type();
|
||||
int get_texture_type() const;
|
||||
|
||||
bool is_clipped();
|
||||
bool is_clipped() const;
|
||||
void set_clip_plane(const vec3d &normal, const vec3d &position);
|
||||
void set_clip_plane();
|
||||
clip_plane& get_clip_plane();
|
||||
const clip_plane& get_clip_plane() const;
|
||||
|
||||
void set_texture_addressing(int addressing);
|
||||
int get_texture_addressing();
|
||||
int get_texture_addressing() const;
|
||||
|
||||
void set_fog(int r, int g, int b, float near, float far);
|
||||
void set_fog();
|
||||
bool is_fogged();
|
||||
fog& get_fog();
|
||||
bool is_fogged() const;
|
||||
const fog& get_fog() const;
|
||||
|
||||
void set_depth_mode(gr_zbuffer_type mode);
|
||||
gr_zbuffer_type get_depth_mode();
|
||||
gr_zbuffer_type get_depth_mode() const;
|
||||
|
||||
void set_cull_mode(bool mode);
|
||||
bool get_cull_mode();
|
||||
bool get_cull_mode() const;
|
||||
|
||||
void set_fill_mode(int mode);
|
||||
int get_fill_mode();
|
||||
int get_fill_mode() const;
|
||||
|
||||
void set_color_mask(bool red, bool green, bool blue, bool alpha);
|
||||
const bvec4& get_color_mask() const;
|
||||
|
||||
void set_blend_mode(gr_alpha_blend mode);
|
||||
gr_alpha_blend get_blend_mode();
|
||||
gr_alpha_blend get_blend_mode() const;
|
||||
|
||||
void set_depth_bias(int bias);
|
||||
int get_depth_bias();
|
||||
int get_depth_bias() const;
|
||||
|
||||
void set_color(float red, float green, float blue, float alpha);
|
||||
void set_color(int r, int g, int b, int a);
|
||||
void set_color(color &clr_in);
|
||||
const vec4& get_color();
|
||||
const vec4& get_color() const;
|
||||
|
||||
void set_color_scale(float scale);
|
||||
float get_color_scale();
|
||||
float get_color_scale() const;
|
||||
|
||||
void set_stencil_test(bool stencil);
|
||||
bool is_stencil_enabled() const;
|
||||
|
||||
void set_stencil_mask(uint32_t mask);
|
||||
uint32_t get_stencil_mask() const;
|
||||
|
||||
void set_stencil_func(ComparisionFunction compare, int ref, uint32_t mask);
|
||||
const StencilFunc& get_stencil_func() const;
|
||||
|
||||
void set_front_stencil_op(StencilOperation stencilFailOperation,
|
||||
StencilOperation depthFailOperation,
|
||||
StencilOperation successOperation);
|
||||
const StencilOp& get_front_stencil_op() const;
|
||||
|
||||
void set_back_stencil_op(StencilOperation stencilFailOperation,
|
||||
StencilOperation depthFailOperation,
|
||||
StencilOperation successOperation);
|
||||
const StencilOp& get_back_stencil_op() const;
|
||||
};
|
||||
|
||||
class model_material : public material
|
||||
@@ -133,50 +196,50 @@ public:
|
||||
model_material();
|
||||
|
||||
void set_desaturation(bool enabled);
|
||||
bool is_desaturated();
|
||||
bool is_desaturated() const;
|
||||
|
||||
void set_shadow_casting(bool enabled);
|
||||
bool is_shadow_casting();
|
||||
bool is_shadow_casting() const;
|
||||
|
||||
void set_light_factor(float factor);
|
||||
float get_light_factor();
|
||||
float get_light_factor() const;
|
||||
|
||||
void set_lighting(bool mode);
|
||||
bool is_lit();
|
||||
bool is_lit() const;
|
||||
|
||||
void set_deferred_lighting(bool enabled);
|
||||
void set_high_dynamic_range(bool enabled);
|
||||
|
||||
void set_center_alpha(int center_alpha);
|
||||
int get_center_alpha();
|
||||
int get_center_alpha() const;
|
||||
|
||||
void set_thrust_scale(float scale = -1.0f);
|
||||
float get_thrust_scale();
|
||||
float get_thrust_scale() const;
|
||||
|
||||
void set_team_color(const team_color &Team_clr);
|
||||
void set_team_color();
|
||||
team_color& get_team_color();
|
||||
const team_color& get_team_color() const;
|
||||
|
||||
void set_animated_effect(int effect, float time);
|
||||
void set_animated_effect();
|
||||
int get_animated_effect();
|
||||
float get_animated_effect_time();
|
||||
int get_animated_effect() const;
|
||||
float get_animated_effect_time() const;
|
||||
|
||||
void set_normal_alpha(float min, float max);
|
||||
void set_normal_alpha();
|
||||
bool is_normal_alpha_active();
|
||||
float get_normal_alpha_min();
|
||||
float get_normal_alpha_max();
|
||||
bool is_normal_alpha_active() const;
|
||||
float get_normal_alpha_min() const;
|
||||
float get_normal_alpha_max() const;
|
||||
|
||||
void set_normal_extrude(float width);
|
||||
void set_normal_extrude();
|
||||
bool is_normal_extrude_active();
|
||||
float get_normal_extrude_width();
|
||||
bool is_normal_extrude_active() const;
|
||||
float get_normal_extrude_width() const;
|
||||
|
||||
void set_batching(bool enabled);
|
||||
bool is_batched();
|
||||
bool is_batched() const;
|
||||
|
||||
virtual uint get_shader_flags();
|
||||
virtual uint get_shader_flags() const override;
|
||||
};
|
||||
|
||||
class particle_material : public material
|
||||
@@ -188,7 +251,7 @@ public:
|
||||
void set_point_sprite_mode(bool enabled);
|
||||
bool get_point_sprite_mode();
|
||||
|
||||
virtual uint get_shader_flags();
|
||||
uint get_shader_flags() const override;
|
||||
};
|
||||
|
||||
class distortion_material: public material
|
||||
@@ -217,6 +280,33 @@ public:
|
||||
float get_impact_radius();
|
||||
};
|
||||
|
||||
class movie_material : public material {
|
||||
int Ytex = -1;
|
||||
int Utex = -1;
|
||||
int Vtex = -1;
|
||||
public:
|
||||
movie_material();
|
||||
|
||||
int getYtex() const;
|
||||
int getUtex() const;
|
||||
int getVtex() const;
|
||||
|
||||
void setYtex(int _Ytex);
|
||||
void setUtex(int _Utex);
|
||||
void setVtex(int _Vtex);
|
||||
};
|
||||
|
||||
class batched_bitmap_material : public material
|
||||
{
|
||||
public:
|
||||
batched_bitmap_material();
|
||||
};
|
||||
|
||||
class nanovg_material : public material {
|
||||
public:
|
||||
nanovg_material();
|
||||
};
|
||||
|
||||
gr_alpha_blend material_determine_blend_mode(int base_bitmap, bool is_transparent);
|
||||
gr_zbuffer_type material_determine_depth_mode(bool depth_testing, bool is_transparent);
|
||||
|
||||
@@ -227,5 +317,8 @@ void material_set_unlit_color(material* mat_info, int texture, color *clr, bool
|
||||
void material_set_unlit_color(material* mat_info, int texture, color *clr, float alpha, bool blending, bool depth_testing);
|
||||
void material_set_unlit_volume(particle_material* mat_info, int texture, bool point_sprites);
|
||||
void material_set_distortion(distortion_material *mat_info, int texture, bool thruster);
|
||||
void material_set_movie(movie_material *mat_info, int y_bm, int u_bm, int v_bm);
|
||||
void material_set_batched_bitmap(batched_bitmap_material* mat_info, int base_tex, float alpha, float color_scale);
|
||||
void material_set_nanovg(nanovg_material* mat_info, int base_tex);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,323 @@
|
||||
|
||||
#include "matrix.h"
|
||||
|
||||
transform_stack gr_model_matrix_stack;
|
||||
matrix4 gr_view_matrix;
|
||||
matrix4 gr_model_view_matrix;
|
||||
matrix4 gr_projection_matrix;
|
||||
matrix4 gr_last_projection_matrix;
|
||||
matrix4 gr_last_view_matrix;
|
||||
|
||||
matrix4 gr_texture_matrix;
|
||||
|
||||
matrix4 gr_env_texture_matrix;
|
||||
static bool gr_env_texture_matrix_set = false;
|
||||
|
||||
bool gr_htl_projection_matrix_set = false;
|
||||
|
||||
static int modelview_matrix_depth = 1;
|
||||
static bool htl_view_matrix_set = false;
|
||||
static int htl_2d_matrix_depth = 0;
|
||||
static bool htl_2d_matrix_set = false;
|
||||
|
||||
static matrix4 create_view_matrix(const vec3d *pos, const matrix *orient)
|
||||
{
|
||||
vec3d scaled_pos;
|
||||
vec3d inv_pos;
|
||||
matrix scaled_orient = *orient;
|
||||
matrix inv_orient;
|
||||
|
||||
vm_vec_copy_scale(&scaled_pos, pos, -1.0f);
|
||||
vm_vec_scale(&scaled_orient.vec.fvec, -1.0f);
|
||||
|
||||
vm_copy_transpose(&inv_orient, &scaled_orient);
|
||||
vm_vec_rotate(&inv_pos, &scaled_pos, &scaled_orient);
|
||||
|
||||
matrix4 out;
|
||||
vm_matrix4_set_transform(&out, &inv_orient, &inv_pos);
|
||||
|
||||
return out;
|
||||
}
|
||||
static void create_perspective_projection_matrix(matrix4 *out, float left, float right, float bottom, float top, float near_dist, float far_dist)
|
||||
{
|
||||
memset(out, 0, sizeof(matrix4));
|
||||
|
||||
out->a1d[0] = 2.0f * near_dist / (right - left);
|
||||
out->a1d[5] = 2.0f * near_dist / (top - bottom);
|
||||
out->a1d[8] = (right + left) / (right - left);
|
||||
out->a1d[9] = (top + bottom) / (top - bottom);
|
||||
out->a1d[10] = -(far_dist + near_dist) / (far_dist - near_dist);
|
||||
out->a1d[11] = -1.0f;
|
||||
out->a1d[14] = -2.0f * far_dist * near_dist / (far_dist - near_dist);
|
||||
}
|
||||
|
||||
static void create_orthographic_projection_matrix(matrix4* out, float left, float right, float bottom, float top, float near_dist, float far_dist)
|
||||
{
|
||||
memset(out, 0, sizeof(matrix4));
|
||||
|
||||
out->a1d[0] = 2.0f / (right - left);
|
||||
out->a1d[5] = 2.0f / (top - bottom);
|
||||
out->a1d[10] = -2.0f / (far_dist - near_dist);
|
||||
out->a1d[12] = -(right + left) / (right - left);
|
||||
out->a1d[13] = -(top + bottom) / (top - bottom);
|
||||
out->a1d[14] = -(far_dist + near_dist) / (far_dist - near_dist);
|
||||
out->a1d[15] = 1.0f;
|
||||
}
|
||||
|
||||
void gr_start_instance_matrix(const vec3d *offset, const matrix *rotation)
|
||||
{
|
||||
Assert( htl_view_matrix_set );
|
||||
|
||||
if (offset == NULL) {
|
||||
offset = &vmd_zero_vector;
|
||||
}
|
||||
|
||||
if (rotation == NULL) {
|
||||
rotation = &vmd_identity_matrix;
|
||||
}
|
||||
|
||||
gr_model_matrix_stack.push(offset, rotation);
|
||||
|
||||
auto model_matrix = gr_model_matrix_stack.get_transform();
|
||||
vm_matrix4_x_matrix4(&gr_model_view_matrix, &gr_view_matrix, &model_matrix);
|
||||
|
||||
modelview_matrix_depth++;
|
||||
}
|
||||
|
||||
void gr_start_angles_instance_matrix(const vec3d *pos, const angles *rotation)
|
||||
{
|
||||
Assert(htl_view_matrix_set);
|
||||
|
||||
matrix m;
|
||||
vm_angles_2_matrix(&m, rotation);
|
||||
|
||||
gr_start_instance_matrix(pos, &m);
|
||||
}
|
||||
|
||||
void gr_end_instance_matrix()
|
||||
{
|
||||
Assert(htl_view_matrix_set);
|
||||
|
||||
gr_model_matrix_stack.pop();
|
||||
|
||||
auto model_matrix = gr_model_matrix_stack.get_transform();
|
||||
vm_matrix4_x_matrix4(&gr_model_view_matrix, &gr_view_matrix, &model_matrix);
|
||||
|
||||
modelview_matrix_depth--;
|
||||
}
|
||||
|
||||
// the projection matrix; fov, aspect ratio, near, far
|
||||
void gr_set_proj_matrix(float fov, float aspect, float z_near, float z_far) {
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
gr_set_viewport(gr_screen.offset_x, gr_screen.offset_y, gr_screen.clip_width, gr_screen.clip_height);
|
||||
} else {
|
||||
gr_set_viewport(gr_screen.offset_x, (gr_screen.max_h - gr_screen.offset_y - gr_screen.clip_height), gr_screen.clip_width, gr_screen.clip_height);
|
||||
}
|
||||
|
||||
float clip_width, clip_height;
|
||||
|
||||
clip_height = tan( fov * 0.5f ) * z_near;
|
||||
clip_width = clip_height * aspect;
|
||||
|
||||
gr_last_projection_matrix = gr_projection_matrix;
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, clip_height, -clip_height, z_near, z_far);
|
||||
} else {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, -clip_height, clip_height, z_near, z_far);
|
||||
}
|
||||
|
||||
gr_htl_projection_matrix_set = true;
|
||||
}
|
||||
|
||||
void gr_end_proj_matrix() {
|
||||
gr_set_viewport(0, 0, gr_screen.max_w, gr_screen.max_h);
|
||||
|
||||
gr_last_projection_matrix = gr_projection_matrix;
|
||||
|
||||
// the top and bottom positions are reversed on purpose, but RTT needs them the other way
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
create_orthographic_projection_matrix(&gr_projection_matrix, 0.0f, i2fl(gr_screen.max_w), 0.0f, i2fl(gr_screen.max_h), -1.0f, 1.0f);
|
||||
} else {
|
||||
create_orthographic_projection_matrix(&gr_projection_matrix, 0.0f, i2fl(gr_screen.max_w), i2fl(gr_screen.max_h), 0.0f, -1.0f, 1.0f);
|
||||
}
|
||||
|
||||
gr_htl_projection_matrix_set = false;
|
||||
}
|
||||
|
||||
void gr_set_view_matrix(const vec3d *pos, const matrix *orient)
|
||||
{
|
||||
Assert(modelview_matrix_depth == 1);
|
||||
|
||||
gr_view_matrix = create_view_matrix(pos, orient);
|
||||
|
||||
gr_model_matrix_stack.clear();
|
||||
gr_model_view_matrix = gr_view_matrix;
|
||||
|
||||
if (Cmdline_env) {
|
||||
gr_env_texture_matrix_set = true;
|
||||
|
||||
// setup the texture matrix which will make the the envmap keep lined
|
||||
// up properly with the environment
|
||||
|
||||
// r.xyz <-- r.x, u.x, f.x
|
||||
gr_env_texture_matrix.a1d[0] = gr_model_view_matrix.a1d[0];
|
||||
gr_env_texture_matrix.a1d[1] = gr_model_view_matrix.a1d[4];
|
||||
gr_env_texture_matrix.a1d[2] = gr_model_view_matrix.a1d[8];
|
||||
// u.xyz <-- r.y, u.y, f.y
|
||||
gr_env_texture_matrix.a1d[4] = gr_model_view_matrix.a1d[1];
|
||||
gr_env_texture_matrix.a1d[5] = gr_model_view_matrix.a1d[5];
|
||||
gr_env_texture_matrix.a1d[6] = gr_model_view_matrix.a1d[9];
|
||||
// f.xyz <-- r.z, u.z, f.z
|
||||
gr_env_texture_matrix.a1d[8] = gr_model_view_matrix.a1d[2];
|
||||
gr_env_texture_matrix.a1d[9] = gr_model_view_matrix.a1d[6];
|
||||
gr_env_texture_matrix.a1d[10] = gr_model_view_matrix.a1d[10];
|
||||
|
||||
gr_env_texture_matrix.a1d[15] = 1.0f;
|
||||
}
|
||||
|
||||
modelview_matrix_depth = 2;
|
||||
htl_view_matrix_set = true;
|
||||
}
|
||||
|
||||
void gr_end_view_matrix()
|
||||
{
|
||||
Assert(modelview_matrix_depth == 2);
|
||||
|
||||
gr_model_matrix_stack.clear();
|
||||
vm_matrix4_set_identity(&gr_view_matrix);
|
||||
vm_matrix4_set_identity(&gr_model_view_matrix);
|
||||
|
||||
modelview_matrix_depth = 1;
|
||||
htl_view_matrix_set = false;
|
||||
gr_env_texture_matrix_set = false;
|
||||
}
|
||||
|
||||
// set a view and projection matrix for a 2D element
|
||||
// TODO: this probably needs to accept values
|
||||
void gr_set_2d_matrix(/*int x, int y, int w, int h*/)
|
||||
{
|
||||
// don't bother with this if we aren't even going to need it
|
||||
if (!gr_htl_projection_matrix_set) {
|
||||
return;
|
||||
}
|
||||
|
||||
Assert( htl_2d_matrix_set == 0 );
|
||||
Assert( htl_2d_matrix_depth == 0 );
|
||||
|
||||
// the viewport needs to be the full screen size since glOrtho() is relative to it
|
||||
gr_set_viewport(0, 0, gr_screen.max_w, gr_screen.max_h);
|
||||
|
||||
gr_last_projection_matrix = gr_projection_matrix;
|
||||
|
||||
// the top and bottom positions are reversed on purpose, but RTT needs them the other way
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
create_orthographic_projection_matrix(&gr_projection_matrix, 0, i2fl(gr_screen.max_w), 0, i2fl(gr_screen.max_h), -1, 1);
|
||||
} else {
|
||||
create_orthographic_projection_matrix(&gr_projection_matrix, 0, i2fl(gr_screen.max_w), i2fl(gr_screen.max_h), 0, -1, 1);
|
||||
}
|
||||
|
||||
matrix4 identity_mat;
|
||||
vm_matrix4_set_identity(&identity_mat);
|
||||
|
||||
gr_model_matrix_stack.push_and_replace(identity_mat);
|
||||
|
||||
gr_last_view_matrix = gr_view_matrix;
|
||||
gr_view_matrix = identity_mat;
|
||||
|
||||
vm_matrix4_x_matrix4(&gr_model_view_matrix, &gr_view_matrix, &identity_mat);
|
||||
|
||||
htl_2d_matrix_set = true;
|
||||
htl_2d_matrix_depth++;
|
||||
}
|
||||
|
||||
// ends a previously set 2d view and projection matrix
|
||||
void gr_end_2d_matrix()
|
||||
{
|
||||
if (!htl_2d_matrix_set)
|
||||
return;
|
||||
|
||||
Assert( htl_2d_matrix_depth == 1 );
|
||||
|
||||
// reset viewport to what it was originally set to by the proj matrix
|
||||
gr_set_viewport(gr_screen.offset_x, (gr_screen.max_h - gr_screen.offset_y - gr_screen.clip_height), gr_screen.clip_width, gr_screen.clip_height);
|
||||
|
||||
gr_projection_matrix = gr_last_projection_matrix;
|
||||
|
||||
gr_model_matrix_stack.pop();
|
||||
|
||||
gr_view_matrix = gr_last_view_matrix;
|
||||
|
||||
auto model_matrix = gr_model_matrix_stack.get_transform();
|
||||
vm_matrix4_x_matrix4(&gr_model_view_matrix, &gr_view_matrix, &model_matrix);
|
||||
|
||||
htl_2d_matrix_set = false;
|
||||
htl_2d_matrix_depth = 0;
|
||||
}
|
||||
|
||||
static bool scale_matrix_set = false;
|
||||
|
||||
void gr_push_scale_matrix(const vec3d *scale_factor)
|
||||
{
|
||||
if ( (scale_factor->xyz.x == 1) && (scale_factor->xyz.y == 1) && (scale_factor->xyz.z == 1) )
|
||||
return;
|
||||
|
||||
scale_matrix_set = true;
|
||||
|
||||
modelview_matrix_depth++;
|
||||
|
||||
gr_model_matrix_stack.push(NULL, NULL, scale_factor);
|
||||
|
||||
auto model_matrix = gr_model_matrix_stack.get_transform();
|
||||
vm_matrix4_x_matrix4(&gr_model_view_matrix, &gr_view_matrix, &model_matrix);
|
||||
}
|
||||
|
||||
void gr_pop_scale_matrix()
|
||||
{
|
||||
if (!scale_matrix_set)
|
||||
return;
|
||||
|
||||
gr_model_matrix_stack.pop();
|
||||
|
||||
auto model_matrix = gr_model_matrix_stack.get_transform();
|
||||
vm_matrix4_x_matrix4(&gr_model_view_matrix, &gr_view_matrix, &model_matrix);
|
||||
|
||||
modelview_matrix_depth--;
|
||||
scale_matrix_set = false;
|
||||
}
|
||||
void gr_setup_viewport() {
|
||||
if (Gr_inited) {
|
||||
// This may be called by FRED before the gr system is actually initialized so we need to make sure that
|
||||
// this function call is actually valid at this point.
|
||||
gr_set_viewport(0, 0, gr_screen.max_w, gr_screen.max_h);
|
||||
}
|
||||
|
||||
|
||||
gr_last_projection_matrix = gr_projection_matrix;
|
||||
|
||||
// the top and bottom positions are reversed on purpose, but RTT needs them the other way
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
create_orthographic_projection_matrix(&gr_projection_matrix, 0, i2fl(gr_screen.max_w), 0, i2fl(gr_screen.max_h), -1, 1);
|
||||
} else {
|
||||
create_orthographic_projection_matrix(&gr_projection_matrix, 0, i2fl(gr_screen.max_w), i2fl(gr_screen.max_h), 0, -1, 1);
|
||||
}
|
||||
}
|
||||
void gr_reset_matrices() {
|
||||
vm_matrix4_set_identity(&gr_projection_matrix);
|
||||
vm_matrix4_set_identity(&gr_last_projection_matrix);
|
||||
|
||||
vm_matrix4_set_identity(&gr_view_matrix);
|
||||
vm_matrix4_set_identity(&gr_last_view_matrix);
|
||||
|
||||
vm_matrix4_set_identity(&gr_model_view_matrix);
|
||||
gr_model_matrix_stack.clear();
|
||||
|
||||
vm_matrix4_set_identity(&gr_texture_matrix);
|
||||
}
|
||||
|
||||
void gr_set_texture_panning(float u, float v, bool enable) {
|
||||
vm_matrix4_set_identity(&gr_texture_matrix);
|
||||
if (enable) {
|
||||
gr_texture_matrix.a2d[3][0] = u;
|
||||
gr_texture_matrix.a2d[3][1] = v;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics/2d.h"
|
||||
|
||||
extern transform_stack gr_model_matrix_stack;
|
||||
extern matrix4 gr_view_matrix;
|
||||
extern matrix4 gr_model_view_matrix;
|
||||
extern matrix4 gr_projection_matrix;
|
||||
extern matrix4 gr_last_projection_matrix;
|
||||
extern matrix4 gr_env_texture_matrix;
|
||||
|
||||
void gr_start_instance_matrix(const vec3d *offset, const matrix *rotation);
|
||||
void gr_start_angles_instance_matrix(const vec3d *pos, const angles *rotation);
|
||||
void gr_end_instance_matrix();
|
||||
|
||||
void gr_set_proj_matrix(float fov, float aspect, float z_near, float z_far);
|
||||
void gr_end_proj_matrix();
|
||||
|
||||
void gr_set_view_matrix(const vec3d *pos, const matrix *orient);
|
||||
void gr_end_view_matrix();
|
||||
|
||||
void gr_set_2d_matrix(/*int x, int y, int w, int h*/);
|
||||
void gr_end_2d_matrix();
|
||||
|
||||
void gr_push_scale_matrix(const vec3d *scale_factor);
|
||||
void gr_pop_scale_matrix();
|
||||
|
||||
void gr_setup_viewport();
|
||||
|
||||
void gr_reset_matrices();
|
||||
|
||||
extern matrix4 gr_texture_matrix;
|
||||
|
||||
void gr_set_texture_panning(float u, float v, bool enable);
|
||||
@@ -193,7 +193,7 @@ void opengl::ShaderProgram::linkProgram() {
|
||||
freeCompiledShaders();
|
||||
}
|
||||
|
||||
void opengl::ShaderProgram::initAttribute(const SCP_string& name, const vec4& default_value)
|
||||
void opengl::ShaderProgram::initAttribute(const SCP_string& name, opengl_vert_attrib::attrib_id attr_id, const vec4& default_value)
|
||||
{
|
||||
auto attrib_loc = glGetAttribLocation(_program_id, name.c_str());
|
||||
|
||||
@@ -203,7 +203,7 @@ void opengl::ShaderProgram::initAttribute(const SCP_string& name, const vec4& de
|
||||
return;
|
||||
}
|
||||
|
||||
_attribute_locations.insert(std::make_pair(name, attrib_loc));
|
||||
_attribute_locations.insert(std::make_pair(attr_id, attrib_loc));
|
||||
|
||||
// The shader needs to be in use before glVertexAttrib can be used
|
||||
use();
|
||||
@@ -215,8 +215,8 @@ void opengl::ShaderProgram::initAttribute(const SCP_string& name, const vec4& de
|
||||
default_value.xyzw.w
|
||||
);
|
||||
}
|
||||
GLint opengl::ShaderProgram::getAttributeLocation(const SCP_string& name) {
|
||||
auto iter = _attribute_locations.find(name);
|
||||
GLint opengl::ShaderProgram::getAttributeLocation(opengl_vert_attrib::attrib_id attribute) {
|
||||
auto iter = _attribute_locations.find(attribute);
|
||||
if (iter == _attribute_locations.end()) {
|
||||
return -1;
|
||||
} else {
|
||||
@@ -228,20 +228,6 @@ opengl::ShaderUniforms::ShaderUniforms(ShaderProgram* shaderProgram) : _program(
|
||||
Assertion(shaderProgram != nullptr, "Shader program may not be null!");
|
||||
}
|
||||
|
||||
void opengl::ShaderUniforms::initUniform(const SCP_string& name)
|
||||
{
|
||||
auto location = glGetUniformLocation(_program->getShaderHandle(), name.c_str());
|
||||
|
||||
if (location == -1)
|
||||
{
|
||||
// This can happen if the uniform has been optimized out by the driver
|
||||
mprintf(("WARNING: Failed to find uniform '%s'.\n", name.c_str()));
|
||||
return;
|
||||
}
|
||||
|
||||
_uniform_locations.insert(std::make_pair(name, location));
|
||||
}
|
||||
|
||||
size_t opengl::ShaderUniforms::findUniform(const SCP_string& name)
|
||||
{
|
||||
auto iter = _uniform_lookup.find(name);
|
||||
@@ -814,7 +800,17 @@ GLint opengl::ShaderUniforms::findUniformLocation(const SCP_string& name) {
|
||||
auto iter = _uniform_locations.find(name);
|
||||
|
||||
if (iter == _uniform_locations.end()) {
|
||||
return -1;
|
||||
// Lazily initialize the uniform locations when required. This avoids keeping a list of all uniforms in the code
|
||||
auto location = glGetUniformLocation(_program->getShaderHandle(), name.c_str());
|
||||
|
||||
if (location == -1)
|
||||
{
|
||||
// This can happen if the uniform has been optimized out by the driver
|
||||
mprintf(("WARNING: Failed to find uniform '%s'.\n", name.c_str()));
|
||||
}
|
||||
|
||||
_uniform_locations.insert(std::make_pair(name, location));
|
||||
return location;
|
||||
}
|
||||
else {
|
||||
return iter->second;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "gropenglshader.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
@@ -51,8 +52,6 @@ class ShaderUniforms {
|
||||
public:
|
||||
explicit ShaderUniforms(ShaderProgram* shaderProgram);
|
||||
|
||||
void initUniform(const SCP_string& name);
|
||||
|
||||
void setUniformi(const SCP_string &name, const int value);
|
||||
void setUniform1iv(const SCP_string &name, const int count, const int *val);
|
||||
void setUniformf(const SCP_string &name, const float value);
|
||||
@@ -80,7 +79,7 @@ class ShaderProgram {
|
||||
|
||||
SCP_vector<GLuint> _compiled_shaders;
|
||||
|
||||
SCP_unordered_map<SCP_string, GLint> _attribute_locations;
|
||||
SCP_unordered_map<opengl_vert_attrib::attrib_id, GLint> _attribute_locations;
|
||||
|
||||
void freeCompiledShaders();
|
||||
public:
|
||||
@@ -101,9 +100,9 @@ class ShaderProgram {
|
||||
|
||||
void linkProgram();
|
||||
|
||||
void initAttribute(const SCP_string& name, const vec4& default_value);
|
||||
void initAttribute(const SCP_string& name, opengl_vert_attrib::attrib_id attr_id, const vec4& default_value);
|
||||
|
||||
GLint getAttributeLocation(const SCP_string& name);
|
||||
GLint getAttributeLocation(opengl_vert_attrib::attrib_id attribute);
|
||||
|
||||
GLuint getShaderHandle();
|
||||
};
|
||||
|
||||
@@ -10,17 +10,19 @@
|
||||
#include "debugconsole/console.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/matrix.h"
|
||||
#include "graphics/paths/PathRenderer.h"
|
||||
#include "gropengl.h"
|
||||
#include "gropenglbmpman.h"
|
||||
#include "gropengldraw.h"
|
||||
#include "gropengllight.h"
|
||||
#include "gropenglpostprocessing.h"
|
||||
#include "gropenglquery.h"
|
||||
#include "gropenglsync.h"
|
||||
#include "gropenglshader.h"
|
||||
#include "gropenglstate.h"
|
||||
#include "gropengltexture.h"
|
||||
#include "gropengltnl.h"
|
||||
#include "gropengldeferred.h"
|
||||
#include "graphics/line.h"
|
||||
#include "io/mouse.h"
|
||||
#include "io/timer.h"
|
||||
@@ -32,6 +34,7 @@
|
||||
#include "render/3d.h"
|
||||
#include "popup/popup.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "pngutils/pngutils.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
@@ -62,8 +65,6 @@ static ushort *GL_original_gamma_ramp = NULL;
|
||||
|
||||
int Use_PBOs = 0;
|
||||
|
||||
float GL_line_width = 1.0f;
|
||||
|
||||
static ubyte *GL_saved_screen = NULL;
|
||||
static int GL_saved_screen_id = -1;
|
||||
static GLuint GL_screen_pbo = 0;
|
||||
@@ -71,6 +72,7 @@ static GLuint GL_screen_pbo = 0;
|
||||
float GL_alpha_threshold = 0.0f;
|
||||
|
||||
extern const char *Osreg_title;
|
||||
extern SCP_string Window_title;
|
||||
|
||||
extern GLfloat GL_anisotropy;
|
||||
|
||||
@@ -149,6 +151,9 @@ void gr_opengl_clear()
|
||||
blue = pow(blue, SRGB_GAMMA);
|
||||
}
|
||||
|
||||
// Make sure that all channels are enabled before doing this.
|
||||
GL_state.ColorMask(true, true, true, true);
|
||||
|
||||
glClearColor(red, green, blue, alpha);
|
||||
|
||||
glClear ( GL_COLOR_BUFFER_BIT );
|
||||
@@ -171,7 +176,6 @@ void gr_opengl_flip()
|
||||
current_viewport->swapBuffers();
|
||||
|
||||
opengl_tcache_frame();
|
||||
opengl_reset_immediate_buffer();
|
||||
|
||||
#ifndef NDEBUG
|
||||
int ic = opengl_check_for_errors();
|
||||
@@ -296,23 +300,14 @@ void gr_opengl_reset_clip()
|
||||
void gr_opengl_print_screen(const char *filename)
|
||||
{
|
||||
char tmp[MAX_PATH_LEN];
|
||||
ubyte tga_hdr[18];
|
||||
int i;
|
||||
ushort width, height;
|
||||
GLubyte *pixels = NULL;
|
||||
GLuint pbo = 0;
|
||||
|
||||
// save to a "screenshots" directory and tack on the filename
|
||||
snprintf(tmp, MAX_PATH_LEN-1, "screenshots/%s.tga", filename);
|
||||
|
||||
snprintf(tmp, MAX_PATH_LEN-1, "screenshots/%s.png", filename);
|
||||
|
||||
_mkdir(os_get_config_path("screenshots").c_str());
|
||||
|
||||
FILE *fout = fopen(os_get_config_path(tmp).c_str(), "wb");
|
||||
|
||||
if (fout == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// glReadBuffer(GL_FRONT);
|
||||
|
||||
// now for the data
|
||||
@@ -321,9 +316,6 @@ void gr_opengl_print_screen(const char *filename)
|
||||
glGenBuffers(1, &pbo);
|
||||
|
||||
if ( !pbo ) {
|
||||
if (fout != NULL)
|
||||
fclose(fout);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -331,7 +323,7 @@ void gr_opengl_print_screen(const char *filename)
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, (gr_screen.max_w * gr_screen.max_h * 4), NULL, GL_STATIC_READ);
|
||||
|
||||
glReadBuffer(GL_FRONT);
|
||||
glReadPixels(0, 0, gr_screen.max_w, gr_screen.max_h, GL_read_format, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
||||
glReadPixels(0, 0, gr_screen.max_w, gr_screen.max_h, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
||||
|
||||
// map the image data so that we can save it to file
|
||||
pixels = (GLubyte*) glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
|
||||
@@ -339,44 +331,17 @@ void gr_opengl_print_screen(const char *filename)
|
||||
pixels = (GLubyte*) vm_malloc(gr_screen.max_w * gr_screen.max_h * 4, memory::quiet_alloc);
|
||||
|
||||
if (pixels == NULL) {
|
||||
if (fout != NULL) {
|
||||
fclose(fout);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
glReadPixels(0, 0, gr_screen.max_w, gr_screen.max_h, GL_read_format, GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
|
||||
glReadPixels(0, 0, gr_screen.max_w, gr_screen.max_h, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
|
||||
glFlush();
|
||||
}
|
||||
|
||||
// Write the TGA header
|
||||
width = INTEL_SHORT((ushort)gr_screen.max_w);
|
||||
height = INTEL_SHORT((ushort)gr_screen.max_h);
|
||||
|
||||
memset( tga_hdr, 0, sizeof(tga_hdr) );
|
||||
|
||||
tga_hdr[2] = 2; // ImageType 2 = 24bpp, uncompressed
|
||||
memcpy( tga_hdr + 12, &width, sizeof(ushort) ); // Width
|
||||
memcpy( tga_hdr + 14, &height, sizeof(ushort) ); // Height
|
||||
tga_hdr[16] = 24; // PixelDepth
|
||||
|
||||
fwrite( tga_hdr, sizeof(tga_hdr), 1, fout );
|
||||
|
||||
// now for the data, we convert it from 32-bit to 24-bit
|
||||
for (i = 0; i < (gr_screen.max_w * gr_screen.max_h * 4); i += 4) {
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
int pix, *pix_tmp;
|
||||
|
||||
pix_tmp = (int*)(pixels + i);
|
||||
pix = INTEL_INT(*pix_tmp);
|
||||
|
||||
fwrite( &pix, 1, 3, fout );
|
||||
#else
|
||||
fwrite( pixels + i, 1, 3, fout );
|
||||
#endif
|
||||
if (!png_write_bitmap(os_get_config_path(tmp).c_str(), gr_screen.max_w, gr_screen.max_h, true, pixels)) {
|
||||
ReleaseWarning(LOCATION, "Failed to write screenshot to \"%s\".", os_get_config_path(tmp).c_str());
|
||||
}
|
||||
|
||||
|
||||
if (pbo) {
|
||||
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
||||
pixels = NULL;
|
||||
@@ -384,9 +349,6 @@ void gr_opengl_print_screen(const char *filename)
|
||||
glDeleteBuffers(1, &pbo);
|
||||
}
|
||||
|
||||
// done!
|
||||
fclose(fout);
|
||||
|
||||
if (pixels != NULL) {
|
||||
vm_free(pixels);
|
||||
}
|
||||
@@ -394,10 +356,7 @@ void gr_opengl_print_screen(const char *filename)
|
||||
|
||||
void gr_opengl_shutdown()
|
||||
{
|
||||
graphics::paths::PathRenderer::shutdown();
|
||||
|
||||
opengl_tcache_shutdown();
|
||||
opengl_light_shutdown();
|
||||
opengl_tnl_shutdown();
|
||||
opengl_scene_texture_shutdown();
|
||||
opengl_post_process_shutdown();
|
||||
@@ -407,7 +366,7 @@ void gr_opengl_shutdown()
|
||||
|
||||
glDeleteVertexArrays(1, &GL_vao);
|
||||
GL_vao = 0;
|
||||
|
||||
|
||||
if (GL_original_gamma_ramp != NULL && os::getSDLMainWindow() != nullptr) {
|
||||
SDL_SetWindowGammaRamp( os::getSDLMainWindow(), GL_original_gamma_ramp, (GL_original_gamma_ramp+256), (GL_original_gamma_ramp+512) );
|
||||
}
|
||||
@@ -485,17 +444,18 @@ void gr_opengl_set_clear_color(int r, int g, int b)
|
||||
|
||||
int gr_opengl_set_color_buffer(int mode)
|
||||
{
|
||||
GLboolean enabled = GL_FALSE;
|
||||
bvec4 enabled;
|
||||
|
||||
if ( mode ) {
|
||||
enabled = GL_state.ColorMask(GL_TRUE);
|
||||
enabled = GL_state.ColorMask(true, true, true, true);
|
||||
} else {
|
||||
enabled = GL_state.ColorMask(GL_FALSE);
|
||||
enabled = GL_state.ColorMask(false, false, false, false);
|
||||
}
|
||||
|
||||
GL_state.SetAlphaBlendMode(ALPHA_BLEND_ALPHA_BLEND_ALPHA);
|
||||
|
||||
return (enabled) ? 1 : 0;
|
||||
// Check if all channels are active
|
||||
return enabled.x && enabled.y && enabled.z && enabled.w;
|
||||
}
|
||||
|
||||
int gr_opengl_zbuffer_get()
|
||||
@@ -555,13 +515,16 @@ int gr_opengl_stencil_set(int mode)
|
||||
|
||||
if ( mode == GR_STENCIL_READ ) {
|
||||
GL_state.StencilTest(1);
|
||||
GL_state.SetStencilType(STENCIL_TYPE_READ);
|
||||
GL_state.StencilFunc(GL_NEVER, 1, 0xFFFF);
|
||||
GL_state.StencilOpSeparate(GL_FRONT_AND_BACK, GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
} else if ( mode == GR_STENCIL_WRITE ) {
|
||||
GL_state.StencilTest(1);
|
||||
GL_state.SetStencilType(STENCIL_TYPE_WRITE);
|
||||
GL_state.StencilFunc(GL_NOTEQUAL, 1, 0XFFFF);
|
||||
GL_state.StencilOpSeparate(GL_FRONT_AND_BACK, GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
} else {
|
||||
GL_state.StencilTest(0);
|
||||
GL_state.SetStencilType(STENCIL_TYPE_NONE);
|
||||
GL_state.StencilFunc(GL_ALWAYS, 1, 0xFFFF);
|
||||
GL_state.StencilOpSeparate(GL_FRONT_AND_BACK, GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
@@ -875,7 +838,7 @@ void gr_opengl_set_line_width(float width)
|
||||
if (width <= 1.0f) {
|
||||
GL_state.SetLineWidth(width);
|
||||
}
|
||||
GL_line_width = width;
|
||||
gr_screen.line_width = width;
|
||||
}
|
||||
|
||||
int opengl_check_for_errors(const char *err_at)
|
||||
@@ -912,20 +875,6 @@ void opengl_set_vsync(int status)
|
||||
GL_CHECK_FOR_ERRORS("end of set_vsync()");
|
||||
}
|
||||
|
||||
void opengl_setup_viewport()
|
||||
{
|
||||
glViewport(0, 0, gr_screen.max_w, gr_screen.max_h);
|
||||
|
||||
GL_last_projection_matrix = GL_projection_matrix;
|
||||
|
||||
// the top and bottom positions are reversed on purpose, but RTT needs them the other way
|
||||
if (GL_rendering_to_texture) {
|
||||
opengl_create_orthographic_projection_matrix(&GL_projection_matrix, 0, i2fl(gr_screen.max_w), 0, i2fl(gr_screen.max_h), -1.0, 1.0);
|
||||
} else {
|
||||
opengl_create_orthographic_projection_matrix(&GL_projection_matrix, 0, i2fl(gr_screen.max_w), i2fl(gr_screen.max_h), 0, -1.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<os::Viewport> gr_opengl_create_viewport(const os::ViewPortProperties& props) {
|
||||
os::ViewPortProperties attrs = props;
|
||||
attrs.pixel_format.red_size = Gr_red.bits;
|
||||
@@ -1077,6 +1026,9 @@ int opengl_init_display_device()
|
||||
attrs.height = (uint32_t) gr_screen.max_h;
|
||||
|
||||
attrs.title = Osreg_title;
|
||||
if (!Window_title.empty()) {
|
||||
attrs.title = Window_title;
|
||||
}
|
||||
|
||||
if (!Cmdline_window && ! Cmdline_fullscreen_window) {
|
||||
attrs.flags.set(os::ViewPortFlags::Fullscreen);
|
||||
@@ -1089,7 +1041,7 @@ int opengl_init_display_device()
|
||||
return 1;
|
||||
}
|
||||
|
||||
const int gl_versions[] = { 41, 40, 33, 32, 31, 30, 21, 20 };
|
||||
const int gl_versions[] = { 45, 44, 43, 42, 41, 40, 33, 32 };
|
||||
|
||||
// find the latest and greatest OpenGL context
|
||||
for (auto ver : gl_versions)
|
||||
@@ -1133,29 +1085,11 @@ void opengl_setup_function_pointers()
|
||||
|
||||
gr_screen.gf_clear = gr_opengl_clear;
|
||||
// gr_screen.gf_bitmap = gr_opengl_bitmap;
|
||||
gr_screen.gf_bitmap_ex = gr_opengl_bitmap_ex;
|
||||
gr_screen.gf_aabitmap = gr_opengl_aabitmap;
|
||||
gr_screen.gf_aabitmap_ex = gr_opengl_aabitmap_ex;
|
||||
|
||||
// gr_screen.gf_rect = gr_opengl_rect;
|
||||
// gr_screen.gf_shade = gr_opengl_shade;
|
||||
gr_screen.gf_string = gr_opengl_string;
|
||||
gr_screen.gf_circle = gr_opengl_circle;
|
||||
gr_screen.gf_unfilled_circle = gr_opengl_unfilled_circle;
|
||||
gr_screen.gf_arc = gr_opengl_arc;
|
||||
gr_screen.gf_curve = gr_opengl_curve;
|
||||
|
||||
gr_screen.gf_line = gr_opengl_line;
|
||||
gr_screen.gf_aaline = gr_opengl_aaline;
|
||||
gr_screen.gf_pixel = gr_opengl_pixel;
|
||||
|
||||
gr_screen.gf_gradient = gr_opengl_gradient;
|
||||
|
||||
gr_screen.gf_print_screen = gr_opengl_print_screen;
|
||||
|
||||
gr_screen.gf_flash = gr_opengl_flash;
|
||||
gr_screen.gf_flash_alpha = gr_opengl_flash_alpha;
|
||||
|
||||
gr_screen.gf_zbuffer_get = gr_opengl_zbuffer_get;
|
||||
gr_screen.gf_zbuffer_set = gr_opengl_zbuffer_set;
|
||||
gr_screen.gf_zbuffer_clear = gr_opengl_zbuffer_clear;
|
||||
@@ -1199,23 +1133,14 @@ void opengl_setup_function_pointers()
|
||||
gr_screen.gf_set_texture_addressing = gr_opengl_set_texture_addressing;
|
||||
gr_screen.gf_zbias = gr_opengl_zbias;
|
||||
gr_screen.gf_set_fill_mode = gr_opengl_set_fill_mode;
|
||||
gr_screen.gf_set_texture_panning = gr_opengl_set_texture_panning;
|
||||
|
||||
gr_screen.gf_create_vertex_buffer = gr_opengl_create_vertex_buffer;
|
||||
gr_screen.gf_create_index_buffer = gr_opengl_create_index_buffer;
|
||||
gr_screen.gf_create_buffer = gr_opengl_create_buffer;
|
||||
gr_screen.gf_delete_buffer = gr_opengl_delete_buffer;
|
||||
gr_screen.gf_update_buffer_data = gr_opengl_update_buffer_data;
|
||||
gr_screen.gf_update_buffer_data_offset = gr_opengl_update_buffer_data_offset;
|
||||
gr_screen.gf_bind_uniform_buffer = gr_opengl_bind_uniform_buffer;
|
||||
|
||||
gr_screen.gf_update_transform_buffer = gr_opengl_update_transform_buffer;
|
||||
gr_screen.gf_set_transform_buffer_offset = gr_opengl_set_transform_buffer_offset;
|
||||
|
||||
gr_screen.gf_start_instance_matrix = gr_opengl_start_instance_matrix;
|
||||
gr_screen.gf_end_instance_matrix = gr_opengl_end_instance_matrix;
|
||||
gr_screen.gf_start_angles_instance_matrix = gr_opengl_start_instance_angles;
|
||||
|
||||
gr_screen.gf_set_light = gr_opengl_set_light;
|
||||
gr_screen.gf_reset_lighting = gr_opengl_reset_lighting;
|
||||
gr_screen.gf_set_ambient_light = gr_opengl_set_ambient_light;
|
||||
|
||||
gr_screen.gf_post_process_set_effect = gr_opengl_post_process_set_effect;
|
||||
gr_screen.gf_post_process_set_defaults = gr_opengl_post_process_set_defaults;
|
||||
@@ -1233,24 +1158,10 @@ void opengl_setup_function_pointers()
|
||||
gr_screen.gf_deferred_lighting_end = gr_opengl_deferred_lighting_end;
|
||||
gr_screen.gf_deferred_lighting_finish = gr_opengl_deferred_lighting_finish;
|
||||
|
||||
gr_screen.gf_start_clip_plane = gr_opengl_start_clip_plane;
|
||||
gr_screen.gf_end_clip_plane = gr_opengl_end_clip_plane;
|
||||
|
||||
gr_screen.gf_lighting = gr_opengl_set_lighting;
|
||||
|
||||
gr_screen.gf_set_proj_matrix = gr_opengl_set_projection_matrix;
|
||||
gr_screen.gf_end_proj_matrix = gr_opengl_end_projection_matrix;
|
||||
|
||||
gr_screen.gf_set_view_matrix = gr_opengl_set_view_matrix;
|
||||
gr_screen.gf_end_view_matrix = gr_opengl_end_view_matrix;
|
||||
|
||||
gr_screen.gf_push_scale_matrix = gr_opengl_push_scale_matrix;
|
||||
gr_screen.gf_pop_scale_matrix = gr_opengl_pop_scale_matrix;
|
||||
|
||||
gr_screen.gf_set_line_width = gr_opengl_set_line_width;
|
||||
|
||||
gr_screen.gf_sphere = gr_opengl_sphere;
|
||||
|
||||
|
||||
gr_screen.gf_maybe_create_shader = gr_opengl_maybe_create_shader;
|
||||
gr_screen.gf_shadow_map_start = gr_opengl_shadow_map_start;
|
||||
gr_screen.gf_shadow_map_end = gr_opengl_shadow_map_end;
|
||||
@@ -1264,13 +1175,14 @@ void opengl_setup_function_pointers()
|
||||
|
||||
gr_screen.gf_render_model = gr_opengl_render_model;
|
||||
gr_screen.gf_render_primitives= gr_opengl_render_primitives;
|
||||
gr_screen.gf_render_primitives_immediate = gr_opengl_render_primitives_immediate;
|
||||
gr_screen.gf_render_primitives_2d = gr_opengl_render_primitives_2d;
|
||||
gr_screen.gf_render_primitives_2d_immediate = gr_opengl_render_primitives_2d_immediate;
|
||||
gr_screen.gf_render_primitives_particle = gr_opengl_render_primitives_particle;
|
||||
gr_screen.gf_render_primitives_batched = gr_opengl_render_primitives_batched;
|
||||
gr_screen.gf_render_primitives_distortion = gr_opengl_render_primitives_distortion;
|
||||
gr_screen.gf_render_movie = gr_opengl_render_movie;
|
||||
gr_screen.gf_render_nanovg = gr_opengl_render_nanovg;
|
||||
|
||||
gr_screen.gf_is_capable = gr_opengl_is_capable;
|
||||
gr_screen.gf_get_property = gr_opengl_get_property;
|
||||
|
||||
gr_screen.gf_push_debug_group = gr_opengl_push_debug_group;
|
||||
gr_screen.gf_pop_debug_group = gr_opengl_pop_debug_group;
|
||||
@@ -1284,6 +1196,12 @@ void opengl_setup_function_pointers()
|
||||
gr_screen.gf_create_viewport = gr_opengl_create_viewport;
|
||||
gr_screen.gf_use_viewport = gr_opengl_use_viewport;
|
||||
|
||||
gr_screen.gf_sync_fence = gr_opengl_sync_fence;
|
||||
gr_screen.gf_sync_wait = gr_opengl_sync_wait;
|
||||
gr_screen.gf_sync_delete = gr_opengl_sync_delete;
|
||||
|
||||
gr_screen.gf_set_viewport = gr_opengl_set_viewport;
|
||||
|
||||
// NOTE: All function pointers here should have a Cmdline_nohtl check at the top
|
||||
// if they shouldn't be run in non-HTL mode, Don't keep separate entries.
|
||||
// *****************************************************************************
|
||||
@@ -1421,11 +1339,11 @@ static void init_extensions() {
|
||||
Texture_compression_available = true;
|
||||
// Swifty put this in, but it's not doing anything. Once he uses it, he can uncomment it.
|
||||
//int use_base_vertex = Is_Extension_Enabled(OGL_ARB_DRAW_ELEMENTS_BASE_VERTEX);
|
||||
|
||||
|
||||
if ( !Cmdline_no_pbo ) {
|
||||
Use_PBOs = 1;
|
||||
}
|
||||
|
||||
|
||||
int ver = 0, major = 0, minor = 0;
|
||||
const char *glsl_ver = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
|
||||
|
||||
@@ -1532,9 +1450,6 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
|
||||
|
||||
init_extensions();
|
||||
|
||||
// setup the lighting stuff that will get used later
|
||||
opengl_light_init();
|
||||
|
||||
// init state system (must come AFTER light is set up)
|
||||
GL_state.init();
|
||||
|
||||
@@ -1546,10 +1461,11 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
|
||||
|
||||
// create vertex array object to make OpenGL Core happy
|
||||
glGenVertexArrays(1, &GL_vao);
|
||||
glBindVertexArray(GL_vao);
|
||||
GL_state.BindVertexArray(GL_vao);
|
||||
|
||||
GL_state.Texture.init(max_texture_units);
|
||||
GL_state.Array.init(max_texture_coords);
|
||||
GL_state.Constants.init();
|
||||
|
||||
opengl_set_texture_target();
|
||||
GL_state.Texture.SetActiveUnit(0);
|
||||
@@ -1571,9 +1487,8 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
|
||||
// must be called after extensions are setup
|
||||
opengl_set_vsync( !Cmdline_no_vsync );
|
||||
|
||||
opengl_setup_viewport();
|
||||
vm_matrix4_set_identity(&GL_view_matrix);
|
||||
vm_matrix4_set_identity(&GL_model_view_matrix);
|
||||
gr_reset_matrices();
|
||||
gr_setup_viewport();
|
||||
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
@@ -1618,7 +1533,11 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
|
||||
mprintf(( " Using %s texture filter.\n", (GL_mipmap_filter) ? NOX("trilinear") : NOX("bilinear") ));
|
||||
|
||||
mprintf(( " OpenGL Shader Version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION) ));
|
||||
|
||||
|
||||
mprintf((" Max uniform block size: %d\n", GL_state.Constants.GetMaxUniformBlockSize()));
|
||||
mprintf((" Max uniform buffer bindings: %d\n", GL_state.Constants.GetMaxUniformBlockBindings()));
|
||||
mprintf((" Uniform buffer byte offset alignment: %d\n", GL_state.Constants.GetUniformBufferOffsetAlignment()));
|
||||
|
||||
// This stops fred crashing if no textures are set
|
||||
gr_screen.current_bitmap = -1;
|
||||
|
||||
@@ -1653,12 +1572,22 @@ bool gr_opengl_is_capable(gr_capability capability)
|
||||
case CAPABILITY_POINT_PARTICLES:
|
||||
return !Cmdline_no_geo_sdr_effects;
|
||||
case CAPABILITY_TIMESTAMP_QUERY:
|
||||
return GL_version >= 33; // Timestamp queries are available from 3.3 onwards
|
||||
return GLAD_GL_ARB_timer_query != 0; // Timestamp queries are available from 3.3 onwards
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gr_opengl_get_property(gr_property prop, void* dest) {
|
||||
switch(prop) {
|
||||
case gr_property::UNIFORM_BUFFER_OFFSET_ALIGNMENT:
|
||||
*((int*)dest) = GL_state.Constants.GetUniformBufferOffsetAlignment();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void gr_opengl_push_debug_group(const char* name) {
|
||||
if (GLAD_GL_KHR_debug) {
|
||||
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION_KHR, 0, -1, name);
|
||||
|
||||
@@ -22,6 +22,7 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps);
|
||||
void gr_opengl_cleanup(bool closing, int minimize=1);
|
||||
int opengl_check_for_errors(const char *err_at = NULL);
|
||||
bool gr_opengl_is_capable(gr_capability capability);
|
||||
bool gr_opengl_get_property(gr_property prop, void* dest);
|
||||
void gr_opengl_push_debug_group(const char* name);
|
||||
void gr_opengl_pop_debug_group();
|
||||
|
||||
@@ -56,6 +57,5 @@ extern int Use_PBOs;
|
||||
extern GLuint GL_vao;
|
||||
|
||||
extern float GL_alpha_threshold;
|
||||
extern float GL_line_width;
|
||||
|
||||
#endif
|
||||
@@ -55,11 +55,8 @@ void gr_opengl_bm_free_data(int n, bool release)
|
||||
{
|
||||
Assert( (n >= 0) && (n < MAX_BITMAPS) );
|
||||
|
||||
// might as well free up the on card texture data too in order to get rid
|
||||
// of old interface stuff but don't free USER types, unless it's a total release,
|
||||
// since we can reuse ANI slots for faster and less resource intensive rendering
|
||||
if ( release || (bm_bitmaps[n].type != BM_TYPE_USER) )
|
||||
opengl_free_texture_slot( n );
|
||||
if ( release )
|
||||
opengl_free_texture_slot( n );
|
||||
|
||||
if ( (bm_bitmaps[n].type == BM_TYPE_RENDER_TARGET_STATIC) || (bm_bitmaps[n].type == BM_TYPE_RENDER_TARGET_DYNAMIC) )
|
||||
opengl_kill_render_target( n );
|
||||
@@ -112,9 +109,7 @@ void gr_opengl_bm_save_render_target(int n)
|
||||
return;
|
||||
}
|
||||
|
||||
if (Cmdline_save_render_targets) {
|
||||
dds_save_image(bmp->w, bmp->h, bmp->true_bpp, be->num_mipmaps, (ubyte*)bmp->data, (bmp->flags & BMP_FLAG_CUBEMAP));
|
||||
}
|
||||
dds_save_image(bmp->w, bmp->h, bmp->true_bpp, be->num_mipmaps, (ubyte*)bmp->data, (bmp->flags & BMP_FLAG_CUBEMAP));
|
||||
}
|
||||
|
||||
int gr_opengl_bm_make_render_target(int n, int *width, int *height, int *bpp, int *mm_lvl, int flags)
|
||||
|
||||
Loaded 100 of 384 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user