diff --git a/.travis.yml b/.travis.yml index a6bd4732b..b7f46447e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,13 +14,13 @@ before_install: # Update repos - sudo apt-get update -qq # Install dependencies - - sudo apt-get install build-essential cmake libogg-dev libvorbis-dev libopenal-dev libxxf86vm-dev libcurl4-openssl-dev libfribidi-dev libbluetooth-dev + - sudo apt-get install build-essential libogg-dev libvorbis-dev libopenal-dev libxxf86vm-dev libcurl4-openssl-dev libfribidi-dev libbluetooth-dev # Install mesa from an other repo (a newer version is required). Quantal is not supported anymore, saucy is only supported till July 2014, # so we try to use trusty (precise which is what traiv uses a too old mesa version which doesn't link) - sudo apt-add-repository "deb http://archive.ubuntu.com/ubuntu trusty main restricted" - sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 3B4FE6ACC0B21F32 - sudo apt-get update -qq - - sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev + - sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev libglew-dev cmake script: # First a debug build: - mkdir build-debug diff --git a/CMakeLists.txt b/CMakeLists.txt index e7a47d353..f44e15003 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,12 +15,12 @@ option(USE_WIIUSE "Support for wiimote input devices" ON) option(USE_FRIBIDI "Support for right-to-left languages" ON) option(CHECK_ASSETS "Check if assets are installed in ../stk-assets" ON) -if(UNIX) +if(UNIX OR MINGW) option(USE_CPP2011 "Activate C++ 2011 mode (GCC only)" OFF) endif() -if(MSVC) +if(MSVC OR MINGW) # Normally hide the option to build wiiuse on VS, since it depends - # on the installation of the Windows DDK (Driver Developer Kit), + # on the installation of the Windows DDK (Driver Developer Kit), # which also needs an absolute path :( option(WIIUSE_BUILD "Build wiiuse lib (only for developers)" OFF) mark_as_advanced(WIIUSE_BUILD) @@ -28,6 +28,10 @@ else() set(WIIUSE_BUILD ON) endif() +if(MINGW) + set(USE_WIIUSE OFF) +endif() + if(UNIX AND NOT APPLE) option(USE_XRANDR "Use xrandr instead of vidmode" ON) option(USE_ASAN "Build with Leak/Address sanitizer" OFF) @@ -69,6 +73,7 @@ endif() # Build the angelscript library add_subdirectory("${PROJECT_SOURCE_DIR}/lib/angelscript/projects/cmake") include_directories("${PROJECT_SOURCE_DIR}/lib/angelscript/include") + # Set include paths include_directories(${STK_SOURCE_DIR}) @@ -80,6 +85,11 @@ if(MSVC) add_definitions(/D_IRR_STATIC_LIB_) endif() +if(MINGW) + set(ENV{OPENALDIR} ${PROJECT_SOURCE_DIR}/dependencies) + add_definitions(-D_IRR_STATIC_LIB_) +endif() + if(APPLE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch i386") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch i386 -F/Library/Frameworks") @@ -124,8 +134,15 @@ if(USE_FRIBIDI) endif() endif() +# OpenMP +find_package(OpenMP) +if (OPENMP_FOUND) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() -if(UNIX) + +if(UNIX OR MINGW) # if(USE_CPP2011) add_definitions("-std=gnu++0x") # endif() @@ -135,6 +152,10 @@ endif() find_package(OpenGL REQUIRED) include_directories(${OPENGL_INCLUDE_DIR}) +# Glew +find_package(GLEW REQUIRED) +include_directories(${GLEW_INCLUDE_DIR}) + if(UNIX AND NOT APPLE) if(USE_XRANDR) find_package(Xrandr REQUIRED) @@ -147,7 +168,7 @@ if(UNIX AND NOT APPLE) endif() endif() - + # Set some compiler options if(UNIX) add_definitions(-Wall) @@ -175,6 +196,9 @@ endif() # TODO: remove this switch add_definitions(-DHAVE_OGGVORBIS) +if(WIN32 AND NOT MINGW) + configure_file("${STK_SOURCE_DIR}/windows_installer/icon_rc.template" "${PROJECT_BINARY_DIR}/tmp/icon.rc") +endif() # Provides list of source and header files (STK_SOURCES and STK_HEADERS) include(sources.cmake) @@ -230,7 +254,7 @@ else() endif() # Build the final executable - add_executable(supertuxkart ${STK_SOURCES} ${STK_HEADERS}) + add_executable(supertuxkart ${STK_SOURCES} ${STK_RESOURCES} ${STK_HEADERS}) target_link_libraries(supertuxkart ${PTHREAD_LIBRARY}) endif() @@ -253,8 +277,9 @@ target_link_libraries(supertuxkart ${CURL_LIBRARIES} ${OGGVORBIS_LIBRARIES} ${OPENAL_LIBRARY} - ${OPENGL_LIBRARIES}) - + ${OPENGL_LIBRARIES} + ${GLEW_LIBRARIES}) + if(UNIX AND NOT APPLE) if(USE_XRANDR) target_link_libraries(supertuxkart ${XRANDR_LIBRARIES}) @@ -288,8 +313,12 @@ if(USE_WIIUSE) if(APPLE) find_library(BLUETOOTH_LIBRARY NAMES IOBluetooth PATHS /Developer/Library/Frameworks/IOBluetooth.framework) target_link_libraries(supertuxkart wiiuse ${BLUETOOTH_LIBRARY}) - elseif(MSVC) - add_definitions("/DWIIUSE_STATIC") + elseif(WIN32) + if(MSVC) + add_definitions("/DWIIUSE_STATIC") + else() + add_definitions("-DWIIUSE_STATIC") + endif() if(WIIUSE_BUILD) target_link_libraries(supertuxkart wiiuse) else() @@ -302,12 +331,12 @@ if(USE_WIIUSE) endif() -if(MSVC) +if(MSVC OR MINGW) target_link_libraries(supertuxkart iphlpapi.lib) add_custom_command(TARGET supertuxkart POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${PROJECT_SOURCE_DIR}/dependencies/dll" - $<TARGET_FILE_DIR:supertuxkart>) + $<TARGET_FILE_DIR:supertuxkart>) add_custom_target(stkshaders SOURCES ${STK_SHADERS}) endif() @@ -316,7 +345,7 @@ add_subdirectory(tools/font_tool) # ==== Make dist target ==== -if(MSVC) +if(MSVC OR MINGW) # Don't create a dist target for VS else() add_custom_target(dist @@ -340,9 +369,9 @@ endif() # ==== Checking if stk-assets folder exists ==== if(CHECK_ASSETS) - if((IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/karts) AND - (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/library) AND - (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/music) AND + if((IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/karts) AND + (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/library) AND + (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/music) AND (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/sfx) AND (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/textures) AND (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/tracks)) @@ -368,11 +397,8 @@ install(DIRECTORY ${STK_DATA_DIR} DESTINATION ${STK_INSTALL_DATA_DIR} PATTERN ". if(STK_ASSETS_DIR AND CHECK_ASSETS) install(DIRECTORY ${STK_ASSETS_DIR} DESTINATION ${STK_INSTALL_DATA_DIR}/data PATTERN ".svn" EXCLUDE PATTERN ".git" EXCLUDE) endif() -install(FILES ${PROJECT_BINARY_DIR}/supertuxkart.desktop DESTINATION share/applications) +install(FILES ${STK_DATA_DIR}/supertuxkart.desktop DESTINATION share/applications) +install(FILES data/supertuxkart_32.png DESTINATION share/icons/hicolor/32x32 RENAME supertuxkart.png) +install(FILES data/supertuxkart_128.png DESTINATION share/icons/hicolor/128x128 RENAME supertuxkart.png) install(FILES data/supertuxkart_32.png data/supertuxkart_128.png DESTINATION share/pixmaps) install(FILES data/supertuxkart.appdata DESTINATION share/appdata) - - -set(PREFIX ${CMAKE_INSTALL_PREFIX}) -configure_file(data/supertuxkart_desktop.template supertuxkart.desktop) -add_dependencies(supertuxkart supertuxkart.desktop) \ No newline at end of file diff --git a/INSTALL.md b/INSTALL.md index 9e1a4f976..47ce60feb 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -23,7 +23,7 @@ Ubuntu command: ``` sudo apt-get install autoconf automake build-essential cmake libogg-dev libvorbis-dev libopenal-dev libxxf86vm-dev \ -libgl1-mesa-dev libglu1-mesa-dev libcurl4-openssl-dev libfribidi-dev libbluetooth-dev +libgl1-mesa-dev libglu1-mesa-dev libcurl4-openssl-dev libfribidi-dev libbluetooth-dev libxrandr-dev ``` Unpack the files from the tarball like this: diff --git a/data/gui/gp_info.stkgui b/data/gui/gp_info.stkgui new file mode 100644 index 000000000..a1018587c --- /dev/null +++ b/data/gui/gp_info.stkgui @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<stkgui> + <icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/> + + <div x="2%" y="2%" width="96%" height="96%" layout="vertical-row"> + + <header id="name" height="5%" width="80%" align="center" text_align="center"/> + + <spacer width="1" height="5%"/> + + <box width="95%" height="40%" padding="10" layout="horizontal-row"> + <spacer width="10" height="100%"/> + <!-- Left pane --> + <div width="45%" height="95%" align="center" layout="vertical-row"> + <placeholder proportion="1" width="100%" height="100%" id="screenshot_div"> + </placeholder> + </div> + + <spacer width="5%" height="100%"/> + + <!-- Right pane --> + <div width="45%" height="95%" align="center" layout="vertical-row"> + <list id="tracks" width="100%" height="100%"/> + </div> + + </box> + <spacer width="1" height="5%"/> + <box width="95%" height="25%" padding="10" layout="horizontal-row"> + <spacer width="1" height="5%"/> + <div width="50%" height="100%" layout="vertical-row"> + + <div width="100%" height="20%" layout="horizontal-row" > + <label id="ai-text" height="100%" width="50%" I18N="Number of AI karts" text="AI karts"/> + <spinner id="ai-spinner" width="50%" min_value="1" max_value="20" align="center" + wrap_around="true" /> + </div> + <spacer height="5%" /> + <div width="100%" height="20%" layout="horizontal-row" > + <label id="reverse-text" width="50%" height="100%" I18N="Drive the track reverse" text="Reverse"/> + <spinner id="reverse-spinner" width="50%" align="center" wrap_around="true" /> + </div> + <spacer height="5%" /> + <div width="100%" height="20%" layout="horizontal-row"> + <label id="track-text" width="50%" height="100%" text="Tracks" + I18N="Number of tracks to pick in a random Grand Prix."/> + <spinner id="track-spinner" width="50%" min_value="1" max_value="20" align="center" + wrap_around="true" /> + <spacer height="1%" /> + </div> + <spacer height="5%" /> + <div width="100%" height="20%" layout="horizontal-row" > + <label id="group-text" width="50%" height="100%" I18N="Number of AI karts" text="Track group"/> + <spinner id="group-spinner" width="50%" align="center" wrap_around="true" /> + <spacer proportion="1" height="2" /> + </div> + </div> + </box> + <spacer width="1" height="5%"/> + <buttonbar id="buttons" height="15%" width="100%" align="center"> + + <icon-button id="start" width="64" height="64" icon="gui/green_check.png" + I18N="Start race" text="Start Race"/> + + <icon-button id="continue" width="64" height="64" icon="gui/green_check.png" + I18N="Continue saved GP" text="Continue saved GP"/> + </buttonbar> + + </div> +</stkgui> diff --git a/data/gui/grand_prix_lose.stkgui b/data/gui/grand_prix_lose.stkgui index 743196dae..e08bb49f4 100644 --- a/data/gui/grand_prix_lose.stkgui +++ b/data/gui/grand_prix_lose.stkgui @@ -1,7 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <stkgui> - <div x="2%" y="2%" width="96%" height="96%" layout="vertical-row"> - <spacer width="10" proportion="1"/> - <button id="continue" x="20" width="250" align="left" text="Continue"/> + <div x="2%" y="2%" width="96%" height="96%" layout="horizontal-row"> + <button id="continue" width="250" align="bottom" text="Continue"/> + <spacer width="20"/> + <button id="save" width="250" align="bottom" text="Save Grand Prix"/> </div> </stkgui> diff --git a/data/gui/grand_prix_win.stkgui b/data/gui/grand_prix_win.stkgui index 743196dae..05d24c048 100644 --- a/data/gui/grand_prix_win.stkgui +++ b/data/gui/grand_prix_win.stkgui @@ -1,7 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> <stkgui> - <div x="2%" y="2%" width="96%" height="96%" layout="vertical-row"> - <spacer width="10" proportion="1"/> - <button id="continue" x="20" width="250" align="left" text="Continue"/> + <div x="2%" y="2%" width="96%" height="96%" layout="horizontal-row"> + <button id="continue" width="250" align="bottom" text="Continue"/> + <spacer width="20"/> + <button id="save" width="250" align="bottom" text="Save Grand Prix"/> </div> </stkgui> + diff --git a/data/gui/racesetup.stkgui b/data/gui/racesetup.stkgui index fe940123f..dd52aa0ea 100644 --- a/data/gui/racesetup.stkgui +++ b/data/gui/racesetup.stkgui @@ -1,41 +1,33 @@ <?xml version="1.0" encoding="UTF-8"?> <stkgui> - <div x="5%" y="5%" width="90%" height="90%" layout="vertical-row" > + <div x="2%" y="2%" width="96%" height="96%" layout="vertical-row" > - <header width="80%" text="Race Setup" align="center" text_align="center" /> + <header height="5%" width="80%" text="Race Setup" align="center" text_align="center" /> - <spacer proportion="1" width="25"/> + <spacer height="5%" width="25"/> + <box width="95%" height="40%" padding="10" layout="vertical-row"> + <bright width="100%" text="Select a difficulty" align="center" text_align="left" /> - <div layout="horizontal-row" width="100%" height="50" align="center"> - <bright proportion="1" height="100%" - I18N="In race setup menu" text="Number of AI karts" text_align="right" /> - <spacer width="50" height="25"/> - <!-- - <spinner id="aikartamount" proportion="3" height="100%" min_value="0" max_value="8" icon="gui/karts%i.png"/> --> - <!-- The maximum is set by stk from data/stk_config.xml. --> - <spinner id="aikartamount" proportion="1" height="100%" min_value="0" wrap_around="true"/> - </div> + <ribbon id="difficulty" height="135" width="100%" align="center"> + <icon-button id="novice" width="128" height="128" icon="gui/difficulty_easy.png" + I18N="Difficulty" text="Novice"/> + <icon-button id="intermediate" width="128" height="128" icon="gui/difficulty_medium.png" + I18N="Difficulty" text="Intermediate"/> + <icon-button id="expert" width="128" height="128" icon="gui/difficulty_hard.png" + I18N="Difficulty" text="Expert"/> + <icon-button id="best" width="128" height="128" icon="gui/difficulty_best.png" + I18N="Difficulty" text="SuperTux"/> + </ribbon> + </box> + <spacer height="5%"" width="25"/> - <spacer proportion="1" width="25"/> + <box width="95%" height="40%" padding="10" layout="vertical-row"> + <bright width="100%" text="Select a game mode" align="center" text_align="left" /> - <ribbon id="difficulty" height="135" width="65%" align="center"> - <icon-button id="novice" width="128" height="128" icon="gui/difficulty_easy.png" - I18N="Difficulty" text="Novice"/> - <icon-button id="intermediate" width="128" height="128" icon="gui/difficulty_medium.png" - I18N="Difficulty" text="Intermediate"/> - <icon-button id="expert" width="128" height="128" icon="gui/difficulty_hard.png" - I18N="Difficulty" text="Expert"/> - <icon-button id="best" width="128" height="128" icon="gui/difficulty_best.png" - I18N="Difficulty" text="SuperTux"/> - </ribbon> - - <spacer proportion="1" width="25"/> - - <bright width="100%" text="Select a game mode" align="center" text_align="left" /> - - <scrollable_toolbar id="gamemode" height="135" width="85%" label_location="bottom" align="center" - child_width="135" child_height="135" /> - <spacer proportion="1" width="25" /> + <scrollable_toolbar id="gamemode" height="135" width="85%" label_location="bottom" align="center" + child_width="135" child_height="135" /> + <spacer proportion="1" width="25" /> + </box> </div> <icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/> diff --git a/data/gui/track_info.stkgui b/data/gui/track_info.stkgui new file mode 100644 index 000000000..32ab2e52d --- /dev/null +++ b/data/gui/track_info.stkgui @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<stkgui> + <icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/> + + <div x="2%" y="2%" width="96%" height="96%" layout="vertical-row"> + + <header id="name" height="5%" width="80%" align="center" text_align="center"/> + + <spacer width="1" height="5%"/> + + <box width="95%" height="40%" padding="10" layout="horizontal-row"> + <!-- Left pane --> + <div proportion="1" height="100%" layout="vertical-row"> + <placeholder proportion="1" width="100%" height="100%" id="screenshot_div"> + </placeholder> + + </div> + <!-- Right pane --> + <div proportion="1" height="100%" layout="vertical-row"> + <label id="highscores" width="100%" text_align="center" text="= Highscores ="/> + + <spacer width="1" height="2%"/> + + <div width="95%" height="fit" layout="horizontal-row"> + <icon id="iconscore1" icon="gui/random_kart.png" width="font" height="font"/> + <spacer width="2%" height="1"/> + <label id="highscore1" proportion="1" text="(Empty)"/> + </div> + + <spacer width="1" height="2%"/> + + <div width="95%" height="fit" layout="horizontal-row"> + <icon id="iconscore2" icon="gui/random_kart.png" width="font" height="font"/> + <spacer width="2%" height="1"/> + <label id="highscore2" proportion="1" text="(Empty)"/> + </div> + + <spacer width="1" height="2%"/> + + <div width="95%" height="fit" layout="horizontal-row"> + <icon id="iconscore3" icon="gui/random_kart.png" width="font" height="font"/> + <spacer width="2%" height="1"/> + <label id="highscore3" proportion="1" text="(Empty)"/> + </div> + + <spacer width="1" height="10%"/> + + <label id="author" width="100%" text_align="center" word_wrap="true"/> + </div> + + </box> + <spacer width="1" height="5%"/> + <box width="95%" height="25%" padding="10" layout="vertical-row"> + <spacer width="1" height="5%"/> + + <div width="75%" height="fit" layout="horizontal-row" > + <spacer width="40" height="2" /> + <label id="lap-text" height="100%" width="40%" I18N="Number of laps" text="Number of laps"/> + <spacer witdh="40" height="2" /> + <spinner id="lap-spinner" width="20%" min_value="1" max_value="20" align="center" + wrap_around="true" /> + <spacer proportion="1" height="2" /> + </div> + <div width="75%" height="fit" layout="horizontal-row" > + <spacer width="40" height="2" /> + <label id="ai-text" height="100%" width="40%" I18N="Number of AI karts" text="Number of AI karts"/> + <spacer with="40" height="2" /> + <spinner id="ai-spinner" width="20%" min_value="1" max_value="20" align="center" + wrap_around="true" /> + <spacer proportion="1" height="2" /> + </div> + <div width="75%" height="fit" layout="horizontal-row" > + <spacer width="40" height="2" /> + <label id="reverse-text" height="100%" width="40%" I18N="Drive the track reverse" text="Drive in reverse"/> + <spacer width="40" height="2" /> + <checkbox id="reverse"/> + <spacer proportion="1" height="2" /> + </div> + <spacer width="1" height="2%"/> + </box> + <spacer width="1" height="5%"/> + <buttonbar id="buttons" height="15%" width="100%" align="center"> + + <icon-button id="start" width="64" height="64" icon="gui/green_check.png" + I18N="Start race" text="Start Race"/> + + </buttonbar>> + + </div> +</stkgui> diff --git a/data/gui/track_info_dialog.stkgui b/data/gui/track_info_dialog.stkgui deleted file mode 100644 index 1cd67f681..000000000 --- a/data/gui/track_info_dialog.stkgui +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<stkgui> - <div x="1%" y="1%" width="99%" height="99%"> - <div x="2%" y="2%" width="96%" height="96%" layout="vertical-row"> - <label id="name" width="100%" text_align="center"/> - - <spacer width="1" height="5%"/> - - <div width="95%" proportion="5" layout="horizontal-row"> - - <!-- Left pane --> - <div proportion="1" height="100%" layout="vertical-row"> - <label id="highscores" width="100%" text_align="center" text="= Highscores ="/> - - <spacer width="1" height="2%"/> - - <div width="95%" height="fit" layout="horizontal-row"> - <icon id="iconscore1" icon="gui/random_kart.png" width="font" height="font"/> - <spacer width="2%" height="1"/> - <label id="highscore1" proportion="1" text="(Empty)"/> - </div> - - <spacer width="1" height="2%"/> - - <div width="95%" height="fit" layout="horizontal-row"> - <icon id="iconscore2" icon="gui/random_kart.png" width="font" height="font"/> - <spacer width="2%" height="1"/> - <label id="highscore2" proportion="1" text="(Empty)"/> - </div> - - <spacer width="1" height="2%"/> - - <div width="95%" height="fit" layout="horizontal-row"> - <icon id="iconscore3" icon="gui/random_kart.png" width="font" height="font"/> - <spacer width="2%" height="1"/> - <label id="highscore3" proportion="1" text="(Empty)"/> - </div> - - <spacer width="1" proportion="1"/> - - <label id="author" width="100%" text_align="center" word_wrap="true"/> - </div> - - <!-- Right pane --> - <div proportion="1" height="100%" layout="vertical-row"> - <placeholder proportion="1" width="100%" height="100%" id="screenshot_div"> - </placeholder> - <div width="75%" height="fit" layout="horizontal-row" > - <spacer proportion="1" height="2" /> - <checkbox id="reverse"/> - <spacer width="20" height="2" /> - <label id="reverse-text" height="100%" I18N="Drive the track reverse" text="Reverse"/> - <spacer proportion="1" height="2" /> - </div> - - </div> - </div> - - <spacer width="1" height="5%"/> - - <spinner id="lapcountspinner" width="50%" min_value="1" max_value="20" align="center" wrap_around="true" - I18N="In the track setup screen (number of laps choice, where %i is the number)" text="%i laps"/> - - <spacer width="1" height="5%"/> - - <button id="start" text="Start Race" align="center"/> - - <spacer width="1" height="2%"/> - </div> - - <icon-button id="closePopup" x="0" y="0" width="8%" height="8%" icon="gui/back.png"/> - </div> -</stkgui> diff --git a/data/shaders/detailledobject_pass2.frag b/data/shaders/detailledobject_pass2.frag index 6d9a94c04..a426b6935 100644 --- a/data/shaders/detailledobject_pass2.frag +++ b/data/shaders/detailledobject_pass2.frag @@ -1,5 +1,10 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D Albedo; +layout(bindless_sampler) uniform sampler2D Detail; +#else uniform sampler2D Albedo; uniform sampler2D Detail; +#endif #if __VERSION__ >= 130 in vec2 uv; @@ -16,6 +21,11 @@ vec3 getLightFactor(float specMapValue); void main(void) { vec4 color = texture(Albedo, uv); +#ifdef GL_ARB_bindless_texture +#ifdef SRGBBindlessFix + color.xyz = pow(color.xyz, vec3(2.2)); +#endif +#endif vec4 detail = texture(Detail, uv_bis); color *= detail; vec3 LightFactor = getLightFactor(1. - color.a); diff --git a/data/shaders/glow_object.frag b/data/shaders/glow_object.frag new file mode 100644 index 000000000..a811b40f8 --- /dev/null +++ b/data/shaders/glow_object.frag @@ -0,0 +1,8 @@ +flat in vec4 glowColor; + +out vec4 FragColor; + +void main() +{ + FragColor = vec4(glowColor.rgb, 1.0); +} diff --git a/data/shaders/glow_object.vert b/data/shaders/glow_object.vert new file mode 100644 index 000000000..703529317 --- /dev/null +++ b/data/shaders/glow_object.vert @@ -0,0 +1,24 @@ +layout(location = 0) in vec3 Position; +layout(location = 1) in vec3 Normal; +layout(location = 2) in vec4 Color; +layout(location = 3) in vec2 Texcoord; +layout(location = 5) in vec3 Tangent; +layout(location = 6) in vec3 Bitangent; + +layout(location = 7) in vec3 Origin; +layout(location = 8) in vec3 Orientation; +layout(location = 9) in vec3 Scale; +layout(location = 12) in vec4 GlowColor; + +flat out vec4 glowColor; + +mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); +mat4 getInverseWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); + +void main(void) +{ + mat4 ModelMatrix = getWorldMatrix(Origin, Orientation, Scale); + mat4 TransposeInverseModelView = transpose(getInverseWorldMatrix(Origin, Orientation, Scale) * InverseViewMatrix); + gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * vec4(Position, 1.); + glowColor = GlowColor; +} diff --git a/data/shaders/grass_pass2.frag b/data/shaders/grass_pass2.frag index 663232a72..408e78365 100644 --- a/data/shaders/grass_pass2.frag +++ b/data/shaders/grass_pass2.frag @@ -1,6 +1,12 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D Albedo; +layout(bindless_sampler) uniform sampler2D dtex; +#else uniform sampler2D Albedo; -uniform vec3 SunDir; uniform sampler2D dtex; +#endif + +uniform vec3 SunDir; in vec3 nor; in vec2 uv; @@ -26,6 +32,11 @@ void main(void) float scattering = mix(fPowEdotL, fLdotNBack, .5); vec4 color = texture(Albedo, uv); +#ifdef GL_ARB_bindless_texture +#ifdef SRGBBindlessFix + color.xyz = pow(color.xyz, vec3(2.2)); +#endif +#endif if (color.a < 0.5) discard; vec3 LightFactor = (scattering * 0.3) + getLightFactor(1.); FragColor = vec4(color.xyz * LightFactor, 1.); diff --git a/data/shaders/header.txt b/data/shaders/header.txt index 74a2cb81b..98e73f6a9 100644 --- a/data/shaders/header.txt +++ b/data/shaders/header.txt @@ -3,6 +3,7 @@ uniform mat4 ViewMatrix; uniform mat4 ProjectionMatrix; uniform mat4 InverseViewMatrix; uniform mat4 InverseProjectionMatrix; +uniform mat4 ProjectionViewMatrix; uniform vec2 screen; #else layout (std140) uniform MatrixesData @@ -11,7 +12,8 @@ layout (std140) uniform MatrixesData mat4 ProjectionMatrix; mat4 InverseViewMatrix; mat4 InverseProjectionMatrix; + mat4 ProjectionViewMatrix; mat4 ShadowViewProjMatrixes[4]; vec2 screen; }; -#endif +#endif \ No newline at end of file diff --git a/data/shaders/instanced_detailledobject_pass2.frag b/data/shaders/instanced_detailledobject_pass2.frag new file mode 100644 index 000000000..18ff5aa20 --- /dev/null +++ b/data/shaders/instanced_detailledobject_pass2.frag @@ -0,0 +1,31 @@ +#ifndef GL_ARB_bindless_texture +uniform sampler2D Albedo; +uniform sampler2D Detail; +#endif + +#ifdef GL_ARB_bindless_texture +flat in sampler2D handle; +flat in sampler2D secondhandle; +#endif +in vec2 uv; +in vec2 uv_bis; +out vec4 FragColor; + +vec3 getLightFactor(float specMapValue); + +void main(void) +{ +#ifdef GL_ARB_bindless_texture + vec4 color = texture(handle, uv); +#ifdef SRGBBindlessFix + color.xyz = pow(color.xyz, vec3(2.2)); +#endif + vec4 detail = texture(secondhandle, uv_bis); +#else + vec4 color = texture(Albedo, uv); + vec4 detail = texture(Detail, uv_bis); +#endif + color *= detail; + vec3 LightFactor = getLightFactor(1. - color.a); + FragColor = vec4(color.xyz * LightFactor, 1.); +} diff --git a/data/shaders/instanced_grass.vert b/data/shaders/instanced_grass.vert index 803fa7f92..5a9d11769 100644 --- a/data/shaders/instanced_grass.vert +++ b/data/shaders/instanced_grass.vert @@ -9,6 +9,10 @@ layout(location = 3) in vec2 Texcoord; layout(location = 7) in vec3 Origin; layout(location = 8) in vec3 Orientation; layout(location = 9) in vec3 Scale; +#ifdef GL_ARB_bindless_texture +layout(location = 10) in sampler2D Handle; +#endif + #else in vec3 Position; in vec3 Normal; @@ -22,6 +26,9 @@ in vec3 Scale; out vec3 nor; out vec2 uv; +#ifdef GL_ARB_bindless_texture +flat out sampler2D handle; +#endif mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); mat4 getInverseWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); @@ -30,7 +37,10 @@ void main() { mat4 ModelMatrix = getWorldMatrix(Origin + windDir * Color.r, Orientation, Scale); mat4 TransposeInverseModelView = transpose(getInverseWorldMatrix(Origin + windDir * Color.r, Orientation, Scale) * InverseViewMatrix); - gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * vec4(Position, 1.); + gl_Position = ProjectionViewMatrix * ModelMatrix * vec4(Position, 1.); nor = (TransposeInverseModelView * vec4(Normal, 0.)).xyz; uv = Texcoord; +#ifdef GL_ARB_bindless_texture + handle = Handle; +#endif } diff --git a/data/shaders/instanced_grass_pass2.frag b/data/shaders/instanced_grass_pass2.frag new file mode 100644 index 000000000..b297a4c88 --- /dev/null +++ b/data/shaders/instanced_grass_pass2.frag @@ -0,0 +1,47 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D dtex; +#else +uniform sampler2D Albedo; +uniform sampler2D dtex; +#endif + +uniform vec3 SunDir; + +#ifdef GL_ARB_bindless_texture +flat in sampler2D handle; +#endif +in vec3 nor; +in vec2 uv; +out vec4 FragColor; + +vec3 getLightFactor(float specMapValue); + +void main(void) +{ + vec2 texc = gl_FragCoord.xy / screen; + float z = texture(dtex, texc).x; + + vec4 xpos = 2.0 * vec4(texc, z, 1.0) - 1.0f; + xpos = InverseProjectionMatrix * xpos; + xpos /= xpos.w; + vec3 eyedir = normalize(xpos.xyz); + + // Inspired from http://http.developer.nvidia.com/GPUGems3/gpugems3_ch16.html + float fEdotL = max(0., dot(SunDir, eyedir)); + float fPowEdotL = pow(fEdotL, 4.); + + float fLdotNBack = max(0., - dot(nor, SunDir) * 0.6 + 0.4); + float scattering = mix(fPowEdotL, fLdotNBack, .5); + +#ifdef GL_ARB_bindless_texture + vec4 color = texture(handle, uv); +#ifdef SRGBBindlessFix + color.xyz = pow(color.xyz, vec3(2.2)); +#endif +#else + vec4 color = texture(Albedo, uv); +#endif + if (color.a < 0.5) discard; + vec3 LightFactor = (scattering * 0.3) + getLightFactor(1.); + FragColor = vec4(color.xyz * LightFactor, 1.); +} diff --git a/data/shaders/instanced_normalmap.frag b/data/shaders/instanced_normalmap.frag new file mode 100644 index 000000000..4b4ecadcd --- /dev/null +++ b/data/shaders/instanced_normalmap.frag @@ -0,0 +1,35 @@ +#ifndef GL_ARB_bindless_texture +uniform sampler2D normalMap; +uniform sampler2D DiffuseForAlpha; +#endif + +#ifdef GL_ARB_bindless_texture +flat in sampler2D handle; +flat in sampler2D secondhandle; +#endif +in vec3 tangent; +in vec3 bitangent; +in vec2 uv; +out vec3 EncodedNormal; + +vec2 EncodeNormal(vec3 n); + +void main() +{ + // normal in Tangent Space +#ifdef GL_ARB_bindless_texture + vec3 TS_normal = 2.0 * texture(secondhandle, uv).rgb - 1.0; + float alpha = texture(handle, uv).a; +#else + vec3 TS_normal = 2.0 * texture(normalMap, uv).rgb - 1.0; + float alpha = texture(DiffuseForAlpha, uv).a; +#endif + // Because of interpolation, we need to renormalize + vec3 Frag_tangent = normalize(tangent); + vec3 Frag_normal = normalize(cross(Frag_tangent, bitangent)); + vec3 Frag_bitangent = cross(Frag_normal, Frag_tangent); + + vec3 FragmentNormal = TS_normal.x * Frag_tangent + TS_normal.y * Frag_bitangent - TS_normal.z * Frag_normal; + EncodedNormal.xy = 0.5 * EncodeNormal(normalize(FragmentNormal)) + 0.5; + EncodedNormal.z = exp2(10. * (1. - alpha) + 1.); +} diff --git a/data/shaders/instanced_object_pass.vert b/data/shaders/instanced_object_pass.vert index f83c7f7b5..ab0fce5b2 100644 --- a/data/shaders/instanced_object_pass.vert +++ b/data/shaders/instanced_object_pass.vert @@ -9,6 +9,11 @@ layout(location = 6) in vec3 Bitangent; layout(location = 7) in vec3 Origin; layout(location = 8) in vec3 Orientation; layout(location = 9) in vec3 Scale; +#ifdef GL_ARB_bindless_texture +layout(location = 10) in sampler2D Handle; +layout(location = 11) in sampler2D SecondHandle; +#endif + #else in vec3 Position; in vec3 Normal; @@ -27,6 +32,10 @@ out vec3 tangent; out vec3 bitangent; out vec2 uv; out vec4 color; +#ifdef GL_ARB_bindless_texture +flat out sampler2D handle; +flat out sampler2D secondhandle; +#endif mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); mat4 getInverseWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); @@ -35,10 +44,14 @@ void main(void) { mat4 ModelMatrix = getWorldMatrix(Origin, Orientation, Scale); mat4 TransposeInverseModelView = transpose(getInverseWorldMatrix(Origin, Orientation, Scale) * InverseViewMatrix); - gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * vec4(Position, 1.); + gl_Position = ProjectionViewMatrix * ModelMatrix * vec4(Position, 1.); nor = (TransposeInverseModelView * vec4(Normal, 0.)).xyz; tangent = (TransposeInverseModelView * vec4(Tangent, 1.)).xyz; bitangent = (TransposeInverseModelView * vec4(Bitangent, 1.)).xyz; uv = Texcoord; color = Color.zyxw; +#ifdef GL_ARB_bindless_texture + handle = Handle; + secondhandle = SecondHandle; +#endif } diff --git a/data/shaders/instanced_object_pass1.frag b/data/shaders/instanced_object_pass1.frag new file mode 100644 index 000000000..fc04aa63f --- /dev/null +++ b/data/shaders/instanced_object_pass1.frag @@ -0,0 +1,23 @@ +#ifndef GL_ARB_bindless_texture +uniform sampler2D tex; +#endif + +#ifdef GL_ARB_bindless_texture +flat in sampler2D handle; +#endif +in vec3 nor; +in vec2 uv; +out vec3 EncodedNormal; + +vec2 EncodeNormal(vec3 n); + +void main(void) +{ +#ifdef GL_ARB_bindless_texture + vec4 col = texture(handle, uv); +#else + vec4 col = texture(tex, uv); +#endif + EncodedNormal.xy = 0.5 * EncodeNormal(normalize(nor)) + 0.5; + EncodedNormal.z = exp2(10. * (1. - col.a) + 1.); +} diff --git a/data/shaders/instanced_object_pass2.frag b/data/shaders/instanced_object_pass2.frag new file mode 100644 index 000000000..76176ba37 --- /dev/null +++ b/data/shaders/instanced_object_pass2.frag @@ -0,0 +1,27 @@ +#ifndef GL_ARB_bindless_texture +uniform sampler2D Albedo; +#endif + +#ifdef GL_ARB_bindless_texture +flat in sampler2D handle; +#endif +in vec2 uv; +in vec4 color; +out vec4 FragColor; + +vec3 getLightFactor(float specMapValue); + +void main(void) +{ +#ifdef GL_ARB_bindless_texture + vec4 col = texture(handle, uv); +#ifdef SRGBBindlessFix + col.xyz = pow(col.xyz, vec3(2.2)); +#endif +#else + vec4 col = texture(Albedo, uv); +#endif + col.xyz *= pow(color.xyz, vec3(2.2)); + vec3 LightFactor = getLightFactor(1.); + FragColor = vec4(col.xyz * LightFactor, 1.); +} diff --git a/data/shaders/instanced_object_unlit.frag b/data/shaders/instanced_object_unlit.frag new file mode 100644 index 000000000..4e90c0fc4 --- /dev/null +++ b/data/shaders/instanced_object_unlit.frag @@ -0,0 +1,26 @@ +#ifndef GL_ARB_bindless_texture +uniform sampler2D tex; +#endif + +#ifdef GL_ARB_bindless_texture +flat in sampler2D handle; +#endif + +in vec2 uv; +in vec4 color; +out vec4 FragColor; + +void main(void) +{ +#ifdef GL_ARB_bindless_texture + vec4 col = texture(handle, uv); +#ifdef SRGBBindlessFix + col.xyz = pow(col.xyz, vec3(2.2)); +#endif +#else + vec4 col = texture(tex, uv); +#endif + col.xyz *= pow(color.xyz, vec3(2.2)); + if (col.a < 0.5) discard; + FragColor = vec4(col.xyz, 1.); +} diff --git a/data/shaders/instanced_objectpass_spheremap.frag b/data/shaders/instanced_objectpass_spheremap.frag new file mode 100644 index 000000000..5365dd7ef --- /dev/null +++ b/data/shaders/instanced_objectpass_spheremap.frag @@ -0,0 +1,35 @@ +// See http://www.ozone3d.net/tutorials/glsl_texturing_p04.php for ref + +#ifndef GL_ARB_bindless_texture +uniform sampler2D tex; +#endif + +#ifdef GL_ARB_bindless_texture +flat in sampler2D handle; +#endif +in vec3 nor; +out vec4 FragColor; + + +vec4 getPosFromUVDepth(vec3 uvDepth, mat4 InverseProjectionMatrix); +vec3 getLightFactor(float specMapValue); + +void main() { + vec3 texc = gl_FragCoord.xyz / vec3(screen, 1.); + vec3 u = getPosFromUVDepth(texc, InverseProjectionMatrix).xyz; + vec3 r = reflect(u, nor); + + float m = 2.0 * sqrt(r.x * r.x + r.y * r.y + (r.z + 1.0) * (r.z + 1.0)); + r.y = - r.y; +#ifdef GL_ARB_bindless_texture + vec4 detail0 = texture(handle, r.xy / m + .5); +#ifdef SRGBBindlessFix + detail0.xyz = pow(detail0.xyz, vec3(2.2)); +#endif +#else + vec4 detail0 = texture(tex, r.xy / m + .5); +#endif + vec3 LightFactor = getLightFactor(1.); + + FragColor = vec4(detail0.xyz * LightFactor, 1.); +} diff --git a/data/shaders/instanced_objectref_pass1.frag b/data/shaders/instanced_objectref_pass1.frag new file mode 100644 index 000000000..c24fcddf7 --- /dev/null +++ b/data/shaders/instanced_objectref_pass1.frag @@ -0,0 +1,25 @@ +#ifndef GL_ARB_bindless_texture +uniform sampler2D tex; +#endif + +#ifdef GL_ARB_bindless_texture +flat in sampler2D handle; +#endif +in vec3 nor; +in vec2 uv; +out vec3 EncodedNormal; + +vec2 EncodeNormal(vec3 n); + +void main() { +#ifdef GL_ARB_bindless_texture + vec4 col = texture(handle, uv); +#else + vec4 col = texture(tex, uv); +#endif + if (col.a < 0.5) + discard; + EncodedNormal.xy = 0.5 * EncodeNormal(normalize(nor)) + 0.5; + EncodedNormal.z = 1.; +} + diff --git a/data/shaders/instanced_objectref_pass2.frag b/data/shaders/instanced_objectref_pass2.frag new file mode 100644 index 000000000..201f610a1 --- /dev/null +++ b/data/shaders/instanced_objectref_pass2.frag @@ -0,0 +1,28 @@ +#ifndef GL_ARB_bindless_texture +uniform sampler2D Albedo; +#endif + +#ifdef GL_ARB_bindless_texture +flat in sampler2D handle; +#endif +in vec2 uv; +in vec4 color; +out vec4 FragColor; + +vec3 getLightFactor(float specMapValue); + +void main(void) +{ +#ifdef GL_ARB_bindless_texture + vec4 col = texture(handle, uv); +#ifdef SRGBBindlessFix + col.xyz = pow(col.xyz, vec3(2.2)); +#endif +#else + vec4 col = texture(Albedo, uv); +#endif + col.xyz *= pow(color.xyz, vec3(2.2)); + if (col.a * color.a < 0.5) discard; + vec3 LightFactor = getLightFactor(1.); + FragColor = vec4(col.xyz * LightFactor, 1.); +} diff --git a/data/shaders/instanced_rsm.frag b/data/shaders/instanced_rsm.frag new file mode 100644 index 000000000..a5f82d259 --- /dev/null +++ b/data/shaders/instanced_rsm.frag @@ -0,0 +1,27 @@ +#ifndef GL_ARB_bindless_texture +uniform sampler2D tex; +#endif + +in vec2 uv; +in vec3 nor; +in vec4 color; +#ifdef GL_ARB_bindless_texture +flat in uvec2 handle; +#endif +layout (location = 0) out vec3 RSMColor; +layout (location = 1) out vec3 RSMNormals; + +void main() +{ +#ifdef GL_ARB_bindless_texture + vec4 col = texture(sampler2D(handle), uv); +#ifdef SRGBBindlessFix + col.xyz = pow(col.xyz, vec3(2.2)); +#endif +#else + vec4 col = texture(tex, uv); +#endif + if (col.a < .5) discard; + RSMColor = col.xyz * color.rgb; + RSMNormals = .5 * normalize(nor) + .5; +} diff --git a/data/shaders/instanced_rsm.vert b/data/shaders/instanced_rsm.vert new file mode 100644 index 000000000..fc84a79ed --- /dev/null +++ b/data/shaders/instanced_rsm.vert @@ -0,0 +1,39 @@ +uniform mat4 RSMMatrix; + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec3 Normal; +layout(location = 2) in vec4 Color; +layout(location = 3) in vec2 Texcoord; +layout(location = 4) in vec2 SecondTexcoord; +layout(location = 7) in vec3 Origin; +layout(location = 8) in vec3 Orientation; +layout(location = 9) in vec3 Scale; +#ifdef GL_ARB_bindless_texture +layout(location = 10) in uvec2 Handle; +#endif + +out vec3 nor; +out vec2 uv; +out vec2 uv_bis; +out vec4 color; +#ifdef GL_ARB_bindless_texture +flat out uvec2 handle; +#endif + + +mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); +mat4 getInverseWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); + +void main(void) +{ + mat4 ModelMatrix = getWorldMatrix(Origin, Orientation, Scale); + mat4 ModelViewProjectionMatrix = RSMMatrix * ModelMatrix; + mat4 TransposeInverseModel = transpose(inverse(ModelMatrix)); + gl_Position = ModelViewProjectionMatrix * vec4(Position, 1.); + nor = (TransposeInverseModel * vec4(Normal, 0.)).xyz; + uv = Texcoord; + color = Color.zyxw; +#ifdef GL_ARB_bindless_texture + handle = Handle; +#endif +} diff --git a/data/shaders/instanced_shadow.geom b/data/shaders/instanced_shadow.geom new file mode 100644 index 000000000..a1a851e65 --- /dev/null +++ b/data/shaders/instanced_shadow.geom @@ -0,0 +1,28 @@ +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +#ifdef GL_ARB_bindless_texture +flat in uvec2 hdle[3]; +#endif +in vec2 tc[3]; +in int layerId[3]; + +out vec2 uv; +#ifdef GL_ARB_bindless_texture +out flat uvec2 handle; +#endif + +void main(void) +{ + gl_Layer = layerId[0]; +#ifdef GL_ARB_bindless_texture + handle = hdle[0]; +#endif + for(int i=0; i<3; i++) + { + uv = tc[i]; + gl_Position = gl_in[i].gl_Position; + EmitVertex(); + } + EndPrimitive(); +} diff --git a/data/shaders/instanced_shadowref.frag b/data/shaders/instanced_shadowref.frag new file mode 100644 index 000000000..0706edb1d --- /dev/null +++ b/data/shaders/instanced_shadowref.frag @@ -0,0 +1,21 @@ +#ifndef GL_ARB_bindless_texture +uniform sampler2D tex; +#endif + +#ifdef GL_ARB_bindless_texture +flat in uvec2 handle; +#endif +in vec2 uv; +in vec4 color; +out vec4 FragColor; + +void main(void) +{ +#ifdef GL_ARB_bindless_texture + vec4 col = texture(sampler2D(handle), uv); +#else + vec4 col = texture(tex, uv); +#endif + if (col.a < 0.5) discard; + FragColor = vec4(1.); +} diff --git a/data/shaders/instanciedgrassshadow.vert b/data/shaders/instanciedgrassshadow.vert index d27f2e808..e78f020eb 100644 --- a/data/shaders/instanciedgrassshadow.vert +++ b/data/shaders/instanciedgrassshadow.vert @@ -1,3 +1,5 @@ +uniform int layer; + uniform vec3 windDir; #if __VERSION__ >= 330 layout(location = 0) in vec3 Position; @@ -7,6 +9,10 @@ layout(location = 3) in vec2 Texcoord; layout(location = 7) in vec3 Origin; layout(location = 8) in vec3 Orientation; layout(location = 9) in vec3 Scale; +#ifdef GL_ARB_bindless_texture +layout(location = 10) in uvec2 Handle; +#endif + #else in vec3 Position; in vec4 Color; @@ -19,9 +25,15 @@ in vec3 Scale; #ifdef VSLayer out vec2 uv; +#ifdef GL_ARB_bindless_texture +flat out uvec2 handle; +#endif #else out vec2 tc; out int layerId; +#ifdef GL_ARB_bindless_texture +flat out uvec2 hdle; +#endif #endif mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); @@ -31,12 +43,18 @@ void main(void) { mat4 ModelMatrix = getWorldMatrix(Origin, Orientation, Scale); #ifdef VSLayer - gl_Layer = gl_InstanceID & 3; + gl_Layer = layer; gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * vec4(Position + windDir * Color.r, 1.); uv = Texcoord; +#ifdef GL_ARB_bindless_texture + handle = Handle; +#endif #else - layerId = gl_InstanceID & 3; + layerId = layer; gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * vec4(Position + windDir * Color.r, 1.); tc = Texcoord; +#ifdef GL_ARB_bindless_texture + hdle = Handle; +#endif #endif } \ No newline at end of file diff --git a/data/shaders/instanciedshadow.vert b/data/shaders/instanciedshadow.vert index a9f5fc34d..20b9d87f1 100644 --- a/data/shaders/instanciedshadow.vert +++ b/data/shaders/instanciedshadow.vert @@ -1,3 +1,5 @@ +uniform int layer; + #if __VERSION__ >= 330 layout(location = 0) in vec3 Position; layout(location = 3) in vec2 Texcoord; @@ -5,6 +7,10 @@ layout(location = 3) in vec2 Texcoord; layout(location = 7) in vec3 Origin; layout(location = 8) in vec3 Orientation; layout(location = 9) in vec3 Scale; +#ifdef GL_ARB_bindless_texture +layout(location = 10) in uvec2 Handle; +#endif + #else in vec3 Position; in vec2 Texcoord; @@ -16,9 +22,15 @@ in vec3 Scale; #ifdef VSLayer out vec2 uv; +#ifdef GL_ARB_bindless_texture +flat out uvec2 handle; +#endif #else out vec2 tc; out int layerId; +#ifdef GL_ARB_bindless_texture +flat out uvec2 hdle; +#endif #endif mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); @@ -28,12 +40,18 @@ void main(void) { mat4 ModelMatrix = getWorldMatrix(Origin, Orientation, Scale); #ifdef VSLayer - gl_Layer = gl_InstanceID & 3; + gl_Layer = layer; gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * vec4(Position, 1.); uv = Texcoord; +#ifdef GL_ARB_bindless_texture + handle = Handle; +#endif #else - layerId = gl_InstanceID & 3; + layerId = layer; gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * vec4(Position, 1.); tc = Texcoord; +#ifdef GL_ARB_bindless_texture + hdle = Handle; +#endif #endif } \ No newline at end of file diff --git a/data/shaders/normalmap.frag b/data/shaders/normalmap.frag index 255942efd..e7ba8efe4 100644 --- a/data/shaders/normalmap.frag +++ b/data/shaders/normalmap.frag @@ -1,5 +1,10 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D normalMap; +layout(bindless_sampler) uniform sampler2D DiffuseForAlpha; +#else uniform sampler2D normalMap; uniform sampler2D DiffuseForAlpha; +#endif in vec3 tangent; in vec3 bitangent; diff --git a/data/shaders/object_pass1.frag b/data/shaders/object_pass1.frag index e8e0df6ba..cd193b5ec 100644 --- a/data/shaders/object_pass1.frag +++ b/data/shaders/object_pass1.frag @@ -1,4 +1,8 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D tex; +#else uniform sampler2D tex; +#endif #if __VERSION__ >= 130 in vec3 nor; diff --git a/data/shaders/object_pass2.frag b/data/shaders/object_pass2.frag index d45ca01fb..047f0a192 100644 --- a/data/shaders/object_pass2.frag +++ b/data/shaders/object_pass2.frag @@ -1,4 +1,8 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D Albedo; +#else uniform sampler2D Albedo; +#endif in vec2 uv; in vec4 color; @@ -8,7 +12,14 @@ vec3 getLightFactor(float specMapValue); void main(void) { +#ifdef GL_ARB_bindless_texture vec4 col = texture(Albedo, uv); +#ifdef SRGBBindlessFix + col.xyz = pow(col.xyz, vec3(2.2)); +#endif +#else + vec4 col = texture(Albedo, uv); +#endif col.xyz *= pow(color.xyz, vec3(2.2)); vec3 LightFactor = getLightFactor(1.); FragColor = vec4(col.xyz * LightFactor, 1.); diff --git a/data/shaders/object_unlit.frag b/data/shaders/object_unlit.frag index bf5c5f3c9..6f38a27be 100644 --- a/data/shaders/object_unlit.frag +++ b/data/shaders/object_unlit.frag @@ -1,4 +1,8 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D tex; +#else uniform sampler2D tex; +#endif in vec2 uv; in vec4 color; @@ -7,6 +11,11 @@ out vec4 FragColor; void main(void) { vec4 col = texture(tex, uv); +#ifdef GL_ARB_bindless_texture +#ifdef SRGBBindlessFix + col.xyz = pow(col.xyz, vec3(2.2)); +#endif +#endif col.xyz *= pow(color.xyz, vec3(2.2)); if (col.a < 0.5) discard; FragColor = vec4(col.xyz, 1.); diff --git a/data/shaders/objectpass_spheremap.frag b/data/shaders/objectpass_spheremap.frag index 138936d23..8e4e0f4fc 100644 --- a/data/shaders/objectpass_spheremap.frag +++ b/data/shaders/objectpass_spheremap.frag @@ -1,6 +1,10 @@ // See http://www.ozone3d.net/tutorials/glsl_texturing_p04.php for ref +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D tex; +#else uniform sampler2D tex; +#endif #if __VERSION__ >= 130 in vec3 nor; @@ -21,6 +25,11 @@ void main() { float m = 2.0 * sqrt(r.x * r.x + r.y * r.y + (r.z + 1.0) * (r.z + 1.0)); r.y = - r.y; vec4 detail0 = texture(tex, r.xy / m + .5); +#ifdef GL_ARB_bindless_texture +#ifdef SRGBBindlessFix + detail0.xyz = pow(detail0.xyz, vec3(2.2)); +#endif +#endif vec3 LightFactor = getLightFactor(1.); FragColor = vec4(detail0.xyz * LightFactor, 1.); diff --git a/data/shaders/objectref_pass1.frag b/data/shaders/objectref_pass1.frag index f4cf55e29..7738e82b8 100644 --- a/data/shaders/objectref_pass1.frag +++ b/data/shaders/objectref_pass1.frag @@ -1,4 +1,8 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D tex; +#else uniform sampler2D tex; +#endif #if __VERSION__ >= 130 in vec3 nor; diff --git a/data/shaders/objectref_pass2.frag b/data/shaders/objectref_pass2.frag index c20b7e82e..13ff676f8 100644 --- a/data/shaders/objectref_pass2.frag +++ b/data/shaders/objectref_pass2.frag @@ -1,4 +1,8 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D Albedo; +#else uniform sampler2D Albedo; +#endif in vec2 uv; in vec4 color; @@ -9,6 +13,11 @@ vec3 getLightFactor(float specMapValue); void main(void) { vec4 col = texture(Albedo, uv); +#ifdef GL_ARB_bindless_texture +#ifdef SRGBBindlessFix + col.xyz = pow(col.xyz, vec3(2.2)); +#endif +#endif col.xyz *= pow(color.xyz, vec3(2.2)); if (col.a * color.a < 0.5) discard; vec3 LightFactor = getLightFactor(1.); diff --git a/data/shaders/pointlight.frag b/data/shaders/pointlight.frag index c8913fd50..c479ec7ce 100644 --- a/data/shaders/pointlight.frag +++ b/data/shaders/pointlight.frag @@ -1,6 +1,5 @@ uniform sampler2D ntex; uniform sampler2D dtex; -uniform float spec; flat in vec3 center; flat in float energy; diff --git a/data/shaders/shadow.vert b/data/shaders/shadow.vert index 7fe9b6fa8..3bbc6c6a5 100644 --- a/data/shaders/shadow.vert +++ b/data/shaders/shadow.vert @@ -1,3 +1,4 @@ +uniform int layer; uniform mat4 ModelMatrix; #if __VERSION__ >= 330 @@ -18,11 +19,11 @@ out int layerId; void main(void) { #ifdef VSLayer - gl_Layer = gl_InstanceID & 3; + gl_Layer = layer; uv = Texcoord; gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * vec4(Position, 1.); #else - layerId = gl_InstanceID & 3; + layerId = layer; tc = Texcoord; gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * vec4(Position, 1.); #endif diff --git a/data/shaders/shadow_grass.vert b/data/shaders/shadow_grass.vert index 39ae2ea5c..bf6d7435b 100644 --- a/data/shaders/shadow_grass.vert +++ b/data/shaders/shadow_grass.vert @@ -1,3 +1,4 @@ +uniform int layer; uniform mat4 ModelMatrix; uniform vec3 windDir; @@ -21,11 +22,11 @@ out int layerId; void main(void) { #ifdef VSLayer - gl_Layer = gl_InstanceID & 3; + gl_Layer = layer; uv = Texcoord; gl_Position = ShadowViewProjMatrixes[gl_Layer] * ModelMatrix * vec4(Position + windDir * Color.r, 1.); #else - layerId = gl_InstanceID & 3; + layerId = layer; tc = Texcoord; gl_Position = ShadowViewProjMatrixes[layerId] * ModelMatrix * vec4(Position + windDir * Color.r, 1.); #endif diff --git a/data/shaders/splatting.frag b/data/shaders/splatting.frag index d8bdc0555..d302908d2 100644 --- a/data/shaders/splatting.frag +++ b/data/shaders/splatting.frag @@ -1,8 +1,16 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D tex_layout; +layout(bindless_sampler) uniform sampler2D tex_detail0; +layout(bindless_sampler) uniform sampler2D tex_detail1; +layout(bindless_sampler) uniform sampler2D tex_detail2; +layout(bindless_sampler) uniform sampler2D tex_detail3; +#else uniform sampler2D tex_layout; uniform sampler2D tex_detail0; uniform sampler2D tex_detail1; uniform sampler2D tex_detail2; uniform sampler2D tex_detail3; +#endif #if __VERSION__ >= 130 in vec2 uv; @@ -24,6 +32,14 @@ void main() { vec4 detail2 = texture(tex_detail2, uv); vec4 detail3 = texture(tex_detail3, uv); vec4 detail4 = vec4(0.0); +#ifdef GL_ARB_bindless_texture +#ifdef SRGBBindlessFix + detail0.xyz = pow(detail0.xyz, vec3(2.2)); + detail1.xyz = pow(detail1.xyz, vec3(2.2)); + detail2.xyz = pow(detail2.xyz, vec3(2.2)); + detail3.xyz = pow(detail3.xyz, vec3(2.2)); +#endif +#endif vec4 splatted = splatting.r * detail0 + splatting.g * detail1 + diff --git a/data/shaders/transparent.frag b/data/shaders/transparent.frag index aaeba0601..5c84fee03 100644 --- a/data/shaders/transparent.frag +++ b/data/shaders/transparent.frag @@ -1,4 +1,8 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D tex; +#else uniform sampler2D tex; +#endif in vec2 uv; in vec4 color; @@ -8,6 +12,9 @@ out vec4 FragColor; void main() { vec4 Color = texture(tex, uv); +#ifdef GL_ARB_bindless_texture + Color.xyz = pow(Color.xyz, vec3(2.2)); +#endif Color.xyz *= pow(color.xyz, vec3(2.2)); Color.a *= color.a; // Premultiply alpha diff --git a/data/shaders/transparentfog.frag b/data/shaders/transparentfog.frag index d6f0f3344..b73a06fdf 100644 --- a/data/shaders/transparentfog.frag +++ b/data/shaders/transparentfog.frag @@ -1,4 +1,9 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D tex; +#else uniform sampler2D tex; +#endif + uniform float fogmax; uniform float startH; @@ -15,6 +20,9 @@ out vec4 FragColor; void main() { vec4 diffusecolor = texture(tex, uv); +#ifdef GL_ARB_bindless_texture + diffusecolor.xyz = pow(diffusecolor.xyz, vec3(2.2)); +#endif diffusecolor.xyz *= pow(color.xyz, vec3(2.2)); diffusecolor.a *= color.a; vec3 tmp = vec3(gl_FragCoord.xy / screen, gl_FragCoord.z); diff --git a/data/shaders/utils/getLightFactor.frag b/data/shaders/utils/getLightFactor.frag index ec7fa5725..9bf4cdf58 100644 --- a/data/shaders/utils/getLightFactor.frag +++ b/data/shaders/utils/getLightFactor.frag @@ -1,6 +1,12 @@ +#ifdef GL_ARB_bindless_texture +layout(bindless_sampler) uniform sampler2D DiffuseMap; +layout(bindless_sampler) uniform sampler2D SpecularMap; +layout(bindless_sampler) uniform sampler2D SSAO; +#else uniform sampler2D DiffuseMap; uniform sampler2D SpecularMap; uniform sampler2D SSAO; +#endif vec3 getLightFactor(float specMapValue) { diff --git a/data/shaders/utils/getworldmatrix.vert b/data/shaders/utils/getworldmatrix.vert index 3bff563f4..c5883ae35 100644 --- a/data/shaders/utils/getworldmatrix.vert +++ b/data/shaders/utils/getworldmatrix.vert @@ -45,6 +45,6 @@ mat4 getInverseWorldMatrix(vec3 translation, vec3 rotation, vec3 scale) { mat4 result = transpose(getMatrixFromRotation(rotation)); // FIXME: it's wrong but the fourth column is not used - result[3].xyz -= translation; + // result[3].xyz -= translation; return getScaleMatrix(1. / scale) * result; } \ No newline at end of file diff --git a/data/stk_config.xml b/data/stk_config.xml index f6b5c9223..5e0fdfbe0 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -155,12 +155,13 @@ otherwise obstricts too much of the view. --> <camera distance="1.5" forward-up-angle="15" backward-up-angle="30"/> + <!-- Additional offset to move graphical chassis with regards to the physics. --> + <graphics y-offset="0.0"/> - <!-- Jump animation related values: - animation-time: only if the estimated time for a jump is larger - than this value will the jump animation being - shown. --> - <jump animation-time="0.5" /> + <!-- Jump animation related values: + animation-time: only if the estimated time for a jump is larger + than this value will the jump animation being shown. --> + <jump animation-time="0.5" /> <!-- Skidding: increase: multiplicative increase of skidding factor in each frame. decrease: multiplicative decrease of skidding factor in each frame. @@ -415,11 +416,14 @@ physical-wheel-position: Defines where the 'physical' (raycast) wheel will be located. It's a weight factor with 0 = being at the widest side of the bevel, 1 = at the front and - narrowest part of the kart. --> + narrowest part of the kart. If the value is less than 0, the old + physics settings are used which places the raycast wheels + outside of the chassis and results in more stable physical + behaviour of the karts. --> <collision impulse-type="normal" - impulse="3000" impulse-time="0.1" terrain-impulse="8000" + impulse="3000" impulse-time="0.1" terrain-impulse="1600" restitution="1.0" bevel-factor="0.5 0.0 0.7" - physical-wheel-position="0.5" /> + physical-wheel-position="-1" /> <!-- If a kart starts within the specified time after 'go', it receives the corresponding bonus from 'boost'. Those diff --git a/data/supertuxkart_desktop.template b/data/supertuxkart.desktop similarity index 66% rename from data/supertuxkart_desktop.template rename to data/supertuxkart.desktop index 789b21442..034f20da6 100644 --- a/data/supertuxkart_desktop.template +++ b/data/supertuxkart.desktop @@ -1,15 +1,14 @@ [Desktop Entry] Name=SuperTuxKart -Icon=@PREFIX@/share/pixmaps/supertuxkart_128.png +Icon=supertuxkart GenericName=A kart racing game GenericName[de]=Ein Kart-Rennspiel GenericName[fr]=Un jeu de karting GenericName[gl]=Xogo de carreiras con karts GenericName[pl]=Wyścigi gokartów GenericName[ro]=Un joc de curse cu carturi -Exec=@PREFIX@/@STK_INSTALL_BINARY_DIR@/supertuxkart --no-console +Exec=supertuxkart Terminal=false StartupNotify=false Type=Application -TryExec=@PREFIX@/@STK_INSTALL_BINARY_DIR@/supertuxkart Categories=Game;ArcadeGame; diff --git a/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionObject.h b/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionObject.h index 6140458e4..6e76828d4 100644 --- a/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionObject.h +++ b/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionObject.h @@ -4,8 +4,8 @@ Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -24,6 +24,12 @@ subject to the following restrictions: # include <math.h> #endif +#if defined(__MINGW32__) && __cplusplus >= 201103 + #include <cmath> + using std::isinf; + using std::isnan; +#endif + #include "LinearMath/btTransform.h" //island management, m_activationState1 @@ -51,7 +57,7 @@ typedef btAlignedObjectArray<class btCollisionObject*> btCollisionObjectArray; #endif -/// btCollisionObject can be used to manage collision detection objects. +/// btCollisionObject can be used to manage collision detection objects. /// btCollisionObject maintains all information that is needed for a collision detection: Shape, Transform and AABB proxy. /// They can be added to the btCollisionWorld. ATTRIBUTE_ALIGNED16(class) btCollisionObject @@ -64,20 +70,20 @@ protected: ///m_interpolationWorldTransform is used for CCD and interpolation ///it can be either previous or future (predicted) transform btTransform m_interpolationWorldTransform; - //those two are experimental: just added for bullet time effect, so you can still apply impulses (directly modifying velocities) + //those two are experimental: just added for bullet time effect, so you can still apply impulses (directly modifying velocities) //without destroying the continuous interpolated motion (which uses this interpolation velocities) btVector3 m_interpolationLinearVelocity; btVector3 m_interpolationAngularVelocity; - + btVector3 m_anisotropicFriction; int m_hasAnisotropicFriction; - btScalar m_contactProcessingThreshold; + btScalar m_contactProcessingThreshold; btBroadphaseProxy* m_broadphaseHandle; btCollisionShape* m_collisionShape; ///m_extensionPointer is used by some internal low-level Bullet extensions. void* m_extensionPointer; - + ///m_rootCollisionShape is temporarily used to store the original collision shape ///The m_collisionShape might be temporarily replaced by a child collision shape during collision detection purposes ///If it is NULL, the m_collisionShape is not temporarily replaced. @@ -102,14 +108,14 @@ protected: void* m_userObjectPointer; ///time of impact calculation - btScalar m_hitFraction; - + btScalar m_hitFraction; + ///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: btScalar m_ccdSweptSphereRadius; /// Don't do continuous collision detection if the motion (in one step) is less then m_ccdMotionThreshold btScalar m_ccdMotionThreshold; - + /// If some object should have elaborate collision filtering by sub-classes int m_checkCollideWith; @@ -194,7 +200,7 @@ public: return (m_collisionFlags & CF_NO_CONTACT_RESPONSE)==0; } - + btCollisionObject(); virtual ~btCollisionObject(); @@ -232,7 +238,7 @@ public: m_collisionShape = collisionShape; } - ///Avoid using this internal API call, the extension pointer is used by some Bullet extensions. + ///Avoid using this internal API call, the extension pointer is used by some Bullet extensions. ///If you need to store your own user pointer, use 'setUserPointer/getUserPointer' instead. void* internalGetExtensionPointer() const { @@ -246,7 +252,7 @@ public: } SIMD_FORCE_INLINE int getActivationState() const { return m_activationState1;} - + void setActivationState(int newState); void setDeactivationTime(btScalar time) @@ -385,7 +391,7 @@ public: SIMD_FORCE_INLINE btScalar getHitFraction() const { - return m_hitFraction; + return m_hitFraction; } void setHitFraction(btScalar hitFraction) @@ -393,7 +399,7 @@ public: m_hitFraction = hitFraction; } - + SIMD_FORCE_INLINE int getCollisionFlags() const { return m_collisionFlags; @@ -403,7 +409,7 @@ public: { m_collisionFlags = flags; } - + ///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: btScalar getCcdSweptSphereRadius() const { @@ -439,7 +445,7 @@ public: { return m_userObjectPointer; } - + ///users can point to their objects, userPointer is not used by Bullet void setUserPointer(void* userPointer) { @@ -477,11 +483,11 @@ struct btCollisionObjectDoubleData btVector3DoubleData m_interpolationLinearVelocity; btVector3DoubleData m_interpolationAngularVelocity; btVector3DoubleData m_anisotropicFriction; - double m_contactProcessingThreshold; + double m_contactProcessingThreshold; double m_deactivationTime; double m_friction; double m_restitution; - double m_hitFraction; + double m_hitFraction; double m_ccdSweptSphereRadius; double m_ccdMotionThreshold; @@ -509,11 +515,11 @@ struct btCollisionObjectFloatData btVector3FloatData m_interpolationLinearVelocity; btVector3FloatData m_interpolationAngularVelocity; btVector3FloatData m_anisotropicFriction; - float m_contactProcessingThreshold; + float m_contactProcessingThreshold; float m_deactivationTime; float m_friction; float m_restitution; - float m_hitFraction; + float m_hitFraction; float m_ccdSweptSphereRadius; float m_ccdMotionThreshold; diff --git a/lib/bullet/src/BulletDynamics/Dynamics/btRigidBody.h b/lib/bullet/src/BulletDynamics/Dynamics/btRigidBody.h index 6028a19cb..1036c576c 100644 --- a/lib/bullet/src/BulletDynamics/Dynamics/btRigidBody.h +++ b/lib/bullet/src/BulletDynamics/Dynamics/btRigidBody.h @@ -4,8 +4,8 @@ Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -26,6 +26,11 @@ subject to the following restrictions: #endif #include <math.h> +#if defined(__MINGW32__) && __cplusplus >= 201103 + #include <cmath> + using std::isnan; +#endif + class btCollisionShape; class btMotionState; class btTypedConstraint; @@ -51,7 +56,7 @@ enum btRigidBodyFlags ///The btRigidBody is the main class for rigid body objects. It is derived from btCollisionObject, so it keeps a pointer to a btCollisionShape. ///It is recommended for performance and memory use to share btCollisionShape objects whenever possible. -///There are 3 types of rigid bodies: +///There are 3 types of rigid bodies: ///- A) Dynamic rigid bodies, with positive mass. Motion is controlled by rigid body dynamics. ///- B) Fixed objects with zero mass. They are not moving (basically collision objects) ///- C) Kinematic objects, which are objects without mass, but the user can move them. There is on-way interaction, and Bullet calculates a velocity based on the timestep and previous and current world transform. @@ -66,12 +71,12 @@ class btRigidBody : public btCollisionObject btScalar m_inverseMass; btVector3 m_linearFactor; - btVector3 m_gravity; + btVector3 m_gravity; btVector3 m_gravity_acceleration; btVector3 m_invInertiaLocal; btVector3 m_totalForce; btVector3 m_totalTorque; - + btScalar m_linearDamping; btScalar m_angularDamping; @@ -92,9 +97,9 @@ class btRigidBody : public btCollisionObject btAlignedObjectArray<btTypedConstraint*> m_constraintRefs; int m_rigidbodyFlags; - + int m_debugBodyId; - + protected: @@ -111,7 +116,7 @@ public: ///The btRigidBodyConstructionInfo structure provides information to create a rigid body. Setting mass to zero creates a fixed (non-dynamic) rigid body. ///For dynamic objects, you can use the collision shape to approximate the local inertia tensor, otherwise use the zero vector (default argument) - ///You can use the motion state to synchronize the world transform between physics and graphics objects. + ///You can use the motion state to synchronize the world transform between physics and graphics objects. ///And if the motion state is provided, the rigid body will initialize its initial world transform from the motion state, ///m_startWorldTransform is only used when you don't provide a motion state. struct btRigidBodyConstructionInfo @@ -168,16 +173,16 @@ public: ///btRigidBody constructor using construction info btRigidBody( const btRigidBodyConstructionInfo& constructionInfo); - ///btRigidBody constructor for backwards compatibility. + ///btRigidBody constructor for backwards compatibility. ///To specify friction (etc) during rigid body construction, please use the other constructor (using btRigidBodyConstructionInfo) btRigidBody( btScalar mass, btMotionState* motionState, btCollisionShape* collisionShape, const btVector3& localInertia=btVector3(0,0,0)); virtual ~btRigidBody() - { + { //No constraints should point to this rigidbody - //Remove constraints from the dynamics world before you delete the related rigidbodies. - btAssert(m_constraintRefs.size()==0); + //Remove constraints from the dynamics world before you delete the related rigidbodies. + btAssert(m_constraintRefs.size()==0); } protected: @@ -187,8 +192,8 @@ protected: public: - void proceedToTransform(const btTransform& newTrans); - + void proceedToTransform(const btTransform& newTrans); + ///to keep collision detection and dynamics separate we don't store a rigidbody pointer ///but a rigidbody is derived from btCollisionObject, so we can safely perform an upcast static const btRigidBody* upcast(const btCollisionObject* colObj) @@ -203,15 +208,15 @@ public: return (btRigidBody*)colObj; return 0; } - + /// continuous collision detection needs prediction void predictIntegratedTransform(btScalar step, btTransform& predictedTransform) ; - + void saveKinematicState(btScalar step); - + void applyGravity(); - - void setGravity(const btVector3& acceleration); + + void setGravity(const btVector3& acceleration); const btVector3& getGravity() const { @@ -249,9 +254,9 @@ public: SIMD_FORCE_INLINE btCollisionShape* getCollisionShape() { return m_collisionShape; } - + void setMassProps(btScalar mass, const btVector3& inertia); - + const btVector3& getLinearFactor() const { return m_linearFactor; @@ -265,10 +270,10 @@ public: m_invMass = m_linearFactor*m_inverseMass; } btScalar getInvMass() const { return m_inverseMass; } - const btMatrix3x3& getInvInertiaTensorWorld() const { - return m_invInertiaTensorWorld; + const btMatrix3x3& getInvInertiaTensorWorld() const { + return m_invInertiaTensorWorld; } - + void integrateVelocities(btScalar step); void setCenterOfMassTransform(const btTransform& xform); @@ -290,7 +295,7 @@ public: { return m_totalTorque; }; - + const btVector3& getInvInertiaDiagLocal() const { return m_invInertiaLocal; @@ -314,8 +319,8 @@ public: btAssert(!isnan(torque.getZ())); m_totalTorque += torque*m_angularFactor; } - - void applyForce(const btVector3& force, const btVector3& rel_pos) + + void applyForce(const btVector3& force, const btVector3& rel_pos) { btAssert(!isnan(force.getX())); btAssert(!isnan(force.getY())); @@ -326,7 +331,7 @@ public: applyCentralForce(force); applyTorque(rel_pos.cross(force*m_linearFactor)); } - + void applyCentralImpulse(const btVector3& impulse) { btAssert(!isnan(impulse.getX())); @@ -334,7 +339,7 @@ public: btAssert(!isnan(impulse.getZ())); m_linearVelocity += impulse *m_linearFactor * m_inverseMass; } - + void applyTorqueImpulse(const btVector3& torque) { btAssert(!isnan(torque.getX())); @@ -342,8 +347,8 @@ public: btAssert(!isnan(torque.getZ())); m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; } - - void applyImpulse(const btVector3& impulse, const btVector3& rel_pos) + + void applyImpulse(const btVector3& impulse, const btVector3& rel_pos) { btAssert(!isnan(impulse.getX())); btAssert(!isnan(impulse.getY())); @@ -361,44 +366,44 @@ public: } } - void clearForces() + void clearForces() { m_totalForce.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); m_totalTorque.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); } - - void updateInertiaTensor(); - - const btVector3& getCenterOfMassPosition() const { - return m_worldTransform.getOrigin(); + + void updateInertiaTensor(); + + const btVector3& getCenterOfMassPosition() const { + return m_worldTransform.getOrigin(); } btQuaternion getOrientation() const; - - const btTransform& getCenterOfMassTransform() const { - return m_worldTransform; + + const btTransform& getCenterOfMassTransform() const { + return m_worldTransform; } - const btVector3& getLinearVelocity() const { - return m_linearVelocity; + const btVector3& getLinearVelocity() const { + return m_linearVelocity; } - const btVector3& getAngularVelocity() const { - return m_angularVelocity; + const btVector3& getAngularVelocity() const { + return m_angularVelocity; } - + inline void setLinearVelocity(const btVector3& lin_vel) - { + { btAssert(!isnan(lin_vel.getX())); btAssert(!isnan(lin_vel.getY())); btAssert(!isnan(lin_vel.getZ())); - m_linearVelocity = lin_vel; + m_linearVelocity = lin_vel; } - inline void setAngularVelocity(const btVector3& ang_vel) - { + inline void setAngularVelocity(const btVector3& ang_vel) + { btAssert(!isnan(ang_vel.getX())); btAssert(!isnan(ang_vel.getY())); btAssert(!isnan(ang_vel.getZ())); - m_angularVelocity = ang_vel; + m_angularVelocity = ang_vel; } btVector3 getVelocityInLocalPoint(const btVector3& rel_pos) const @@ -410,18 +415,18 @@ public: // return (m_worldTransform(rel_pos) - m_interpolationWorldTransform(rel_pos)) / m_kinematicTimeStep; } - void translate(const btVector3& v) + void translate(const btVector3& v) { - m_worldTransform.getOrigin() += v; + m_worldTransform.getOrigin() += v; } - + void getAabb(btVector3& aabbMin,btVector3& aabbMax) const; - + SIMD_FORCE_INLINE btScalar computeImpulseDenominator(const btVector3& pos, const btVector3& normal) const { btVector3 r0 = pos - getCenterOfMassPosition(); @@ -478,12 +483,12 @@ public: } - + const btBroadphaseProxy* getBroadphaseProxy() const { return m_broadphaseHandle; } - btBroadphaseProxy* getBroadphaseProxy() + btBroadphaseProxy* getBroadphaseProxy() { return m_broadphaseHandle; } @@ -567,12 +572,12 @@ public: return m_deltaAngularVelocity; } - const btVector3& getPushVelocity() const + const btVector3& getPushVelocity() const { return m_pushVelocity; } - const btVector3& getTurnVelocity() const + const btVector3& getTurnVelocity() const { return m_turnVelocity; } @@ -580,7 +585,7 @@ public: //////////////////////////////////////////////// ///some internal methods, don't use them - + btVector3& internalGetDeltaLinearVelocity() { return m_deltaLinearVelocity; @@ -600,7 +605,7 @@ public: { return m_invMass; } - + btVector3& internalGetPushVelocity() { return m_pushVelocity; @@ -640,7 +645,7 @@ public: m_turnVelocity += angularComponent*(impulseMagnitude*m_angularFactor); } } - + void internalWritebackVelocity() { if (m_inverseMass) @@ -656,7 +661,7 @@ public: void internalWritebackVelocity(btScalar timeStep); - + /////////////////////////////////////////////// @@ -679,7 +684,7 @@ struct btRigidBodyFloatData btVector3FloatData m_angularVelocity; btVector3FloatData m_angularFactor; btVector3FloatData m_linearFactor; - btVector3FloatData m_gravity; + btVector3FloatData m_gravity; btVector3FloatData m_gravity_acceleration; btVector3FloatData m_invInertiaLocal; btVector3FloatData m_totalForce; @@ -705,7 +710,7 @@ struct btRigidBodyDoubleData btVector3DoubleData m_angularVelocity; btVector3DoubleData m_angularFactor; btVector3DoubleData m_linearFactor; - btVector3DoubleData m_gravity; + btVector3DoubleData m_gravity; btVector3DoubleData m_gravity_acceleration; btVector3DoubleData m_invInertiaLocal; btVector3DoubleData m_totalForce; diff --git a/lib/enet/CMakeLists.txt b/lib/enet/CMakeLists.txt index 9cae95a6b..719d2b9ea 100644 --- a/lib/enet/CMakeLists.txt +++ b/lib/enet/CMakeLists.txt @@ -21,6 +21,10 @@ add_library(enet STATIC win32.c ) +if(MINGW) + target_link_libraries(enet wsock32 ws2_32 Winmm) +endif() + #if(WIN32) # find_library(WS2_LIBRARY NAMES "ws2_32" PATHS "C:/Windows/System32") # target_link_libraries(enet ${WS2_LIBRARY}) diff --git a/lib/irrlicht/CMakeLists.txt b/lib/irrlicht/CMakeLists.txt index 17b96e62e..8b5b2132a 100644 --- a/lib/irrlicht/CMakeLists.txt +++ b/lib/irrlicht/CMakeLists.txt @@ -16,6 +16,9 @@ add_definitions(-DNDEBUG=1 -DIRRLICHT_EXPORTS=1 -DPNG_THREAD_UNSAFE_OK -DPNG_NO_ if(MSVC) add_definitions(/D_IRR_STATIC_LIB_) add_definitions(/D_CRT_SECURE_NO_WARNINGS) # Shut up about unsafe stuff +elseif(MINGW) + add_definitions(-D_IRR_STATIC_LIB_) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) # Shut up about unsafe stuff else() set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -Wall -pipe -O3 -fno-exceptions -fstrict-aliasing -fexpensive-optimizations -I/usr/X11R6/include") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pipe -O3 -fno-exceptions -fstrict-aliasing -fexpensive-optimizations -I/usr/X11R6/include") @@ -766,16 +769,16 @@ if(APPLE) source/Irrlicht/MacOSX/AppDelegate.mm source/Irrlicht/MacOSX/CIrrDeviceMacOSX.mm source/Irrlicht/MacOSX/OSXClipboard.mm) - + #list(APPEND CMAKE_C_SOURCE_FILE_EXTENSIONS mm) #set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS cpp) - + set_source_files_properties(source/Irrlicht/MacOSX/AppDelegate.mm PROPERTIES COMPILE_FLAGS "-x objective-c++ -O3 -fno-rtti") set_source_files_properties(source/Irrlicht/MacOSX/AppDelegate.mm PROPERTIES LANGUAGE C) - + set_source_files_properties(source/Irrlicht/MacOSX/CIrrDeviceMacOSX.mm PROPERTIES COMPILE_FLAGS "-x objective-c++ -O3 -fno-rtti") set_source_files_properties(source/Irrlicht/MacOSX/CIrrDeviceMacOSX.mm PROPERTIES LANGUAGE C) - + set_source_files_properties(source/Irrlicht/MacOSX/OSXClipboard.mm PROPERTIES COMPILE_FLAGS "-x objective-c++ -O3 -fno-rtti") set_source_files_properties(source/Irrlicht/MacOSX/OSXClipboard.mm PROPERTIES LANGUAGE C) endif() diff --git a/lib/irrlicht/include/matrix4.h b/lib/irrlicht/include/matrix4.h index 45fe98374..6c04a8308 100644 --- a/lib/irrlicht/include/matrix4.h +++ b/lib/irrlicht/include/matrix4.h @@ -12,6 +12,9 @@ #include "aabbox3d.h" #include "rect.h" #include "irrString.h" +#if defined(WIN32) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)) +#include <intrin.h> +#endif // enable this to keep track of changes to the matrix // and make simpler identity check for seldomly changing matrices @@ -44,6 +47,10 @@ namespace core template <class T> class CMatrix4 { + private: +#if defined(WIN32) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)) + float M_raw[24]; +#endif public: //! Constructor Flags @@ -402,8 +409,12 @@ namespace core bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const; private: +#if defined(WIN32) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)) //! Matrix data, stored in row-major order - T M[16]; + T* M = (T*)((uintptr_t)&M_raw[4] & ~0xF); +#else + T M[16]; +#endif #if defined ( USE_MATRIX_TEST ) //! Flag is this matrix is identity matrix mutable u32 definitelyIdentityMatrix; @@ -658,6 +669,58 @@ namespace core const T *m1 = other_a.M; const T *m2 = other_b.M; +#if defined(WIN32) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)) + // From http://drrobsjournal.blogspot.fr/2012/10/fast-simd-4x4-matrix-multiplication.html + // Use unaligned load/store + + const float *matA = other_a.pointer(); + + const __m128 a = _mm_load_ps(matA); // First row + const __m128 b = _mm_load_ps(&matA[4]); // Second row + const __m128 c = _mm_load_ps(&matA[8]); // Third row + const __m128 d = _mm_load_ps(&matA[12]); // Fourth row + + __m128 t1 = _mm_set1_ps(m2[0]); + __m128 t2 = _mm_mul_ps(a, t1); + t1 = _mm_set1_ps(m2[1]); + t2 = _mm_add_ps(_mm_mul_ps(b, t1), t2); + t1 = _mm_set1_ps(m2[2]); + t2 = _mm_add_ps(_mm_mul_ps(c, t1), t2); + t1 = _mm_set1_ps(m2[3]); + t2 = _mm_add_ps(_mm_mul_ps(d, t1), t2); + _mm_store_ps(&M[0], t2); + + t1 = _mm_set1_ps(m2[4]); + t2 = _mm_mul_ps(a, t1); + t1 = _mm_set1_ps(m2[5]); + t2 = _mm_add_ps(_mm_mul_ps(b, t1), t2); + t1 = _mm_set1_ps(m2[6]); + t2 = _mm_add_ps(_mm_mul_ps(c, t1), t2); + t1 = _mm_set1_ps(m2[7]); + t2 = _mm_add_ps(_mm_mul_ps(d, t1), t2); + _mm_store_ps(&M[4], t2); + + t1 = _mm_set1_ps(m2[8]); + t2 = _mm_mul_ps(a, t1); + t1 = _mm_set1_ps(m2[9]); + t2 = _mm_add_ps(_mm_mul_ps(b, t1), t2); + t1 = _mm_set1_ps(m2[10]); + t2 = _mm_add_ps(_mm_mul_ps(c, t1), t2); + t1 = _mm_set1_ps(m2[11]); + t2 = _mm_add_ps(_mm_mul_ps(d, t1), t2); + _mm_store_ps(&M[8], t2); + + t1 = _mm_set1_ps(m2[12]); + t2 = _mm_mul_ps(a, t1); + t1 = _mm_set1_ps(m2[13]); + t2 = _mm_add_ps(_mm_mul_ps(b, t1), t2); + t1 = _mm_set1_ps(m2[14]); + t2 = _mm_add_ps(_mm_mul_ps(c, t1), t2); + t1 = _mm_set1_ps(m2[15]); + t2 = _mm_add_ps(_mm_mul_ps(d, t1), t2); + _mm_store_ps(&M[12], t2); +#else + M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3]; M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3]; M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3]; @@ -679,6 +742,7 @@ namespace core M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15]; #if defined ( USE_MATRIX_TEST ) definitelyIdentityMatrix=false; +#endif #endif return *this; } @@ -1307,20 +1371,110 @@ namespace core template <class T> - inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const - { - /// Calculates the inverse of this Matrix - /// The inverse is calculated using Cramers rule. - /// If no inverse exists then 'false' is returned. + inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const + { + /// Calculates the inverse of this Matrix + /// The inverse is calculated using Cramers rule. + /// If no inverse exists then 'false' is returned. #if defined ( USE_MATRIX_TEST ) - if ( this->isIdentity() ) - { - out=*this; - return true; - } + if ( this->isIdentity() ) + { + out=*this; + return true; + } #endif - const CMatrix4<T> &m = *this; + const CMatrix4<T> &m = *this; +#if defined(WIN32) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)) + float *src = (float*)m.pointer(); + float *dst = (float*)out.pointer(); + // from http://www.intel.com/design/pentiumiii/sml/245043.htm + { + __m128 minor0 = {}, minor1 = {}, minor2 = {}, minor3 = {}; + __m128 row0 = {}, row1 = {}, row2 = {}, row3 = {}; + __m128 det = {}, tmp1 = {}; + tmp1 = _mm_loadh_pi(_mm_loadl_pi(tmp1, (__m64*)(src)), (__m64*)(src + 4)); + row1 = _mm_loadh_pi(_mm_loadl_pi(row1, (__m64*)(src + 8)), (__m64*)(src + 12)); + row0 = _mm_shuffle_ps(tmp1, row1, 0x88); + row1 = _mm_shuffle_ps(row1, tmp1, 0xDD); + tmp1 = _mm_loadh_pi(_mm_loadl_pi(tmp1, (__m64*)(src + 2)), (__m64*)(src + 6)); + row3 = _mm_loadh_pi(_mm_loadl_pi(row3, (__m64*)(src + 10)), (__m64*)(src + 14)); + row2 = _mm_shuffle_ps(tmp1, row3, 0x88); + row3 = _mm_shuffle_ps(row3, tmp1, 0xDD); + // ----------------------------------------------- + tmp1 = _mm_mul_ps(row2, row3); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1); + minor0 = _mm_mul_ps(row1, tmp1); + minor1 = _mm_mul_ps(row0, tmp1); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E); + minor0 = _mm_sub_ps(_mm_mul_ps(row1, tmp1), minor0); + minor1 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor1); + minor1 = _mm_shuffle_ps(minor1, minor1, 0x4E); + // ----------------------------------------------- + tmp1 = _mm_mul_ps(row1, row2); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1); + minor0 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor0); + minor3 = _mm_mul_ps(row0, tmp1); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E); + minor0 = _mm_sub_ps(minor0, _mm_mul_ps(row3, tmp1)); + minor3 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor3); + minor3 = _mm_shuffle_ps(minor3, minor3, 0x4E); + // ----------------------------------------------- + tmp1 = _mm_mul_ps(_mm_shuffle_ps(row1, row1, 0x4E), row3); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1); + row2 = _mm_shuffle_ps(row2, row2, 0x4E); + minor0 = _mm_add_ps(_mm_mul_ps(row2, tmp1), minor0); + minor2 = _mm_mul_ps(row0, tmp1); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E); + minor0 = _mm_sub_ps(minor0, _mm_mul_ps(row2, tmp1)); + minor2 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor2); + minor2 = _mm_shuffle_ps(minor2, minor2, 0x4E); + // ----------------------------------------------- + tmp1 = _mm_mul_ps(row0, row1); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1); + minor2 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor2); + minor3 = _mm_sub_ps(_mm_mul_ps(row2, tmp1), minor3); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E); + minor2 = _mm_sub_ps(_mm_mul_ps(row3, tmp1), minor2); + minor3 = _mm_sub_ps(minor3, _mm_mul_ps(row2, tmp1)); + // ----------------------------------------------- + tmp1 = _mm_mul_ps(row0, row3); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1); + minor1 = _mm_sub_ps(minor1, _mm_mul_ps(row2, tmp1)); + minor2 = _mm_add_ps(_mm_mul_ps(row1, tmp1), minor2); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E); + minor1 = _mm_add_ps(_mm_mul_ps(row2, tmp1), minor1); + minor2 = _mm_sub_ps(minor2, _mm_mul_ps(row1, tmp1)); + // ----------------------------------------------- + tmp1 = _mm_mul_ps(row0, row2); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1); + minor1 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor1); + minor3 = _mm_sub_ps(minor3, _mm_mul_ps(row1, tmp1)); + tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E); + minor1 = _mm_sub_ps(minor1, _mm_mul_ps(row3, tmp1)); + minor3 = _mm_add_ps(_mm_mul_ps(row1, tmp1), minor3); + // ----------------------------------------------- + det = _mm_mul_ps(row0, minor0); + det = _mm_add_ps(_mm_shuffle_ps(det, det, 0x4E), det); + det = _mm_add_ss(_mm_shuffle_ps(det, det, 0xB1), det); + tmp1 = _mm_rcp_ss(det); + det = _mm_sub_ss(_mm_add_ss(tmp1, tmp1), _mm_mul_ss(det, _mm_mul_ss(tmp1, tmp1))); + det = _mm_shuffle_ps(det, det, 0x00); + minor0 = _mm_mul_ps(det, minor0); + _mm_storel_pi((__m64*)(dst), minor0); + _mm_storeh_pi((__m64*)(dst + 2), minor0); + minor1 = _mm_mul_ps(det, minor1); + _mm_storel_pi((__m64*)(dst + 4), minor1); + _mm_storeh_pi((__m64*)(dst + 6), minor1); + minor2 = _mm_mul_ps(det, minor2); + _mm_storel_pi((__m64*)(dst + 8), minor2); + _mm_storeh_pi((__m64*)(dst + 10), minor2); + minor3 = _mm_mul_ps(det, minor3); + _mm_storel_pi((__m64*)(dst + 12), minor3); + _mm_storeh_pi((__m64*)(dst + 14), minor3); + } + return true; +#else f32 d = (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) - (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) + @@ -1387,6 +1541,7 @@ namespace core out.definitelyIdentityMatrix = definitelyIdentityMatrix; #endif return true; +#endif } diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp b/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp index f780938da..b5423ca57 100644 --- a/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.cpp @@ -194,7 +194,7 @@ CIrrDeviceLinux::~CIrrDeviceLinux() } // Reset fullscreen resolution change - switchToFullscreen(true); + restoreResolution(); if (!ExternalWindow) { @@ -235,43 +235,62 @@ int IrrPrintXError(Display *display, XErrorEvent *event) } #endif - -bool CIrrDeviceLinux::switchToFullscreen(bool reset) +bool CIrrDeviceLinux::restoreResolution() { if (!CreationParams.Fullscreen) return true; - if (reset) + + #ifdef _IRR_LINUX_X11_VIDMODE_ + if (UseXVidMode && CreationParams.Fullscreen) { - #ifdef _IRR_LINUX_X11_VIDMODE_ - if (UseXVidMode && CreationParams.Fullscreen) - { - XF86VidModeSwitchToMode(display, screennr, &oldVideoMode); - XF86VidModeSetViewPort(display, screennr, 0, 0); - } - #endif - #ifdef _IRR_LINUX_X11_RANDR_ - if (UseXRandR && CreationParams.Fullscreen) - { - XRRScreenResources* res = XRRGetScreenResources(display, DefaultRootWindow(display)); - XRROutputInfo* output = XRRGetOutputInfo(display, res, output_id); - XRRCrtcInfo* crtc = XRRGetCrtcInfo(display, res, output->crtc); - - Status s = XRRSetCrtcConfig(display, res, output->crtc, CurrentTime, - crtc->x, crtc->y, old_mode, - crtc->rotation, &output_id, 1); - - XRRFreeOutputInfo(output); - XRRFreeCrtcInfo(crtc); - XRRFreeScreenResources(res); - - if (s != Success) - return false; - } - #endif - return true; + XF86VidModeSwitchToMode(display, screennr, &oldVideoMode); + XF86VidModeSetViewPort(display, screennr, 0, 0); } + #endif + #ifdef _IRR_LINUX_X11_RANDR_ + if (UseXRandR && CreationParams.Fullscreen && old_mode != BadRRMode) + { + XRRScreenResources* res = XRRGetScreenResources(display, DefaultRootWindow(display)); + if (!res) + return false; + + XRROutputInfo* output = XRRGetOutputInfo(display, res, output_id); + if (!output || !output->crtc || output->connection == RR_Disconnected) + { + XRRFreeOutputInfo(output); + return false; + } + + XRRCrtcInfo* crtc = XRRGetCrtcInfo(display, res, output->crtc); + if (!crtc) + { + XRRFreeOutputInfo(output); + return false; + } + + Status s = XRRSetCrtcConfig(display, res, output->crtc, CurrentTime, + crtc->x, crtc->y, old_mode, + crtc->rotation, &output_id, 1); + + XRRFreeOutputInfo(output); + XRRFreeCrtcInfo(crtc); + XRRFreeScreenResources(res); + + if (s != Success) + return false; + } + #endif + return true; +} + + +bool CIrrDeviceLinux::changeResolution() +{ + if (!CreationParams.Fullscreen) + return true; getVideoModeList(); + #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_) s32 eventbase, errorbase; s32 bestMode = -1; @@ -333,47 +352,56 @@ bool CIrrDeviceLinux::switchToFullscreen(bool reset) XFree(modes); } - else #endif #ifdef _IRR_LINUX_X11_RANDR_ - if (XRRQueryExtension(display, &eventbase, &errorbase)) + while (XRRQueryExtension(display, &eventbase, &errorbase)) { - XRRScreenResources* res = XRRGetScreenResources(display, DefaultRootWindow(display)); + if (output_id == BadRROutput) + break; + XRRScreenResources* res = XRRGetScreenResources(display, DefaultRootWindow(display)); if (!res) - { - CreationParams.Fullscreen = false; - return CreationParams.Fullscreen; - } + break; XRROutputInfo* output = XRRGetOutputInfo(display, res, output_id); + if (!output || !output->crtc || output->connection == RR_Disconnected) + { + XRRFreeOutputInfo(output); + XRRFreeScreenResources(res); + break; + } + XRRCrtcInfo* crtc = XRRGetCrtcInfo(display, res, output->crtc); + if (!crtc) + { + XRRFreeOutputInfo(output); + XRRFreeScreenResources(res); + break; + } + float refresh_rate, refresh_rate_new; - unsigned int mode0_width = -1, mode0_height = -1; + core::dimension2d<u32> mode0_size = core::dimension2d<u32>(0, 0); for (int i = 0; i < res->nmode; i++) { const XRRModeInfo* mode = &res->modes[i]; - unsigned int w, h; - + core::dimension2d<u32> size; + if (crtc->rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) { - w = mode->height; - h = mode->width; + size = core::dimension2d<u32>(mode->height, mode->width); } else { - w = mode->width; - h = mode->height; + size = core::dimension2d<u32>(mode->width, mode->height); } if (bestMode == -1 && mode->id == output->modes[0]) { - mode0_width = w; - mode0_height = h; + mode0_size = size; } - if (bestMode == -1 && w == Width && h == Height) + if (bestMode == -1 && size.Width == Width && size.Height == Height) { for (int j = 0; j < output->nmode; j++) { @@ -385,7 +413,7 @@ bool CIrrDeviceLinux::switchToFullscreen(bool reset) } } } - else if (bestMode != -1 && w == Width && h == Height) + else if (bestMode != -1 && size.Width == Width && size.Height == Height) { refresh_rate_new = (mode->dotClock * 1000.0) / (mode->hTotal * mode->vTotal); @@ -408,33 +436,29 @@ bool CIrrDeviceLinux::switchToFullscreen(bool reset) if (bestMode == -1) { bestMode = 0; - Width = mode0_width; - Height = mode0_height; + Width = mode0_size.Width; + Height = mode0_size.Height; } Status s = XRRSetCrtcConfig(display, res, output->crtc, CurrentTime, crtc->x, crtc->y, output->modes[bestMode], crtc->rotation, &output_id, 1); + + if (s == Success) + UseXRandR = true; XRRFreeCrtcInfo(crtc); XRRFreeOutputInfo(output); XRRFreeScreenResources(res); - - if (s != Success) - { - CreationParams.Fullscreen = false; - return CreationParams.Fullscreen; - } - - UseXRandR=true; + break; } - else - #endif + + if (UseXRandR == false) { - os::Printer::log("VidMode or RandR extension must be installed to allow Irrlicht " - "to switch to fullscreen mode. Running in windowed mode instead.", ELL_WARNING); + os::Printer::log("Could not get video output. Try to run in windowed mode.", ELL_WARNING); CreationParams.Fullscreen = false; } + #endif return CreationParams.Fullscreen; } @@ -549,7 +573,7 @@ bool CIrrDeviceLinux::createWindow() screennr = DefaultScreen(display); - switchToFullscreen(); + changeResolution(); #ifdef _IRR_COMPILE_WITH_OPENGL_ @@ -1592,89 +1616,88 @@ video::IVideoModeList* CIrrDeviceLinux::getVideoModeList() } XFree(modes); } - else #endif #ifdef _IRR_LINUX_X11_RANDR_ - if (XRRQueryExtension(display, &eventbase, &errorbase)) + output_id = BadRROutput; + old_mode = BadRRMode; + + while (XRRQueryExtension(display, &eventbase, &errorbase)) { - XRRScreenResources* res = XRRGetScreenResources(display, DefaultRootWindow(display)); - - if (!res) - return &VideoModeList; - - XRROutputInfo *output = NULL; + XRROutputInfo* output = NULL; XRRCrtcInfo* crtc = NULL; crtc_x = crtc_y = -1; + + XRRScreenResources* res = XRRGetScreenResources(display, DefaultRootWindow(display)); + if (!res) + break; + + RROutput primary_id = XRRGetOutputPrimary(display, DefaultRootWindow(display)); for (int i = 0; i < res->noutput; i++) { - output = XRRGetOutputInfo(display, res, res->outputs[i]); - - if (!output || !output->crtc || output->connection == RR_Disconnected) + XRROutputInfo* output_tmp = XRRGetOutputInfo(display, res, res->outputs[i]); + if (!output_tmp || !output_tmp->crtc || output_tmp->connection == RR_Disconnected) { - XRRFreeOutputInfo(output); + XRRFreeOutputInfo(output_tmp); continue; } - crtc = XRRGetCrtcInfo(display, res, output->crtc); - - if (!crtc) + XRRCrtcInfo* crtc_tmp = XRRGetCrtcInfo(display, res, output_tmp->crtc); + if (!crtc_tmp) + { + XRRFreeOutputInfo(output_tmp); + continue; + } + + if (res->outputs[i] == primary_id || + output_id == BadRROutput || crtc_tmp->x < crtc->x || + (crtc_tmp->x == crtc->x && crtc_tmp->y < crtc->y)) { XRRFreeCrtcInfo(crtc); - XRRFreeOutputInfo(output); - continue; - } - - if (crtc_x == -1 || crtc->x < crtc_x) - { - crtc_x = crtc->x; - crtc_y = crtc->y; + XRRFreeOutputInfo(output); + + output = output_tmp; + crtc = crtc_tmp; output_id = res->outputs[i]; } - else if (crtc_x == crtc->x && crtc->y < crtc_y) + else { - crtc_x = crtc->x; - crtc_y = crtc->y; - output_id = res->outputs[i]; + XRRFreeCrtcInfo(crtc_tmp); + XRRFreeOutputInfo(output_tmp); } - XRRFreeCrtcInfo(crtc); - XRRFreeOutputInfo(output); + if (res->outputs[i] == primary_id) + break; } - output = XRRGetOutputInfo(display, res, output_id); - crtc = XRRGetCrtcInfo(display, res, output->crtc); - - if (crtc == NULL) + if (output_id == BadRROutput) { - XRRFreeCrtcInfo(crtc); - XRRFreeOutputInfo(output); - XRRFreeScreenResources(res); - return &VideoModeList; + os::Printer::log("Could not get video output.", ELL_WARNING); + break; } + + crtc_x = crtc->x; + crtc_y = crtc->y; for (int i = 0; i < res->nmode; i++) { const XRRModeInfo* mode = &res->modes[i]; - unsigned int w, h; + core::dimension2d<u32> size; if (crtc->rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) { - w = mode->height; - h = mode->width; + size = core::dimension2d<u32>(mode->height, mode->width); } else { - w = mode->width; - h = mode->height; + size = core::dimension2d<u32>(mode->width, mode->height); } for (int j = 0; j < output->nmode; j++) { if (mode->id == output->modes[j]) { - VideoModeList.addMode(core::dimension2d<u32>( - w, h), defaultDepth); + VideoModeList.addMode(size, defaultDepth); break; } } @@ -1682,21 +1705,18 @@ video::IVideoModeList* CIrrDeviceLinux::getVideoModeList() if (mode->id == crtc->mode) { old_mode = crtc->mode; - VideoModeList.setDesktop(defaultDepth, - core::dimension2d<u32>(w, h)); + VideoModeList.setDesktop(defaultDepth, size); } } - + XRRFreeCrtcInfo(crtc); XRRFreeOutputInfo(output); - XRRFreeScreenResources(res); + XRRFreeScreenResources(res); + break; } - else #endif - { - os::Printer::log("VidMode or RandR X11 extension requireed for VideoModeList." , ELL_WARNING); - } } + if (display && temporaryDisplay) { XCloseDisplay(display); diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.h b/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.h index e071724de..c808b8ebd 100644 --- a/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.h +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceLinux.h @@ -150,7 +150,8 @@ namespace irr void initXAtoms(); - bool switchToFullscreen(bool reset=false); + bool restoreResolution(); + bool changeResolution(); //! Implementation of the linux cursor control class CCursorControl : public gui::ICursorControl diff --git a/sources.cmake b/sources.cmake index 317927706..574d5aeb7 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,5 +1,6 @@ -# Modify this file to change the last-modified date when you add/remove a file. -# This will then trigger a new cmake run automatically. +# Modify this file to change the last-modified date when you add/remove a file. +# This will then trigger a new cmake run automatically. file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp") file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp") file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") +file(GLOB_RECURSE STK_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${PROJECT_BINARY_DIR}/tmp/*.rc") \ No newline at end of file diff --git a/src/addons/addons_manager.cpp b/src/addons/addons_manager.cpp index e4d24e11f..c83a10dbc 100644 --- a/src/addons/addons_manager.cpp +++ b/src/addons/addons_manager.cpp @@ -114,13 +114,13 @@ void AddonsManager::init(const XMLNode *xml, if (download) { - Log::info("NetworkHttp", "Downloading updated addons.xml"); + Log::info("addons", "Downloading updated addons.xml."); Online::HTTPRequest *download_request = new Online::HTTPRequest("addons.xml"); download_request->setURL(addon_list_url); download_request->executeNow(); if(download_request->hadDownloadError()) { - Log::error("addons", "Error on download addons.xml: %s\n", + Log::error("addons", "Error on download addons.xml: %s.", download_request->getDownloadErrorMessage()); delete download_request; return; @@ -129,12 +129,12 @@ void AddonsManager::init(const XMLNode *xml, UserConfigParams::m_addons_last_updated=StkTime::getTimeSinceEpoch(); } else - Log::info("NetworkHttp", "Using cached addons.xml"); + Log::info("addons", "Using cached addons.xml."); const XMLNode *xml_addons = new XMLNode(filename); addons_manager->initAddons(xml_addons); // will free xml_addons if(UserConfigParams::logAddons()) - Log::info("addons", "Addons manager list downloaded"); + Log::info("addons", "Addons manager list downloaded."); } // init // ---------------------------------------------------------------------------- @@ -195,7 +195,7 @@ void AddonsManager::initAddons(const XMLNode *xml) if(file_manager->fileExists(full_path)) { if(UserConfigParams::logAddons()) - Log::warn("[AddonsManager] Removing cached icon '%s'.\n", + Log::warn("addons", "Removing cached icon '%s'.", addon.getIconBasename().c_str()); file_manager->removeFile(full_path); } @@ -226,9 +226,9 @@ void AddonsManager::initAddons(const XMLNode *xml) } else { - Log::error("[AddonsManager]", "Found invalid node '%s' while downloading addons.", + Log::error("addons", "Found invalid node '%s' while downloading addons.", node->getName().c_str()); - Log::error("[AddonsManager]", "Ignored."); + Log::error("addons", "Ignored."); } } // for i<xml->getNumNodes delete xml; @@ -254,7 +254,7 @@ void AddonsManager::initAddons(const XMLNode *xml) // it from the list. if(UserConfigParams::logAddons()) Log::warn( - "[AddonsManager] Removing '%s' which is not on the server anymore.\n", + "addons", "Removing '%s' which is not on the server anymore.", m_addons_list.getData()[i].getId().c_str() ); const std::string &icon = m_addons_list.getData()[i].getIconBasename(); std::string icon_file =file_manager->getAddonsFile("icons/"+icon); @@ -311,7 +311,7 @@ void AddonsManager::checkInstalledAddons() if(n<0) continue; if(!m_addons_list.getData()[n].isInstalled()) { - Log::info("[AddonsManager] Marking '%s' as being installed.", + Log::info("addons", "Marking '%s' as being installed.", kp->getIdent().c_str()); m_addons_list.getData()[n].setInstalled(true); something_was_changed = true; @@ -330,7 +330,7 @@ void AddonsManager::checkInstalledAddons() if(n<0) continue; if(!m_addons_list.getData()[n].isInstalled()) { - Log::info("[AddonsManager] Marking '%s' as being installed.", + Log::info("addons", "Marking '%s' as being installed.", track->getIdent().c_str()); m_addons_list.getData()[n].setInstalled(true); something_was_changed = true; @@ -361,7 +361,7 @@ void AddonsManager::downloadIcons() if(icon=="") { if(UserConfigParams::logAddons()) - Log::error("[AddonsManager]", "No icon or image specified for '%s'.", + Log::error("addons", "No icon or image specified for '%s'.", addon.getId().c_str()); continue; } @@ -400,7 +400,7 @@ void AddonsManager::loadInstalledAddons() /* checking for installed addons */ if(UserConfigParams::logAddons()) { - Log::info("[AddonsManager]", "Loading an xml file for installed addons: %s", + Log::info("addons", "Loading an xml file for installed addons: %s.", m_file_installed.c_str()); } const XMLNode *xml = file_manager->createXMLTree(m_file_installed); @@ -478,15 +478,15 @@ bool AddonsManager::install(const Addon &addon) if (!success) { // TODO: show a message in the interface - Log::error("[AddonsManager]", "Failed to unzip '%s' to '%s'", + Log::error("addons", "Failed to unzip '%s' to '%s'.", from.c_str(), to.c_str()); - Log::error("[AddonsManager]", "Zip file will not be removed."); + Log::error("addons", "Zip file will not be removed."); return false; } if(!file_manager->removeFile(from)) { - Log::error("[AddonsManager]", "Problems removing temporary file '%s'", + Log::error("addons", "Problems removing temporary file '%s'.", from.c_str()); } @@ -520,7 +520,7 @@ bool AddonsManager::install(const Addon &addon) } catch (std::exception& e) { - Log::error("[AddonsManager]", "ERROR: Cannot load track <%s> : %s", + Log::error("addons", "Cannot load track '%s' : %s.", addon.getDataDir().c_str(), e.what()); } } @@ -535,8 +535,8 @@ bool AddonsManager::install(const Addon &addon) */ bool AddonsManager::uninstall(const Addon &addon) { - Log::info("[AddonsManager]", "Uninstalling <%s>", - core::stringc(addon.getName()).c_str()); + Log::info("addons", "Uninstalling '%s'.", + core::stringc(addon.getName()).c_str()); // addon is a const reference, and to avoid removing the const, we // find the proper index again to modify the installed state diff --git a/src/challenges/challenge_data.cpp b/src/challenges/challenge_data.cpp index a65131611..6d0d0514a 100644 --- a/src/challenges/challenge_data.cpp +++ b/src/challenges/challenge_data.cpp @@ -376,7 +376,7 @@ void ChallengeData::setRace(RaceManager::Difficulty d) const else if(m_mode==CM_GRAND_PRIX) { race_manager->setMinorMode(m_minor); - race_manager->setGrandPrix(grand_prix_manager->getGrandPrix(m_gp_id)); + race_manager->setGrandPrix(*grand_prix_manager->getGrandPrix(m_gp_id)); race_manager->setDifficulty(d); race_manager->setNumKarts(m_num_karts[d]); race_manager->setNumLocalPlayers(1); diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index ae91e0b4d..c2f787b42 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -464,6 +464,9 @@ namespace UserConfigParams PARAM_PREFIX BoolUserConfigParam m_gi PARAM_DEFAULT(BoolUserConfigParam(false, "enable_gi", &m_video_group, "Enable Global Illumination")); + PARAM_PREFIX BoolUserConfigParam m_azdo + PARAM_DEFAULT(BoolUserConfigParam(false, "enable_azdo", + &m_video_group, "Enable 'Approaching Zero Driver Overhead' mode (very experimental !)")); // ---- Debug - not saved to config file /** If gamepad debugging is enabled. */ diff --git a/src/graphics/camera.cpp b/src/graphics/camera.cpp index 547add4f9..9648c0372 100644 --- a/src/graphics/camera.cpp +++ b/src/graphics/camera.cpp @@ -24,7 +24,6 @@ #include "audio/music_manager.hpp" #include "config/user_config.hpp" #include "graphics/irr_driver.hpp" -#include "graphics/rain.hpp" #include "io/xml_node.hpp" #include "karts/abstract_kart.hpp" #include "karts/explosion_animation.hpp" @@ -52,7 +51,6 @@ Camera::Camera(int camera_index, AbstractKart* kart) : m_kart(NULL) { m_mode = CM_NORMAL; m_index = camera_index; - m_rain = NULL; m_original_kart = kart; m_camera = irr_driver->addCameraSceneNode(); @@ -92,7 +90,6 @@ Camera::Camera(int camera_index, AbstractKart* kart) : m_kart(NULL) */ Camera::~Camera() { - if(m_rain) delete m_rain; irr_driver->removeCameraSceneNode(m_camera); if (s_active_camera == this) @@ -222,13 +219,6 @@ void Camera::setupCamera() m_camera->setFOV(m_fov); m_camera->setAspectRatio(m_aspect); m_camera->setFarValue(World::getWorld()->getTrack()->getCameraFar()); - - if (UserConfigParams::m_weather_effects && - World::getWorld()->getTrack()->getWeatherType() == WEATHER_RAIN) - { - m_rain = new Rain(this, NULL); - } - } // setupCamera // ---------------------------------------------------------------------------- @@ -530,12 +520,6 @@ void Camera::update(float dt) getCameraSettings(&above_kart, &cam_angle, &side_way, &distance, &smoothing); positionCamera(dt, above_kart, cam_angle, side_way, distance, smoothing); } - - if (UserConfigParams::m_graphical_effects && m_rain) - { - m_rain->setPosition( getCameraSceneNode()->getPosition() ); - m_rain->update(dt); - } // UserConfigParams::m_graphical_effects } // update // ---------------------------------------------------------------------------- diff --git a/src/graphics/camera.hpp b/src/graphics/camera.hpp index 7cf5b15a9..db5937a89 100644 --- a/src/graphics/camera.hpp +++ b/src/graphics/camera.hpp @@ -41,7 +41,6 @@ namespace irr using namespace irr; class AbstractKart; -class Rain; /** * \brief Handles the game camera @@ -120,10 +119,6 @@ private: /** List of all cameras. */ static std::vector<Camera*> m_all_cameras; - /** Used to show rain graphical effects. */ - Rain *m_rain; - - /** A class that stores information about the different end cameras * which can be specified in the scene.xml file. */ class EndCameraInformation diff --git a/src/graphics/gl_headers.hpp b/src/graphics/gl_headers.hpp new file mode 100644 index 000000000..50069f23f --- /dev/null +++ b/src/graphics/gl_headers.hpp @@ -0,0 +1,46 @@ +#ifndef GL_HEADER_HPP +#define GL_HEADER_HPP + +#define GLEW_STATIC +extern "C" { +#include <GL/glew.h> +} +#include <cinttypes> + +#if defined(__APPLE__) +# include <OpenGL/gl.h> +# include <OpenGL/gl3.h> +# define OGL32CTX +# ifdef GL_ARB_instanced_arrays +# define glVertexAttribDivisor glVertexAttribDivisorARB +# endif +# ifndef GL_TEXTURE_SWIZZLE_RGBA +# define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +# endif +#elif defined(ANDROID) +# include <GLES/gl.h> +#elif defined(WIN32) +# define _WINSOCKAPI_ +# include <windows.h> +#else +#define GL_GLEXT_PROTOTYPES +#define DEBUG_OUTPUT_DECLARED +# include <GL/gl.h> +# include <GL/glext.h> +#endif + +#define Bindless_Texture_Support +#define Base_Instance_Support +#define Buffer_Storage +#define Multi_Draw_Indirect +#define Draw_Indirect + +struct DrawElementsIndirectCommand{ + GLuint count; + GLuint instanceCount; + GLuint firstIndex; + GLuint baseVertex; + GLuint baseInstance; +}; + +#endif \ No newline at end of file diff --git a/src/graphics/glwrap.cpp b/src/graphics/glwrap.cpp index 7387b9d8f..7c7975fbd 100644 --- a/src/graphics/glwrap.cpp +++ b/src/graphics/glwrap.cpp @@ -3,92 +3,16 @@ #include <string> #include "config/user_config.hpp" #include "utils/profiler.hpp" +#include "utils/cpp2011.hpp" +#include "graphics/stkmesh.hpp" -#ifdef _IRR_WINDOWS_API_ -#define IRR_OGL_LOAD_EXTENSION(X) wglGetProcAddress(reinterpret_cast<const char*>(X)) -PFNGLGENTRANSFORMFEEDBACKSPROC glGenTransformFeedbacks; -PFNGLBINDTRANSFORMFEEDBACKPROC glBindTransformFeedback; -PFNGLDRAWTRANSFORMFEEDBACKPROC glDrawTransformFeedback; -PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; -PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; -PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; -PFNGLBINDBUFFERBASEPROC glBindBufferBase; -PFNGLGENBUFFERSPROC glGenBuffers; -PFNGLBINDBUFFERPROC glBindBuffer; -PFNGLBUFFERDATAPROC glBufferData; -PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; -PFNGLCREATESHADERPROC glCreateShader; -PFNGLCOMPILESHADERPROC glCompileShader; -PFNGLSHADERSOURCEPROC glShaderSource; -PFNGLCREATEPROGRAMPROC glCreateProgram; -PFNGLATTACHSHADERPROC glAttachShader; -PFNGLLINKPROGRAMPROC glLinkProgram; -PFNGLUSEPROGRAMPROC glUseProgram; -PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; -PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; -PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; -PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; -PFNGLUNIFORM1FPROC glUniform1f; -PFNGLUNIFORM3FPROC glUniform3f; -PFNGLDELETESHADERPROC glDeleteShader; -PFNGLGETSHADERIVPROC glGetShaderiv; -PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; -PFNGLACTIVETEXTUREPROC glActiveTexture; -PFNGLUNIFORM2FPROC glUniform2f; -PFNGLUNIFORM1IPROC glUniform1i; -PFNGLUNIFORM3IPROC glUniform3i; -PFNGLUNIFORM4IPROC glUniform4i; -PFNGLUNIFORM1FVPROC glUniform1fv; -PFNGLUNIFORM4FVPROC glUniform4fv; -PFNGLGETPROGRAMIVPROC glGetProgramiv; -PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; -PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; -PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; -PFNGLBLENDEQUATIONPROC glBlendEquation; -PFNGLVERTEXATTRIBDIVISORPROC glVertexAttribDivisor; -PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced; -PFNGLDRAWELEMENTSBASEVERTEXPROC glDrawElementsBaseVertex; -PFNGLDRAWELEMENTSINSTANCEDPROC glDrawElementsInstanced; -PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glDrawElementsInstancedBaseVertex; -PFNGLDELETEBUFFERSPROC glDeleteBuffers; -PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; -PFNGLBINDVERTEXARRAYPROC glBindVertexArray; -PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; -PFNGLTEXBUFFERPROC glTexBuffer; -PFNGLBUFFERSUBDATAPROC glBufferSubData; -PFNGLMAPBUFFERPROC glMapBuffer; -PFNGLMAPBUFFERRANGEPROC glMapBufferRange; -PFNGLUNMAPBUFFERPROC glUnmapBuffer; -PFNGLFENCESYNCPROC glFenceSync; -PFNGLCLIENTWAITSYNCPROC glClientWaitSync; -PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer; -PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB; -PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; -PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; -PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; -PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; -PFNGLFRAMEBUFFERTEXTUREPROC glFramebufferTexture; -PFNGLTEXIMAGE3DPROC glTexImage3D; -PFNGLGENERATEMIPMAPPROC glGenerateMipmap; -PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; -PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample; -PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer; -PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex; -PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding; -PFNGLBLENDCOLORPROC glBlendColor; -PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D; -PFNGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage; -PFNGLTEXSTORAGE1DPROC glTexStorage1D; -PFNGLTEXSTORAGE2DPROC glTexStorage2D; -PFNGLTEXSTORAGE3DPROC glTexStorage3D; -PFNGLBINDIMAGETEXTUREPROC glBindImageTexture; -PFNGLDISPATCHCOMPUTEPROC glDispatchCompute; -#endif + +#include "../../lib/irrlicht/source/Irrlicht/COpenGLTexture.h" static bool is_gl_init = false; #ifdef DEBUG -#ifdef WIN32 +#if !defined(__APPLE__) #define ARB_DEBUG_OUTPUT #endif #endif @@ -101,9 +25,11 @@ CALLBACK debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* msg, const void *userparam) { +#ifdef GL_DEBUG_SEVERITY_NOTIFICATION // ignore minor notifications sent by some drivers (notably the nvidia one) if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) return; +#endif switch(source) { @@ -172,87 +98,10 @@ void initGL() if (is_gl_init) return; is_gl_init = true; -#ifdef _IRR_WINDOWS_API_ - glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC)IRR_OGL_LOAD_EXTENSION("glGenTransformFeedbacks"); - glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC)IRR_OGL_LOAD_EXTENSION("glBindTransformFeedback"); - glDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC)IRR_OGL_LOAD_EXTENSION("glDrawTransformFeedback"); - glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)IRR_OGL_LOAD_EXTENSION("glBeginTransformFeedback"); - glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)IRR_OGL_LOAD_EXTENSION("glEndTransformFeedback"); - glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)IRR_OGL_LOAD_EXTENSION("glBindBufferBase"); - glGenBuffers = (PFNGLGENBUFFERSPROC)IRR_OGL_LOAD_EXTENSION("glGenBuffers"); - glBindBuffer = (PFNGLBINDBUFFERPROC)IRR_OGL_LOAD_EXTENSION("glBindBuffer"); - glBufferData = (PFNGLBUFFERDATAPROC)IRR_OGL_LOAD_EXTENSION("glBufferData"); - glMapBuffer = (PFNGLMAPBUFFERPROC)IRR_OGL_LOAD_EXTENSION("glMapBuffer"); - glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)IRR_OGL_LOAD_EXTENSION("glMapBufferRange"); - glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)IRR_OGL_LOAD_EXTENSION("glUnmapBuffer"); - glFenceSync = (PFNGLFENCESYNCPROC)IRR_OGL_LOAD_EXTENSION("glFenceSync"); - glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)IRR_OGL_LOAD_EXTENSION("glClientWaitSync"); - glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)IRR_OGL_LOAD_EXTENSION("glVertexAttribPointer"); - glCreateShader = (PFNGLCREATESHADERPROC)IRR_OGL_LOAD_EXTENSION("glCreateShader"); - glCompileShader = (PFNGLCOMPILESHADERPROC)IRR_OGL_LOAD_EXTENSION("glCompileShader"); - glShaderSource = (PFNGLSHADERSOURCEPROC)IRR_OGL_LOAD_EXTENSION("glShaderSource"); - glCreateProgram = (PFNGLCREATEPROGRAMPROC)IRR_OGL_LOAD_EXTENSION("glCreateProgram"); - glAttachShader = (PFNGLATTACHSHADERPROC)IRR_OGL_LOAD_EXTENSION("glAttachShader"); - glLinkProgram = (PFNGLLINKPROGRAMPROC)IRR_OGL_LOAD_EXTENSION("glLinkProgram"); - glUseProgram = (PFNGLUSEPROGRAMPROC)IRR_OGL_LOAD_EXTENSION("glUseProgram"); - glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)IRR_OGL_LOAD_EXTENSION("glEnableVertexAttribArray"); - glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)IRR_OGL_LOAD_EXTENSION("glGetUniformLocation"); - glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)IRR_OGL_LOAD_EXTENSION("glUniformMatrix4fv"); - glUniform1f = (PFNGLUNIFORM1FPROC)IRR_OGL_LOAD_EXTENSION("glUniform1f"); - glUniform3f = (PFNGLUNIFORM3FPROC)IRR_OGL_LOAD_EXTENSION("glUniform3f"); - glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)IRR_OGL_LOAD_EXTENSION("glDisableVertexAttribArray"); - glDeleteShader = (PFNGLDELETESHADERPROC)IRR_OGL_LOAD_EXTENSION("glDeleteShader"); - glGetShaderiv = (PFNGLGETSHADERIVPROC)IRR_OGL_LOAD_EXTENSION("glGetShaderiv"); - glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)IRR_OGL_LOAD_EXTENSION("glGetShaderInfoLog"); - glActiveTexture = (PFNGLACTIVETEXTUREPROC)IRR_OGL_LOAD_EXTENSION("glActiveTexture"); - glUniform2f = (PFNGLUNIFORM2FPROC)IRR_OGL_LOAD_EXTENSION("glUniform2f"); - glUniform4i = (PFNGLUNIFORM4IPROC)IRR_OGL_LOAD_EXTENSION("glUniform4i"); - glUniform3i = (PFNGLUNIFORM3IPROC)IRR_OGL_LOAD_EXTENSION("glUniform3i"); - glUniform1i = (PFNGLUNIFORM1IPROC)IRR_OGL_LOAD_EXTENSION("glUniform1i"); - glGetProgramiv = (PFNGLGETPROGRAMIVPROC)IRR_OGL_LOAD_EXTENSION("glGetProgramiv"); - glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)IRR_OGL_LOAD_EXTENSION("glGetProgramInfoLog"); - glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)IRR_OGL_LOAD_EXTENSION("glTransformFeedbackVaryings"); - glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)IRR_OGL_LOAD_EXTENSION("glGetAttribLocation"); - glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)IRR_OGL_LOAD_EXTENSION("glBindAttribLocation"); - glBlendEquation = (PFNGLBLENDEQUATIONPROC)IRR_OGL_LOAD_EXTENSION("glBlendEquation"); - glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)IRR_OGL_LOAD_EXTENSION("glVertexAttribDivisor"); - glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)IRR_OGL_LOAD_EXTENSION("glDrawArraysInstanced"); - glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)IRR_OGL_LOAD_EXTENSION("glDrawElementsBaseVertex"); - glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)IRR_OGL_LOAD_EXTENSION("glDrawElementsInstanced"); - glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)IRR_OGL_LOAD_EXTENSION("glDrawElementsInstancedBaseVertex"); - glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)IRR_OGL_LOAD_EXTENSION("glDeleteBuffers"); - glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)IRR_OGL_LOAD_EXTENSION("glGenVertexArrays"); - glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)IRR_OGL_LOAD_EXTENSION("glBindVertexArray"); - glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)IRR_OGL_LOAD_EXTENSION("glDeleteVertexArrays"); - glTexBuffer = (PFNGLTEXBUFFERPROC)IRR_OGL_LOAD_EXTENSION("glTexBuffer"); - glUniform1fv = (PFNGLUNIFORM1FVPROC)IRR_OGL_LOAD_EXTENSION("glUniform1fv"); - glUniform4fv = (PFNGLUNIFORM4FVPROC)IRR_OGL_LOAD_EXTENSION("glUniform4fv"); - glBufferSubData = (PFNGLBUFFERSUBDATAPROC)IRR_OGL_LOAD_EXTENSION("glBufferSubData"); - glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)IRR_OGL_LOAD_EXTENSION("glVertexAttribIPointer"); - glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)IRR_OGL_LOAD_EXTENSION("glGenFramebuffers"); - glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)IRR_OGL_LOAD_EXTENSION("glDeleteFramebuffers"); - glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)IRR_OGL_LOAD_EXTENSION("glBindFramebuffer"); - glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)IRR_OGL_LOAD_EXTENSION("glFramebufferTexture2D"); - glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)IRR_OGL_LOAD_EXTENSION("glFramebufferTexture"); - glTexImage3D = (PFNGLTEXIMAGE3DPROC)IRR_OGL_LOAD_EXTENSION("glTexImage3D"); - glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)IRR_OGL_LOAD_EXTENSION("glGenerateMipmap"); - glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)IRR_OGL_LOAD_EXTENSION("glCheckFramebufferStatus"); - glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)IRR_OGL_LOAD_EXTENSION("glTexImage2DMultisample"); - glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)IRR_OGL_LOAD_EXTENSION("glBlitFramebuffer"); - glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)IRR_OGL_LOAD_EXTENSION("glGetUniformBlockIndex"); - glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)IRR_OGL_LOAD_EXTENSION("glUniformBlockBinding"); - glBlendColor = (PFNGLBLENDCOLORPROC)IRR_OGL_LOAD_EXTENSION("glBlendColor"); - glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)IRR_OGL_LOAD_EXTENSION("glCompressedTexImage2D"); - glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)IRR_OGL_LOAD_EXTENSION("glGetCompressedTexImage"); - glTexStorage1D = (PFNGLTEXSTORAGE1DPROC)IRR_OGL_LOAD_EXTENSION("glTexStorage1D"); - glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)IRR_OGL_LOAD_EXTENSION("glTexStorage2D"); - glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)IRR_OGL_LOAD_EXTENSION("glTexStorage3D"); - glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)IRR_OGL_LOAD_EXTENSION("glBindImageTexture"); - glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC)IRR_OGL_LOAD_EXTENSION("glDispatchCompute"); -#ifdef DEBUG - glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)IRR_OGL_LOAD_EXTENSION("glDebugMessageCallbackARB"); -#endif -#endif + glewExperimental = GL_TRUE; + GLenum err = glewInit(); + if (GLEW_OK != err) + Log::fatal("GLEW", "Glew initialisation failed with error %s", glewGetErrorString(err)); #ifdef ARB_DEBUG_OUTPUT if (glDebugMessageCallbackARB) glDebugMessageCallbackARB((GLDEBUGPROCARB)debugCallback, NULL); @@ -282,12 +131,21 @@ GLuint LoadShader(const char * file, unsigned type) char versionString[20]; sprintf(versionString, "#version %d\n", irr_driver->getGLSLVersion()); std::string Code = versionString; + if (UserConfigParams::m_azdo) + Code += "#extension GL_ARB_bindless_texture : enable\n"; + else + { + Code += "#extension GL_ARB_bindless_texture : disable\n"; + Code += "#undef GL_ARB_bindless_texture\n"; + } std::ifstream Stream(file, std::ios::in); Code += "//" + std::string(file) + "\n"; if (irr_driver->needUBOWorkaround()) Code += "#define UBO_DISABLED\n"; if (irr_driver->hasVSLayerExtension()) Code += "#define VSLayer\n"; + if (irr_driver->needsRGBBindlessWorkaround()) + Code += "#define SRGBBindlessFix\n"; Code += LoadHeader(); if (Stream.is_open()) { @@ -539,40 +397,7 @@ void setTexture(unsigned TextureUnit, GLuint TextureId, GLenum MagFilter, GLenum glGetError(); } -class VBOGatherer -{ - enum VTXTYPE { VTXTYPE_STANDARD, VTXTYPE_TCOORD, VTXTYPE_TANGENT, VTXTYPE_COUNT }; - GLuint vbo[VTXTYPE_COUNT], ibo[VTXTYPE_COUNT], vao[VTXTYPE_COUNT]; - std::vector<scene::IMeshBuffer *> storedCPUBuffer[VTXTYPE_COUNT]; - void *vtx_mirror[VTXTYPE_COUNT], *idx_mirror[VTXTYPE_COUNT]; - size_t vtx_cnt[VTXTYPE_COUNT], idx_cnt[VTXTYPE_COUNT]; - std::map<scene::IMeshBuffer*, unsigned> mappedBaseVertex[VTXTYPE_COUNT], mappedBaseIndex[VTXTYPE_COUNT]; - - void regenerateBuffer(enum VTXTYPE); - void regenerateVAO(enum VTXTYPE); - size_t getVertexPitch(enum VTXTYPE) const; - VTXTYPE getVTXTYPE(video::E_VERTEX_TYPE type); - void append(scene::IMeshBuffer *, VBOGatherer::VTXTYPE tp); -public: - VBOGatherer(); - std::pair<unsigned, unsigned> getBase(scene::IMeshBuffer *); - unsigned getVBO(video::E_VERTEX_TYPE type) { return vbo[getVTXTYPE(type)]; } - unsigned getVAO(video::E_VERTEX_TYPE type) { return vao[getVTXTYPE(type)]; } - ~VBOGatherer() - { - for (unsigned i = 0; i < VTXTYPE_COUNT; i++) - { - if (vbo[i]) - glDeleteBuffers(1, &vbo[i]); - if (ibo[i]) - glDeleteBuffers(1, &ibo[i]); - if (vao[i]) - glDeleteVertexArrays(1, &vao[i]); - } - } -}; - -VBOGatherer::VBOGatherer() +VAOManager::VAOManager() { vao[0] = vao[1] = vao[2] = 0; vbo[0] = vbo[1] = vbo[2] = 0; @@ -581,16 +406,81 @@ VBOGatherer::VBOGatherer() idx_cnt[0] = idx_cnt[1] = idx_cnt[2] = 0; vtx_mirror[0] = vtx_mirror[1] = vtx_mirror[2] = NULL; idx_mirror[0] = idx_mirror[1] = idx_mirror[2] = NULL; + instance_count[0] = 0; + + for (unsigned i = 0; i < InstanceTypeCount; i++) + { + glGenBuffers(1, &instance_vbo[i]); + glBindBuffer(GL_ARRAY_BUFFER, instance_vbo[i]); +#ifdef Buffer_Storage + if (irr_driver->hasBufferStorageExtension()) + { + glBufferStorage(GL_ARRAY_BUFFER, 10000 * sizeof(InstanceData), 0, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); + Ptr[i] = glMapBufferRange(GL_ARRAY_BUFFER, 0, 10000 * sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); + } + else +#endif + { + glBufferData(GL_ARRAY_BUFFER, 10000 * sizeof(InstanceData), 0, GL_STREAM_DRAW); + } + } } -void VBOGatherer::regenerateBuffer(enum VTXTYPE tp) +static void cleanVAOMap(std::map<std::pair<video::E_VERTEX_TYPE, InstanceType>, GLuint> Map) +{ + std::map<std::pair<video::E_VERTEX_TYPE, InstanceType>, GLuint>::iterator It = Map.begin(), E = Map.end(); + for (; It != E; It++) + { + glDeleteVertexArrays(1, &(It->second)); + } +} + +void VAOManager::cleanInstanceVAOs() +{ + cleanVAOMap(InstanceVAO); + InstanceVAO.clear(); +} + +VAOManager::~VAOManager() +{ + cleanInstanceVAOs(); + for (unsigned i = 0; i < 3; i++) + { + if (vtx_mirror[i]) + free(vtx_mirror[i]); + if (idx_mirror[i]) + free(idx_mirror[i]); + if (vbo[i]) + glDeleteBuffers(1, &vbo[i]); + if (ibo[i]) + glDeleteBuffers(1, &ibo[i]); + if (vao[i]) + glDeleteVertexArrays(1, &vao[i]); + } + for (unsigned i = 0; i < InstanceTypeCount; i++) + { + glDeleteBuffers(1, &instance_vbo[i]); + } + +} + +void VAOManager::regenerateBuffer(enum VTXTYPE tp) { glBindVertexArray(0); if (vbo[tp]) glDeleteBuffers(1, &vbo[tp]); glGenBuffers(1, &vbo[tp]); glBindBuffer(GL_ARRAY_BUFFER, vbo[tp]); - glBufferData(GL_ARRAY_BUFFER, vtx_cnt[tp] * getVertexPitch(tp), vtx_mirror[tp], GL_DYNAMIC_DRAW); +#ifdef Buffer_Storage + if (irr_driver->hasBufferStorageExtension()) + { + glBufferStorage(GL_ARRAY_BUFFER, vtx_cnt[tp] * getVertexPitch(tp), vtx_mirror[tp], GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); + VBOPtr[tp] = glMapBufferRange(GL_ARRAY_BUFFER, 0, vtx_cnt[tp] * getVertexPitch(tp), GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); + } + else +#endif + glBufferData(GL_ARRAY_BUFFER, vtx_cnt[tp] * getVertexPitch(tp), vtx_mirror[tp], GL_DYNAMIC_DRAW); + if (ibo[tp]) glDeleteBuffers(1, &ibo[tp]); @@ -602,7 +492,7 @@ void VBOGatherer::regenerateBuffer(enum VTXTYPE tp) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } -void VBOGatherer::regenerateVAO(enum VTXTYPE tp) +void VAOManager::regenerateVAO(enum VTXTYPE tp) { if (vao[tp]) glDeleteVertexArrays(1, &vao[tp]); @@ -668,7 +558,100 @@ void VBOGatherer::regenerateVAO(enum VTXTYPE tp) glBindVertexArray(0); } -size_t VBOGatherer::getVertexPitch(enum VTXTYPE tp) const +void VAOManager::regenerateInstancedVAO() +{ + cleanInstanceVAOs(); + + enum video::E_VERTEX_TYPE IrrVT[] = { video::EVT_STANDARD, video::EVT_2TCOORDS, video::EVT_TANGENTS }; + for (unsigned i = 0; i < VTXTYPE_COUNT; i++) + { + video::E_VERTEX_TYPE tp = IrrVT[i]; + if (!vbo[tp] || !ibo[tp]) + continue; + GLuint vao = createVAO(vbo[tp], ibo[tp], tp); + glBindBuffer(GL_ARRAY_BUFFER, instance_vbo[InstanceTypeDefault]); + + glEnableVertexAttribArray(7); + glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), 0); + glVertexAttribDivisor(7, 1); + glEnableVertexAttribArray(8); + glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(3 * sizeof(float))); + glVertexAttribDivisor(8, 1); + glEnableVertexAttribArray(9); + glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(6 * sizeof(float))); + glVertexAttribDivisor(9, 1); + glEnableVertexAttribArray(10); + glVertexAttribIPointer(10, 2, GL_UNSIGNED_INT, sizeof(InstanceData), (GLvoid*)(9 * sizeof(float))); + glVertexAttribDivisor(10, 1); + glEnableVertexAttribArray(11); + glVertexAttribIPointer(11, 2, GL_UNSIGNED_INT, sizeof(InstanceData), (GLvoid*)(9 * sizeof(float) + 2 * sizeof(unsigned))); + glVertexAttribDivisor(11, 1); + InstanceVAO[std::pair<video::E_VERTEX_TYPE, InstanceType>(tp, InstanceTypeDefault)] = vao; + + vao = createVAO(vbo[tp], ibo[tp], tp); + glBindBuffer(GL_ARRAY_BUFFER, instance_vbo[InstanceTypeShadow]); + + glEnableVertexAttribArray(7); + glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), 0); + glVertexAttribDivisor(7, 1); + glEnableVertexAttribArray(8); + glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(3 * sizeof(float))); + glVertexAttribDivisor(8, 1); + glEnableVertexAttribArray(9); + glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(6 * sizeof(float))); + glVertexAttribDivisor(9, 1); + glEnableVertexAttribArray(10); + glVertexAttribIPointer(10, 2, GL_UNSIGNED_INT, sizeof(InstanceData), (GLvoid*)(9 * sizeof(float))); + glVertexAttribDivisor(10, 1); + glEnableVertexAttribArray(11); + glVertexAttribIPointer(11, 2, GL_UNSIGNED_INT, sizeof(InstanceData), (GLvoid*)(9 * sizeof(float) + 2 * sizeof(unsigned))); + glVertexAttribDivisor(11, 1); + InstanceVAO[std::pair<video::E_VERTEX_TYPE, InstanceType>(tp, InstanceTypeShadow)] = vao; + + vao = createVAO(vbo[tp], ibo[tp], tp); + glBindBuffer(GL_ARRAY_BUFFER, instance_vbo[InstanceTypeRSM]); + + glEnableVertexAttribArray(7); + glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), 0); + glVertexAttribDivisor(7, 1); + glEnableVertexAttribArray(8); + glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(3 * sizeof(float))); + glVertexAttribDivisor(8, 1); + glEnableVertexAttribArray(9); + glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (GLvoid*)(6 * sizeof(float))); + glVertexAttribDivisor(9, 1); + glEnableVertexAttribArray(10); + glVertexAttribIPointer(10, 2, GL_UNSIGNED_INT, sizeof(InstanceData), (GLvoid*)(9 * sizeof(float))); + glVertexAttribDivisor(10, 1); + glEnableVertexAttribArray(11); + glVertexAttribIPointer(11, 2, GL_UNSIGNED_INT, sizeof(InstanceData), (GLvoid*)(9 * sizeof(float) + 2 * sizeof(unsigned))); + glVertexAttribDivisor(11, 1); + InstanceVAO[std::pair<video::E_VERTEX_TYPE, InstanceType>(tp, InstanceTypeRSM)] = vao; + + vao = createVAO(vbo[tp], ibo[tp], tp); + glBindBuffer(GL_ARRAY_BUFFER, instance_vbo[InstanceTypeGlow]); + + glEnableVertexAttribArray(7); + glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(GlowInstanceData), 0); + glVertexAttribDivisor(7, 1); + glEnableVertexAttribArray(8); + glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, sizeof(GlowInstanceData), (GLvoid*)(3 * sizeof(float))); + glVertexAttribDivisor(8, 1); + glEnableVertexAttribArray(9); + glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, sizeof(GlowInstanceData), (GLvoid*)(6 * sizeof(float))); + glVertexAttribDivisor(9, 1); + glEnableVertexAttribArray(12); + glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GlowInstanceData), (GLvoid*)(9 * sizeof(float))); + glVertexAttribDivisor(12, 1); + InstanceVAO[std::pair<video::E_VERTEX_TYPE, InstanceType>(tp, InstanceTypeGlow)] = vao; + glBindVertexArray(0); + } + + + +} + +size_t VAOManager::getVertexPitch(enum VTXTYPE tp) const { switch (tp) { @@ -684,22 +667,22 @@ size_t VBOGatherer::getVertexPitch(enum VTXTYPE tp) const } } -VBOGatherer::VTXTYPE VBOGatherer::getVTXTYPE(video::E_VERTEX_TYPE type) +VAOManager::VTXTYPE VAOManager::getVTXTYPE(video::E_VERTEX_TYPE type) { switch (type) { + default: + assert(0 && "Wrong vtxtype"); case video::EVT_STANDARD: return VTXTYPE_STANDARD; case video::EVT_2TCOORDS: return VTXTYPE_TCOORD; case video::EVT_TANGENTS: return VTXTYPE_TANGENT; - default: - assert(0 && "Wrong vtxtype"); } }; -void VBOGatherer::append(scene::IMeshBuffer *mb, VBOGatherer::VTXTYPE tp) +void VAOManager::append(scene::IMeshBuffer *mb, VTXTYPE tp) { size_t old_vtx_cnt = vtx_cnt[tp]; vtx_cnt[tp] += mb->getVertexCount(); @@ -717,7 +700,7 @@ void VBOGatherer::append(scene::IMeshBuffer *mb, VBOGatherer::VTXTYPE tp) mappedBaseIndex[tp][mb] = old_idx_cnt * sizeof(u16); } -std::pair<unsigned, unsigned> VBOGatherer::getBase(scene::IMeshBuffer *mb) +std::pair<unsigned, unsigned> VAOManager::getBase(scene::IMeshBuffer *mb) { VTXTYPE tp = getVTXTYPE(mb->getVertexType()); if (mappedBaseVertex[tp].find(mb) == mappedBaseVertex[tp].end()) @@ -727,6 +710,7 @@ std::pair<unsigned, unsigned> VBOGatherer::getBase(scene::IMeshBuffer *mb) append(mb, tp); regenerateBuffer(tp); regenerateVAO(tp); + regenerateInstancedVAO(); } std::map<scene::IMeshBuffer*, unsigned>::iterator It; @@ -738,63 +722,41 @@ std::pair<unsigned, unsigned> VBOGatherer::getBase(scene::IMeshBuffer *mb) return std::pair<unsigned, unsigned>(vtx, It->second); } -static VBOGatherer *gatherersingleton = 0; - -std::pair<unsigned, unsigned> getVAOOffsetAndBase(scene::IMeshBuffer *mb) +size_t VAOManager::appendInstance(enum InstanceType, const std::vector<InstanceData> &instance_data) { - if (!gatherersingleton) - gatherersingleton = new VBOGatherer(); - return gatherersingleton->getBase(mb); + glBindBuffer(GL_ARRAY_BUFFER, instance_vbo[0]); + glBufferSubData(GL_ARRAY_BUFFER, instance_count[0] * sizeof(InstanceData), instance_data.size() * sizeof(InstanceData), instance_data.data()); + size_t result = instance_count[0]; + instance_count[0] += instance_data.size(); + return result; } -unsigned getVBO(video::E_VERTEX_TYPE type) -{ - if (gatherersingleton) - return gatherersingleton->getVBO(type); - return 0; -} - -unsigned getVAO(video::E_VERTEX_TYPE type) -{ - if (gatherersingleton) - return gatherersingleton->getVAO(type); - return 0; -} - -void resetVAO() -{ - if (gatherersingleton) - delete gatherersingleton; - gatherersingleton = 0; -} - -ScopedGPUTimer::ScopedGPUTimer(GPUTimer &timer) +ScopedGPUTimer::ScopedGPUTimer(GPUTimer &t) : timer(t) { if (!UserConfigParams::m_profiler_enabled) return; if (profiler.isFrozen()) return; - + if (!timer.canSubmitQuery) return; #ifdef GL_TIME_ELAPSED - irr::video::COpenGLDriver *gl_driver = (irr::video::COpenGLDriver *)irr_driver->getDevice()->getVideoDriver(); if (!timer.initialised) { - gl_driver->extGlGenQueries(1, &timer.query); + glGenQueries(1, &timer.query); timer.initialised = true; } - gl_driver->extGlBeginQuery(GL_TIME_ELAPSED, timer.query); + glBeginQuery(GL_TIME_ELAPSED, timer.query); #endif } ScopedGPUTimer::~ScopedGPUTimer() { if (!UserConfigParams::m_profiler_enabled) return; if (profiler.isFrozen()) return; - + if (!timer.canSubmitQuery) return; #ifdef GL_TIME_ELAPSED - irr::video::COpenGLDriver *gl_driver = (irr::video::COpenGLDriver *)irr_driver->getDevice()->getVideoDriver(); - gl_driver->extGlEndQuery(GL_TIME_ELAPSED); + glEndQuery(GL_TIME_ELAPSED); + timer.canSubmitQuery = false; #endif } -GPUTimer::GPUTimer() : initialised(false) +GPUTimer::GPUTimer() : initialised(false), lastResult(0), canSubmitQuery(true) { } @@ -803,8 +765,12 @@ unsigned GPUTimer::elapsedTimeus() if (!initialised) return 0; GLuint result; - irr::video::COpenGLDriver *gl_driver = (irr::video::COpenGLDriver *)irr_driver->getDevice()->getVideoDriver(); - gl_driver->extGlGetQueryObjectuiv(query, GL_QUERY_RESULT, &result); + glGetQueryObjectuiv(query, GL_QUERY_RESULT_AVAILABLE, &result); + if (result == GL_FALSE) + return lastResult; + glGetQueryObjectuiv(query, GL_QUERY_RESULT, &result); + lastResult = result / 1000; + canSubmitQuery = true; return result / 1000; } @@ -861,7 +827,7 @@ void FrameBuffer::Bind() glViewport(0, 0, width, height); irr::video::COpenGLDriver *gl_driver = (irr::video::COpenGLDriver*)irr_driver->getDevice()->getVideoDriver(); GLenum bufs[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; - gl_driver->extGlDrawBuffers(RenderTargets.size(), bufs); + glDrawBuffers(RenderTargets.size(), bufs); } void FrameBuffer::Blit(const FrameBuffer &Src, FrameBuffer &Dst, GLbitfield mask, GLenum filter) @@ -924,7 +890,7 @@ static void drawTexColoredQuad(const video::ITexture *texture, const video::SCol glUseProgram(UIShader::ColoredTextureRectShader::getInstance()->Program); glBindVertexArray(UIShader::ColoredTextureRectShader::getInstance()->vao); - setTexture(UIShader::ColoredTextureRectShader::getInstance()->TU_tex, static_cast<const irr::video::COpenGLTexture*>(texture)->getOpenGLTextureName(), GL_LINEAR, GL_LINEAR); + UIShader::ColoredTextureRectShader::getInstance()->SetTextureUnits(createVector<GLuint>(static_cast<const irr::video::COpenGLTexture*>(texture)->getOpenGLTextureName())); UIShader::ColoredTextureRectShader::getInstance()->setUniforms( core::vector2df(center_pos_x, center_pos_y), core::vector2df(width, height), core::vector2df(tex_center_pos_x, tex_center_pos_y), core::vector2df(tex_width, tex_height)); @@ -944,7 +910,7 @@ void drawTexQuad(GLuint texture, float width, float height, glUseProgram(UIShader::TextureRectShader::getInstance()->Program); glBindVertexArray(SharedObject::UIVAO); - setTexture(UIShader::TextureRectShader::getInstance()->TU_tex, texture, GL_LINEAR, GL_LINEAR); + UIShader::TextureRectShader::getInstance()->SetTextureUnits(createVector<GLuint>(texture)); UIShader::TextureRectShader::getInstance()->setUniforms( core::vector2df(center_pos_x, center_pos_y), core::vector2df(width, height), core::vector2df(tex_center_pos_x, tex_center_pos_y), @@ -1047,7 +1013,7 @@ void draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect glUseProgram(UIShader::UniformColoredTextureRectShader::getInstance()->Program); glBindVertexArray(SharedObject::UIVAO); - setTexture(UIShader::UniformColoredTextureRectShader::getInstance()->TU_tex, static_cast<const irr::video::COpenGLTexture*>(texture)->getOpenGLTextureName(), GL_LINEAR, GL_LINEAR); + UIShader::UniformColoredTextureRectShader::getInstance()->SetTextureUnits(createVector<GLuint>(static_cast<const irr::video::COpenGLTexture*>(texture)->getOpenGLTextureName())); UIShader::UniformColoredTextureRectShader::getInstance()->setUniforms( core::vector2df(center_pos_x, center_pos_y), core::vector2df(width, height), core::vector2df(tex_center_pos_x, tex_center_pos_y), core::vector2df(tex_width, tex_height), colors); @@ -1083,7 +1049,7 @@ void draw2DImageFromRTT(GLuint texture, size_t texture_w, size_t texture_h, glUseProgram(UIShader::UniformColoredTextureRectShader::getInstance()->Program); glBindVertexArray(SharedObject::UIVAO); - setTexture(UIShader::UniformColoredTextureRectShader::getInstance()->TU_tex, texture, GL_LINEAR, GL_LINEAR); + UIShader::UniformColoredTextureRectShader::getInstance()->SetTextureUnits(createVector<GLuint>(texture)); UIShader::UniformColoredTextureRectShader::getInstance()->setUniforms( core::vector2df(center_pos_x, center_pos_y), core::vector2df(width, height), core::vector2df(tex_center_pos_x, tex_center_pos_y), core::vector2df(tex_width, tex_height), @@ -1204,3 +1170,30 @@ void GL32_draw2DRectangle(video::SColor color, const core::rect<s32>& position, glGetError(); } + +bool hasGLExtension(const char* extension) +{ + if (glGetStringi != NULL) + { + GLint numExtensions = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); + for (GLint i = 0; i < numExtensions; i++) + { + const char* foundExtension = + (const char*) glGetStringi(GL_EXTENSIONS, i); + if (foundExtension && strcmp(foundExtension, extension) == 0) + { + return true; + } + } + } + else + { + const char* extensions = (const char*) glGetString(GL_EXTENSIONS); + if (extensions && strstr(extensions, extension) != NULL) + { + return true; + } + } + return false; +} diff --git a/src/graphics/glwrap.hpp b/src/graphics/glwrap.hpp index 2ed1994e1..cd4da2a20 100644 --- a/src/graphics/glwrap.hpp +++ b/src/graphics/glwrap.hpp @@ -1,118 +1,12 @@ #ifndef GLWRAP_HEADER_H #define GLWRAP_HEADER_H -#if defined(__APPLE__) -# include <OpenGL/gl.h> -# include <OpenGL/gl3.h> -# define OGL32CTX -# ifdef GL_ARB_instanced_arrays -# define glVertexAttribDivisor glVertexAttribDivisorARB -# endif -# ifndef GL_TEXTURE_SWIZZLE_RGBA -# define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 -# endif -#elif defined(ANDROID) -# include <GLES/gl.h> -#elif defined(WIN32) -# define _WINSOCKAPI_ -// has to be included before gl.h because of WINGDIAPI and APIENTRY definitions -# include <windows.h> -# include <GL/gl.h> -#else -#define GL_GLEXT_PROTOTYPES -#define DEBUG_OUTPUT_DECLARED -# include <GL/gl.h> -#endif +#include "gl_headers.hpp" #include <vector> #include "irr_driver.hpp" #include "utils/log.hpp" -// already includes glext.h, which defines useful GL constants. -// COpenGLDriver has already loaded the extension GL functions we use (e.g glBeginQuery) -#include "../../lib/irrlicht/source/Irrlicht/COpenGLDriver.h" -#ifdef WIN32 -extern PFNGLGENTRANSFORMFEEDBACKSPROC glGenTransformFeedbacks; -extern PFNGLBINDTRANSFORMFEEDBACKPROC glBindTransformFeedback; -extern PFNGLDRAWTRANSFORMFEEDBACKPROC glDrawTransformFeedback; -extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; -extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; -extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; -extern PFNGLBINDBUFFERBASEPROC glBindBufferBase; -extern PFNGLGENBUFFERSPROC glGenBuffers; -extern PFNGLBINDBUFFERPROC glBindBuffer; -extern PFNGLBUFFERDATAPROC glBufferData; -extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; -extern PFNGLCREATESHADERPROC glCreateShader; -extern PFNGLCOMPILESHADERPROC glCompileShader; -extern PFNGLSHADERSOURCEPROC glShaderSource; -extern PFNGLCREATEPROGRAMPROC glCreateProgram; -extern PFNGLATTACHSHADERPROC glAttachShader; -extern PFNGLLINKPROGRAMPROC glLinkProgram; -extern PFNGLUSEPROGRAMPROC glUseProgram; -extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; -extern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; -extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; -extern PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; -extern PFNGLUNIFORM1FPROC glUniform1f; -extern PFNGLUNIFORM3FPROC glUniform3f; -extern PFNGLUNIFORM1FVPROC glUniform1fv; -extern PFNGLUNIFORM4FVPROC glUniform4fv; -extern PFNGLDELETESHADERPROC glDeleteShader; -extern PFNGLGETSHADERIVPROC glGetShaderiv; -extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; -extern PFNGLACTIVETEXTUREPROC glActiveTexture; -extern PFNGLUNIFORM2FPROC glUniform2f; -extern PFNGLUNIFORM1IPROC glUniform1i; -extern PFNGLUNIFORM3IPROC glUniform3i; -extern PFNGLUNIFORM4IPROC glUniform4i; -extern PFNGLGETPROGRAMIVPROC glGetProgramiv; -extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; -extern PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; -extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; -extern PFNGLBLENDEQUATIONPROC glBlendEquation; -extern PFNGLVERTEXATTRIBDIVISORPROC glVertexAttribDivisor; -extern PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced; -extern PFNGLDRAWELEMENTSBASEVERTEXPROC glDrawElementsBaseVertex; -extern PFNGLDRAWELEMENTSINSTANCEDPROC glDrawElementsInstanced; -extern PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glDrawElementsInstancedBaseVertex; -extern PFNGLDELETEBUFFERSPROC glDeleteBuffers; -extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; -extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; -extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; -extern PFNGLTEXBUFFERPROC glTexBuffer; -extern PFNGLBUFFERSUBDATAPROC glBufferSubData; -extern PFNGLMAPBUFFERPROC glMapBuffer; -extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange; -extern PFNGLUNMAPBUFFERPROC glUnmapBuffer; -extern PFNGLFENCESYNCPROC glFenceSync; -extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync; -extern PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer; -extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; -extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; -extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; -extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; -extern PFNGLFRAMEBUFFERTEXTUREPROC glFramebufferTexture; -extern PFNGLTEXIMAGE3DPROC glTexImage3D; -extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap; -extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; -extern PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample; -extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer; -extern PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex; -extern PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding; -extern PFNGLBLENDCOLORPROC glBlendColor; -extern PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D; -extern PFNGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage; -extern PFNGLTEXSTORAGE1DPROC glTexStorage1D; -extern PFNGLTEXSTORAGE2DPROC glTexStorage2D; -extern PFNGLTEXSTORAGE3DPROC glTexStorage3D; -extern PFNGLBINDIMAGETEXTUREPROC glBindImageTexture; -extern PFNGLDISPATCHCOMPUTEPROC glDispatchCompute; -#ifdef DEBUG -extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB; -#endif -#endif - void initGL(); GLuint LoadTFBProgram(const char * vertex_file_path, const char **varyings, unsigned varyingscount); @@ -194,6 +88,8 @@ class GPUTimer; class ScopedGPUTimer { +protected: + GPUTimer &timer; public: ScopedGPUTimer(GPUTimer &); ~ScopedGPUTimer(); @@ -204,6 +100,8 @@ class GPUTimer friend class ScopedGPUTimer; GLuint query; bool initialised; + unsigned lastResult; + bool canSubmitQuery; public: GPUTimer(); unsigned elapsedTimeus(); @@ -241,10 +139,109 @@ void compressTexture(irr::video::ITexture *tex, bool srgb, bool premul_alpha = f bool loadCompressedTexture(const std::string& compressed_tex); void saveCompressedTexture(const std::string& compressed_tex); -std::pair<unsigned, unsigned> getVAOOffsetAndBase(scene::IMeshBuffer *mb); -unsigned getVAO(video::E_VERTEX_TYPE type); -unsigned getVBO(video::E_VERTEX_TYPE type); -void resetVAO(); +enum InstanceType +{ + InstanceTypeDefault, + InstanceTypeShadow, + InstanceTypeRSM, + InstanceTypeGlow, + InstanceTypeCount, +}; + +#ifdef WIN32 +#pragma pack(push, 1) +#endif +struct InstanceData +{ + struct + { + float X; + float Y; + float Z; + } Origin; + struct + { + float X; + float Y; + float Z; + } Orientation; + struct + { + float X; + float Y; + float Z; + } Scale; + uint64_t Texture; + uint64_t SecondTexture; +#ifdef WIN32 +}; +#else +} __attribute__((packed)); +#endif + +struct GlowInstanceData +{ + struct + { + float X; + float Y; + float Z; + } Origin; + struct + { + float X; + float Y; + float Z; + } Orientation; + struct + { + float X; + float Y; + float Z; + } Scale; + unsigned Color; +#ifdef WIN32 +}; +#else +} __attribute__((packed)); +#endif +#ifdef WIN32 +#pragma pack(pop) +#endif + +class VAOManager : public Singleton<VAOManager> +{ + enum VTXTYPE { VTXTYPE_STANDARD, VTXTYPE_TCOORD, VTXTYPE_TANGENT, VTXTYPE_COUNT }; + GLuint vbo[VTXTYPE_COUNT], ibo[VTXTYPE_COUNT], vao[VTXTYPE_COUNT]; + GLuint instance_vbo[InstanceTypeCount]; + size_t instance_count[InstanceTypeCount]; + void *Ptr[InstanceTypeCount]; + void *VBOPtr[VTXTYPE_COUNT]; + std::vector<scene::IMeshBuffer *> storedCPUBuffer[VTXTYPE_COUNT]; + void *vtx_mirror[VTXTYPE_COUNT], *idx_mirror[VTXTYPE_COUNT]; + size_t vtx_cnt[VTXTYPE_COUNT], idx_cnt[VTXTYPE_COUNT]; + std::map<scene::IMeshBuffer*, unsigned> mappedBaseVertex[VTXTYPE_COUNT], mappedBaseIndex[VTXTYPE_COUNT]; + std::map<std::pair<video::E_VERTEX_TYPE, InstanceType>, GLuint> InstanceVAO; + + void cleanInstanceVAOs(); + void regenerateBuffer(enum VTXTYPE); + void regenerateVAO(enum VTXTYPE); + void regenerateInstancedVAO(); + size_t getVertexPitch(enum VTXTYPE) const; + VTXTYPE getVTXTYPE(video::E_VERTEX_TYPE type); + void append(scene::IMeshBuffer *, VTXTYPE tp); +public: + VAOManager(); + std::pair<unsigned, unsigned> getBase(scene::IMeshBuffer *); + size_t appendInstance(enum InstanceType, const std::vector<InstanceData> &instance_data); + GLuint getInstanceBuffer(InstanceType it) { return instance_vbo[it]; } + void *getInstanceBufferPtr(InstanceType it) { return Ptr[it]; } + unsigned getVBO(video::E_VERTEX_TYPE type) { return vbo[getVTXTYPE(type)]; } + void *getVBOPtr(video::E_VERTEX_TYPE type) { return VBOPtr[getVTXTYPE(type)]; } + unsigned getVAO(video::E_VERTEX_TYPE type) { return vao[getVTXTYPE(type)]; } + unsigned getInstanceVAO(video::E_VERTEX_TYPE vt, enum InstanceType it) { return InstanceVAO[std::pair<video::E_VERTEX_TYPE, InstanceType>(vt, it)]; } + ~VAOManager(); +}; void draw3DLine(const core::vector3df& start, const core::vector3df& end, irr::video::SColor color); @@ -264,4 +261,7 @@ void draw2DImage(const irr::video::ITexture* texture, const irr::core::rect<s32> void GL32_draw2DRectangle(irr::video::SColor color, const irr::core::rect<s32>& position, const irr::core::rect<s32>* clip = 0); + +bool hasGLExtension(const char* extension); + #endif diff --git a/src/graphics/gpuparticles.cpp b/src/graphics/gpuparticles.cpp index 01831b68a..2c7656863 100644 --- a/src/graphics/gpuparticles.cpp +++ b/src/graphics/gpuparticles.cpp @@ -6,6 +6,7 @@ #include <IParticleSystemSceneNode.h> #include "guiengine/engine.hpp" #include "graphics/particle_emitter.hpp" +#include "../../lib/irrlicht/source/Irrlicht/os.h" #define COMPONENTCOUNT 8 scene::IParticleSystemSceneNode *ParticleSystemProxy::addParticleNode( @@ -88,7 +89,7 @@ void ParticleSystemProxy::setHeightmap(const std::vector<std::vector<float> > &h has_height_map = true; glGenBuffers(1, &heighmapbuffer); glBindBuffer(GL_TEXTURE_BUFFER, heighmapbuffer); - glBufferData(GL_TEXTURE_BUFFER, width * height * sizeof(float), hm_array, GL_STATIC_DRAW); + glBufferData(GL_TEXTURE_BUFFER, width * height * sizeof(float), hm_array, GL_STREAM_COPY); glGenTextures(1, &heightmaptexture); glBindTexture(GL_TEXTURE_BUFFER, heightmaptexture); glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, heighmapbuffer); @@ -348,9 +349,7 @@ void ParticleSystemProxy::drawFlip() glBlendFunc(GL_ONE, GL_ONE); glUseProgram(ParticleShader::FlipParticleRender::getInstance()->Program); - setTexture(ParticleShader::FlipParticleRender::getInstance()->TU_tex, texture, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR); - setTexture(ParticleShader::FlipParticleRender::getInstance()->TU_dtex, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); - + ParticleShader::FlipParticleRender::getInstance()->SetTextureUnits(std::vector<GLuint>{ texture, irr_driver->getDepthStencilTexture() }); ParticleShader::FlipParticleRender::getInstance()->setUniforms(); glBindVertexArray(current_rendering_vao); @@ -365,8 +364,7 @@ void ParticleSystemProxy::drawNotFlip() glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glUseProgram(ParticleShader::SimpleParticleRender::getInstance()->Program); - setTexture(ParticleShader::SimpleParticleRender::getInstance()->TU_tex, texture, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR); - setTexture(ParticleShader::SimpleParticleRender::getInstance()->TU_dtex, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); + ParticleShader::SimpleParticleRender::getInstance()->SetTextureUnits(std::vector<GLuint>{ texture, irr_driver->getDepthStencilTexture() }); video::SColorf ColorFrom = video::SColorf(getColorFrom()[0], getColorFrom()[1], getColorFrom()[2]); video::SColorf ColorTo = video::SColorf(getColorTo()[0], getColorTo()[1], getColorTo()[2]); @@ -389,12 +387,12 @@ void ParticleSystemProxy::generateVAOs() glBindVertexArray(0); glGenBuffers(1, &initial_values_buffer); glBindBuffer(GL_ARRAY_BUFFER, initial_values_buffer); - glBufferData(GL_ARRAY_BUFFER, count * sizeof(ParticleData), ParticleParams, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, count * sizeof(ParticleData), ParticleParams, GL_STREAM_COPY); glGenBuffers(2, tfb_buffers); glBindBuffer(GL_ARRAY_BUFFER, tfb_buffers[0]); - glBufferData(GL_ARRAY_BUFFER, count * sizeof(ParticleData), InitialValues, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, count * sizeof(ParticleData), InitialValues, GL_STREAM_COPY); glBindBuffer(GL_ARRAY_BUFFER, tfb_buffers[1]); - glBufferData(GL_ARRAY_BUFFER, count * sizeof(ParticleData), 0, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, count * sizeof(ParticleData), 0, GL_STREAM_COPY); glBindBuffer(GL_ARRAY_BUFFER, 0); glGenVertexArrays(1, ¤t_rendering_vao); @@ -423,7 +421,7 @@ void ParticleSystemProxy::generateVAOs() } glGenBuffers(1, &quaternionsbuffer); glBindBuffer(GL_ARRAY_BUFFER, quaternionsbuffer); - glBufferData(GL_ARRAY_BUFFER, 4 * count * sizeof(float), quaternions, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, 4 * count * sizeof(float), quaternions, GL_STREAM_COPY); delete[] quaternions; } @@ -452,6 +450,12 @@ void ParticleSystemProxy::render() { draw(); } +bool ParticleSystemProxy::update() +{ + doParticleSystem(os::Timer::getTime()); + return (IsVisible && (Particles.size() != 0)); +} + void ParticleSystemProxy::OnRegisterSceneNode() { doParticleSystem(os::Timer::getTime()); diff --git a/src/graphics/gpuparticles.hpp b/src/graphics/gpuparticles.hpp index 84fd72fab..94ca75f81 100644 --- a/src/graphics/gpuparticles.hpp +++ b/src/graphics/gpuparticles.hpp @@ -81,6 +81,7 @@ public: const float* getColorTo() const { return m_color_to; } void setHeightmap(const std::vector<std::vector<float> >&, float, float, float, float); void setFlip(); + bool update(); }; #endif // GPUPARTICLES_H diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 756280e98..15d911208 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -112,6 +112,10 @@ IrrDriver::IrrDriver() m_mipviz = m_wireframe = m_normals = m_ssaoviz = \ m_lightviz = m_shadowviz = m_distortviz = m_rsm = m_rh = m_gi = false; SkyboxCubeMap = m_last_light_bucket_distance = 0; + m_shadow_camnodes[0] = NULL; + m_shadow_camnodes[1] = NULL; + m_shadow_camnodes[2] = NULL; + m_shadow_camnodes[3] = NULL; memset(object_count, 0, sizeof(object_count)); } // IrrDriver @@ -166,6 +170,11 @@ void IrrDriver::IncreaseObjectCount() object_count[m_phase]++; } +void IrrDriver::IncreasePolyCount(unsigned Polys) +{ + poly_count[m_phase] += Polys; +} + core::array<video::IRenderTarget> &IrrDriver::getMainSetup() { return m_mrt; @@ -328,8 +337,8 @@ void IrrDriver::initDevice() } // end if firstTime - const core::dimension2d<u32> ssize = m_device->getVideoModeList() - ->getDesktopResolution(); + video::IVideoModeList* modes = m_device->getVideoModeList(); + const core::dimension2d<u32> ssize = modes->getDesktopResolution(); if (UserConfigParams::m_width > (int)ssize.Width || UserConfigParams::m_height > (int)ssize.Height) { @@ -339,11 +348,14 @@ void IrrDriver::initDevice() UserConfigParams::m_height = (int)ssize.Height; } - core::dimension2d<u32> res = core::dimension2du(UserConfigParams::m_width, UserConfigParams::m_height); - res = m_device->getVideoModeList()->getVideoModeResolution(res, res); - - if (res.Width > 0 && res.Height > 0) + core::dimension2d<u32> res = core::dimension2du(UserConfigParams::m_width, + UserConfigParams::m_height); + + + if (modes->getVideoModeCount() > 0) { + res = modes->getVideoModeResolution(res, res); + UserConfigParams::m_width = res.Width; UserConfigParams::m_height = res.Height; } @@ -467,25 +479,57 @@ void IrrDriver::initDevice() m_need_ubo_workaround = false; m_need_rh_workaround = false; + m_need_srgb_workaround = false; #ifdef WIN32 // Fix for Intel Sandy Bridge on Windows which supports GL up to 3.1 only - if (strstr((const char *)glGetString(GL_VENDOR), "Intel") != nullptr && (GLMajorVersion == 3 && GLMinorVersion == 1)) + if (strstr((const char *)glGetString(GL_VENDOR), "Intel") != NULL && (GLMajorVersion == 3 && GLMinorVersion == 1)) m_need_ubo_workaround = true; #endif // Fix for Nvidia and instanced RH - if (strstr((const char *)glGetString(GL_VENDOR), "NVIDIA") != nullptr) + if (strstr((const char *)glGetString(GL_VENDOR), "NVIDIA") != NULL) m_need_rh_workaround = true; + + // Fix for AMD and bindless sRGB textures + if (strstr((const char *)glGetString(GL_VENDOR), "ATI") != NULL) + m_need_srgb_workaround = true; } m_glsl = (GLMajorVersion > 3 || (GLMajorVersion == 3 && GLMinorVersion >= 1)); + initGL(); // Parse extensions hasVSLayer = false; + hasBaseInstance = false; + hasBuffserStorage = false; + hasDrawIndirect = false; + hasComputeShaders = false; + hasTextureStorage = false; // Default false value for hasVSLayer if --no-graphics argument is used if (!ProfileWorld::isNoGraphics()) { - const GLubyte *extensions = glGetString(GL_EXTENSIONS); - if (extensions && strstr((const char*)extensions, "GL_AMD_vertex_shader_layer") != NULL) - hasVSLayer = true; + if (GLEW_AMD_vertex_shader_layer) { + hasVSLayer = true; + Log::info("GLDriver", "AMD Vertex Shader Layer enabled"); + } + if (GLEW_ARB_buffer_storage) { + hasBuffserStorage = true; + Log::info("GLDriver", "ARB Buffer Storage enabled"); + } + if (GLEW_ARB_base_instance) { + hasBaseInstance = true; + Log::info("GLDriver", "ARB Base Instance enabled"); + } + if (GLEW_ARB_draw_indirect) { + hasDrawIndirect = true; + Log::info("GLDriver", "ARB Draw Indirect enabled"); + } + if (GLEW_ARB_compute_shader) { + hasComputeShaders = true; + Log::info("GLDriver", "ARB Compute Shader enabled"); + } + if (GLEW_ARB_texture_storage) { + hasTextureStorage = true; + Log::info("GLDriver", "ARB Texture Storage enabled"); + } } @@ -513,8 +557,7 @@ void IrrDriver::initDevice() m_mrt.clear(); m_mrt.reallocate(2); - irr::video::COpenGLDriver* gl_driver = (irr::video::COpenGLDriver*)m_device->getVideoDriver(); - gl_driver->extGlGenQueries(1, &m_lensflare_query); + glGenQueries(1, &m_lensflare_query); m_query_issued = false; scene::IMesh * const sphere = m_scene_manager->getGeometryCreator()->createSphereMesh(1, 16, 16); @@ -733,7 +776,7 @@ void IrrDriver::applyResolutionSettings() // FIXME: this load sequence is (mostly) duplicated from main.cpp!! // That's just error prone // (we're sure to update main.cpp at some point and forget this one...) - + m_shaders->killShaders(); // initDevice will drop the current device. initDevice(); @@ -1601,6 +1644,7 @@ video::ITexture* IrrDriver::applyMask(video::ITexture* texture, // ---------------------------------------------------------------------------- void IrrDriver::setRTT(RTT* rtt) { + memset(m_shadow_camnodes, 0, 4 * sizeof(void*)); m_rtts = rtt; } // ---------------------------------------------------------------------------- @@ -1703,13 +1747,14 @@ void IrrDriver::displayFPS() if (UserConfigParams::m_artist_debug_mode) { sprintf( - buffer, "FPS: %i/%i/%i - Objects (P1:%d P2:%d T:%d) - LightDst : ~%d", + buffer, "FPS: %i/%i/%i - PolyCount (Solid:%d Shadows:%d) - LightDst : ~%d", min, fps, max, - object_count[SOLID_NORMAL_AND_DEPTH_PASS], - object_count[SOLID_NORMAL_AND_DEPTH_PASS], - object_count[TRANSPARENT_PASS], + poly_count[SOLID_NORMAL_AND_DEPTH_PASS], + poly_count[SHADOW_PASS], m_last_light_bucket_distance ); + poly_count[SOLID_NORMAL_AND_DEPTH_PASS] = 0; + poly_count[SHADOW_PASS] = 0; object_count[SOLID_NORMAL_AND_DEPTH_PASS] = 0; object_count[SOLID_NORMAL_AND_DEPTH_PASS] = 0; object_count[TRANSPARENT_PASS] = 0; @@ -2414,8 +2459,8 @@ scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos, float energy, if (sun) { - m_sun_interposer->setPosition(pos); - m_sun_interposer->updateAbsolutePosition(); + //m_sun_interposer->setPosition(pos); + //m_sun_interposer->updateAbsolutePosition(); m_lensflare->setPosition(pos); m_lensflare->updateAbsolutePosition(); diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index eb2cc3f61..f324b1dcd 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -78,9 +78,10 @@ enum TypeFBO { FBO_SSAO, FBO_NORMAL_AND_DEPTHS, - FBO_COMBINED_TMP1_TMP2, + FBO_COMBINED_DIFFUSE_SPECULAR, FBO_COLORS, - FBO_LOG_LUMINANCE, + FBO_DIFFUSE, + FBO_SPECULAR, FBO_MLAA_COLORS, FBO_MLAA_BLEND, FBO_MLAA_TMP, @@ -111,6 +112,7 @@ enum QueryPerf { Q_SOLID_PASS1, Q_SHADOWS, + Q_RSM, Q_RH, Q_GI, Q_ENVMAP, @@ -140,7 +142,9 @@ enum TypeRTT RTT_LINEAR_DEPTH, RTT_NORMAL_AND_DEPTH, RTT_COLOR, - RTT_LOG_LUMINANCE, + RTT_DIFFUSE, + RTT_SPECULAR, + RTT_HALF1, RTT_HALF2, @@ -196,8 +200,15 @@ class IrrDriver : public IEventReceiver, public NoCopy private: int GLMajorVersion, GLMinorVersion; bool hasVSLayer; + bool hasBaseInstance; + bool hasDrawIndirect; + bool hasBuffserStorage; + bool hasComputeShaders; + bool hasTextureStorage; bool m_need_ubo_workaround; bool m_need_rh_workaround; + bool m_need_srgb_workaround; + GLsync m_sync; /** The irrlicht device. */ IrrlichtDevice *m_device; /** Irrlicht scene manager. */ @@ -290,11 +301,41 @@ public: return m_need_rh_workaround; } + bool needsRGBBindlessWorkaround() const + { + return m_need_srgb_workaround; + } + + bool hasARB_base_instance() const + { + return hasBaseInstance; + } + + bool hasARB_draw_indirect() const + { + return hasDrawIndirect; + } + bool hasVSLayerExtension() const { return hasVSLayer; } + bool hasBufferStorageExtension() const + { + return hasBuffserStorage; + } + + bool hasARBComputeShaders() const + { + return hasComputeShaders; + } + + bool hasARBTextureStorage() const + { + return hasTextureStorage; + } + video::SColorf getAmbientLight() const; struct GlowData { @@ -332,12 +373,14 @@ private: /** Performance stats */ unsigned m_last_light_bucket_distance; unsigned object_count[PASS_COUNT]; + unsigned poly_count[PASS_COUNT]; u32 m_renderpass; u32 m_lensflare_query; bool m_query_issued; class STKMeshSceneNode *m_sun_interposer; scene::CLensFlareSceneNode *m_lensflare; scene::ICameraSceneNode *m_suncam; + scene::ICameraSceneNode *m_shadow_camnodes[4]; float m_shadows_cam[4][24]; std::vector<GlowData> m_glowing; @@ -379,6 +422,7 @@ private: void renderLights(unsigned pointlightCount); void renderShadowsDebug(); void doScreenShot(); + void PrepareDrawCalls(scene::ICameraSceneNode *camnode); public: IrrDriver(); ~IrrDriver(); @@ -394,6 +438,7 @@ public: return sun_ortho_matrix; } void IncreaseObjectCount(); + void IncreasePolyCount(unsigned); core::array<video::IRenderTarget> &getMainSetup(); void updateConfigIfRelevant(); void setAllMaterialFlags(scene::IMesh *mesh) const; @@ -570,7 +615,7 @@ public: // ----------------------------------------------------------------------- inline video::E_MATERIAL_TYPE getShader(const ShaderType num) {return m_shaders->getShader(num);} // ----------------------------------------------------------------------- - inline void updateShaders() {m_shaders->loadShaders();} + inline void updateShaders() {m_shaders->killShaders();} // ------------------------------------------------------------------------ inline video::IShaderConstantSetCallBack* getCallback(const ShaderType num) { diff --git a/src/graphics/light.hpp b/src/graphics/light.hpp index 8af5d7009..1ecb3c119 100644 --- a/src/graphics/light.hpp +++ b/src/graphics/light.hpp @@ -59,6 +59,7 @@ public: float getEnergy() const { return m_energy; } float getEffectiveEnergy() const { return m_energy_multiplier * m_energy; } core::vector3df getColor() const { return core::vector3df(m_color[0], m_color[1], m_color[2]); } + void setColor(float r, float g, float b) { m_color[0] = r; m_color[1] = g; m_color[2] = b; } float getEnergyMultiplier() const { return m_energy_multiplier; } void setEnergyMultiplier(float newval) { m_energy_multiplier = newval; } diff --git a/src/graphics/lod_node.cpp b/src/graphics/lod_node.cpp index dcf165d70..6a4e0ddf7 100644 --- a/src/graphics/lod_node.cpp +++ b/src/graphics/lod_node.cpp @@ -137,19 +137,24 @@ void LODNode::OnAnimate(u32 timeMs) } } -void LODNode::OnRegisterSceneNode() +void LODNode::updateVisibility(bool* shown) { if (!isVisible()) return; if (m_nodes.size() == 0) return; - bool shown = false; int level = getLevel(); - if (level>=0) + for (size_t i = 0; i < m_nodes.size(); i++) { - m_nodes[level]->updateAbsolutePosition(); - m_nodes[level]->OnRegisterSceneNode(); - shown = true; + m_nodes[i]->setVisible(i == level); + if (i == level && shown != NULL) + *shown = (i > 0); } +} + +void LODNode::OnRegisterSceneNode() +{ + bool shown; + updateVisibility(&shown); const u32 now = irr_driver->getDevice()->getTimer()->getTime(); @@ -158,6 +163,7 @@ void LODNode::OnRegisterSceneNode() m_nodes[0]->getType() == scene::ESNT_ANIMATED_MESH) && now > m_last_tick) { + int level = getLevel(); if (m_previous_visibility == WAS_HIDDEN && shown) { scene::IMesh* mesh; @@ -254,20 +260,7 @@ void LODNode::OnRegisterSceneNode() m_previous_visibility = (shown ? WAS_SHOWN : WAS_HIDDEN); m_last_tick = now; - // If this node has children other than the LOD nodes, draw them - core::list<ISceneNode*>::Iterator it; - - for (it = Children.begin(); it != Children.end(); it++) - { - if (m_nodes_set.find(*it) == m_nodes_set.end()) - { - assert(*it != NULL); - if ((*it)->isVisible()) - { - (*it)->OnRegisterSceneNode(); - } - } - } + scene::ISceneNode::OnRegisterSceneNode(); } void LODNode::add(int level, scene::ISceneNode* node, bool reparent) diff --git a/src/graphics/lod_node.hpp b/src/graphics/lod_node.hpp index 3cca1bc28..8c349eb67 100644 --- a/src/graphics/lod_node.hpp +++ b/src/graphics/lod_node.hpp @@ -83,6 +83,8 @@ public: int getLevel(); + void updateVisibility(bool* shown = NULL); + /* //! Returns a reference to the current relative transformation matrix. //! This is the matrix, this scene node uses instead of scale, translation diff --git a/src/graphics/particle_emitter.cpp b/src/graphics/particle_emitter.cpp index 266bdda45..201921afe 100644 --- a/src/graphics/particle_emitter.cpp +++ b/src/graphics/particle_emitter.cpp @@ -450,7 +450,7 @@ void ParticleEmitter::setParticleType(const ParticleKind* type) else { if (m_is_glsl) - m_node = ParticleSystemProxy::addParticleNode(m_is_glsl, true); + m_node = ParticleSystemProxy::addParticleNode(m_is_glsl, false); else m_node = irr_driver->addParticleNode(); diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index 354e01583..0075fa354 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.cpp @@ -33,6 +33,7 @@ #include "tracks/track.hpp" #include "utils/log.hpp" #include "utils/profiler.hpp" +#include "utils/cpp2011.hpp" #include <SViewFrustum.h> @@ -216,7 +217,7 @@ static void DrawFullScreenEffect(Args...args) static void renderBloom(GLuint in) { - setTexture(FullScreenShader::BloomShader::getInstance()->TU_tex, in, GL_NEAREST, GL_NEAREST); + FullScreenShader::BloomShader::getInstance()->SetTextureUnits(createVector<GLuint>(in)); DrawFullScreenEffect<FullScreenShader::BloomShader>(); } @@ -227,12 +228,12 @@ void PostProcessing::renderDiffuseEnvMap(const float *bSHCoeff, const float *gSH glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_ONE, GL_ONE); - glUseProgram(FullScreenShader::DiffuseEnvMapShader::Program); + glUseProgram(FullScreenShader::DiffuseEnvMapShader::getInstance()->Program); glBindVertexArray(SharedObject::FullScreenQuadVAO); - setTexture(0, irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), GL_NEAREST, GL_NEAREST); + FullScreenShader::DiffuseEnvMapShader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH))); core::matrix4 TVM = irr_driver->getViewMatrix().getTransposed(); - FullScreenShader::DiffuseEnvMapShader::setUniforms(TVM, bSHCoeff, gSHCoeff, rSHCoeff, 0); + FullScreenShader::DiffuseEnvMapShader::getInstance()->setUniforms(TVM, std::vector<float>(bSHCoeff, bSHCoeff + 9), std::vector<float>(gSHCoeff, gSHCoeff + 9), std::vector<float>(rSHCoeff, rSHCoeff + 9)); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(0); @@ -263,26 +264,8 @@ void PostProcessing::renderGI(const core::matrix4 &RHMatrix, const core::vector3 core::matrix4 InvRHMatrix; RHMatrix.getInverse(InvRHMatrix); glDisable(GL_DEPTH_TEST); - glActiveTexture(GL_TEXTURE0 + FullScreenShader::GlobalIlluminationReconstructionShader::getInstance()->TU_SHR); - glBindTexture(GL_TEXTURE_3D, shr); - { - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - glActiveTexture(GL_TEXTURE0 + FullScreenShader::GlobalIlluminationReconstructionShader::getInstance()->TU_SHG); - glBindTexture(GL_TEXTURE_3D, shg); - { - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - glActiveTexture(GL_TEXTURE0 + FullScreenShader::GlobalIlluminationReconstructionShader::getInstance()->TU_SHB); - glBindTexture(GL_TEXTURE_3D, shb); - { - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - setTexture(FullScreenShader::GlobalIlluminationReconstructionShader::getInstance()->TU_ntex, irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), GL_NEAREST, GL_NEAREST); - setTexture(FullScreenShader::GlobalIlluminationReconstructionShader::getInstance()->TU_dtex, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); + FullScreenShader::GlobalIlluminationReconstructionShader::getInstance()->SetTextureUnits(createVector<GLuint>( + irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), irr_driver->getDepthStencilTexture(), shr, shg, shb)); DrawFullScreenEffect<FullScreenShader::GlobalIlluminationReconstructionShader>(RHMatrix, InvRHMatrix, rh_extend); } @@ -295,8 +278,7 @@ void PostProcessing::renderSunlight() glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); - setTexture(FullScreenShader::SunLightShader::getInstance()->TU_ntex, irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), GL_NEAREST, GL_NEAREST); - setTexture(FullScreenShader::SunLightShader::getInstance()->TU_dtex, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); + FullScreenShader::SunLightShader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), irr_driver->getDepthStencilTexture())); DrawFullScreenEffect<FullScreenShader::SunLightShader>(cb->getPosition(), video::SColorf(cb->getRed(), cb->getGreen(), cb->getBlue())); } @@ -309,17 +291,7 @@ void PostProcessing::renderShadowedSunlight(const std::vector<core::matrix4> &su glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); - setTexture(FullScreenShader::ShadowedSunLightShader::getInstance()->TU_ntex, irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), GL_NEAREST, GL_NEAREST); - setTexture(FullScreenShader::ShadowedSunLightShader::getInstance()->TU_dtex, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); - glActiveTexture(GL_TEXTURE0 + FullScreenShader::ShadowedSunLightShader::getInstance()->TU_shadowtex); - glBindTexture(GL_TEXTURE_2D_ARRAY, depthtex); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - + FullScreenShader::ShadowedSunLightShader::getInstance()->SetTextureUnits(createVector<GLuint>( irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), irr_driver->getDepthStencilTexture(), depthtex )); DrawFullScreenEffect<FullScreenShader::ShadowedSunLightShader>(cb->getPosition(), video::SColorf(cb->getRed(), cb->getGreen(), cb->getBlue())); } @@ -331,17 +303,13 @@ void PostProcessing::renderGaussian3Blur(FrameBuffer &in_fbo, FrameBuffer &auxil { auxiliary.Bind(); - setTexture(FullScreenShader::Gaussian3VBlurShader::getInstance()->TU_tex, in_fbo.getRTT()[0], GL_LINEAR, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + FullScreenShader::Gaussian3VBlurShader::getInstance()->SetTextureUnits(createVector<GLuint>(in_fbo.getRTT()[0])); DrawFullScreenEffect<FullScreenShader::Gaussian3VBlurShader>(core::vector2df(inv_width, inv_height)); } { in_fbo.Bind(); - setTexture(FullScreenShader::Gaussian3HBlurShader::getInstance()->TU_tex, auxiliary.getRTT()[0], GL_LINEAR, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + FullScreenShader::Gaussian3HBlurShader::getInstance()->SetTextureUnits(createVector<GLuint>(auxiliary.getRTT()[0])); DrawFullScreenEffect<FullScreenShader::Gaussian3HBlurShader>(core::vector2df(inv_width, inv_height)); } } @@ -353,17 +321,13 @@ void PostProcessing::renderGaussian6Blur(FrameBuffer &in_fbo, FrameBuffer &auxil { auxiliary.Bind(); - setTexture(FullScreenShader::Gaussian6VBlurShader::getInstance()->TU_tex, in_fbo.getRTT()[0], GL_LINEAR, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + FullScreenShader::Gaussian6VBlurShader::getInstance()->SetTextureUnits(createVector<GLuint>(in_fbo.getRTT()[0])); DrawFullScreenEffect<FullScreenShader::Gaussian6VBlurShader>(core::vector2df(inv_width, inv_height)); } { in_fbo.Bind(); - setTexture(FullScreenShader::Gaussian6HBlurShader::getInstance()->TU_tex, auxiliary.getRTT()[0], GL_LINEAR, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + FullScreenShader::Gaussian6HBlurShader::getInstance()->SetTextureUnits(createVector<GLuint>(auxiliary.getRTT()[0])); DrawFullScreenEffect<FullScreenShader::Gaussian6HBlurShader>(core::vector2df(inv_width, inv_height)); } } @@ -373,21 +337,12 @@ void PostProcessing::renderGaussian17TapBlur(FrameBuffer &in_fbo, FrameBuffer &a assert(in_fbo.getWidth() == auxiliary.getWidth() && in_fbo.getHeight() == auxiliary.getHeight()); float inv_width = 1.0f / in_fbo.getWidth(), inv_height = 1.0f / in_fbo.getHeight(); { -#if WIN32 - if (irr_driver->getGLSLVersion() < 430) -#endif + if (irr_driver->hasARBComputeShaders()) { auxiliary.Bind(); - - setTexture(FullScreenShader::Gaussian17TapHShader::getInstance()->TU_tex, in_fbo.getRTT()[0], GL_LINEAR, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - setTexture(FullScreenShader::Gaussian17TapHShader::getInstance()->TU_depth, irr_driver->getFBO(FBO_LINEAR_DEPTH).getRTT()[0], GL_LINEAR, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + FullScreenShader::Gaussian17TapHShader::getInstance()->SetTextureUnits(createVector<GLuint>(in_fbo.getRTT()[0], irr_driver->getFBO(FBO_LINEAR_DEPTH).getRTT()[0])); DrawFullScreenEffect<FullScreenShader::Gaussian17TapHShader>(core::vector2df(inv_width, inv_height)); } -#if WIN32 else { @@ -398,24 +353,15 @@ void PostProcessing::renderGaussian17TapBlur(FrameBuffer &in_fbo, FrameBuffer &a FullScreenShader::ComputeGaussian17TapHShader::getInstance()->setUniforms(); glDispatchCompute(in_fbo.getWidth() / 8, in_fbo.getHeight() / 8, 1); } -#endif } { -#if WIN32 - if (irr_driver->getGLSLVersion() < 430) -#endif + if (irr_driver->hasARBComputeShaders()) { in_fbo.Bind(); - setTexture(FullScreenShader::Gaussian17TapVShader::getInstance()->TU_tex, auxiliary.getRTT()[0], GL_LINEAR, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - setTexture(FullScreenShader::Gaussian17TapVShader::getInstance()->TU_depth, irr_driver->getFBO(FBO_LINEAR_DEPTH).getRTT()[0], GL_LINEAR, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + FullScreenShader::Gaussian17TapVShader::getInstance()->SetTextureUnits(createVector<GLuint>(auxiliary.getRTT()[0], irr_driver->getFBO(FBO_LINEAR_DEPTH).getRTT()[0])); DrawFullScreenEffect<FullScreenShader::Gaussian17TapVShader>(core::vector2df(inv_width, inv_height)); } -#if WIN32 else { glUseProgram(FullScreenShader::ComputeGaussian17TapVShader::getInstance()->Program); @@ -425,7 +371,6 @@ void PostProcessing::renderGaussian17TapBlur(FrameBuffer &in_fbo, FrameBuffer &a FullScreenShader::ComputeGaussian17TapVShader::getInstance()->setUniforms(); glDispatchCompute(in_fbo.getWidth() / 8, in_fbo.getHeight() / 8, 1); } -#endif } } @@ -434,7 +379,7 @@ void PostProcessing::renderPassThrough(GLuint tex) glUseProgram(FullScreenShader::PassThroughShader::getInstance()->Program); glBindVertexArray(FullScreenShader::PassThroughShader::getInstance()->vao); - setTexture(FullScreenShader::PassThroughShader::getInstance()->TU_tex, tex, GL_LINEAR, GL_LINEAR); + FullScreenShader::PassThroughShader::getInstance()->SetTextureUnits(createVector<GLuint>(tex)); FullScreenShader::PassThroughShader::getInstance()->setUniforms(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -459,7 +404,7 @@ void PostProcessing::renderGlow(unsigned tex) glUseProgram(FullScreenShader::GlowShader::getInstance()->Program); glBindVertexArray(FullScreenShader::GlowShader::getInstance()->vao); - setTexture(FullScreenShader::GlowShader::getInstance()->TU_tex, tex, GL_LINEAR, GL_LINEAR); + FullScreenShader::GlowShader::getInstance()->SetTextureUnits(createVector<GLuint>(tex)); FullScreenShader::GlowShader::getInstance()->setUniforms(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -473,11 +418,11 @@ void PostProcessing::renderSSAO() // Generate linear depth buffer irr_driver->getFBO(FBO_LINEAR_DEPTH).Bind(); - setTexture(FullScreenShader::LinearizeDepthShader::getInstance()->TU_tex, irr_driver->getDepthStencilTexture(), GL_LINEAR, GL_LINEAR); + FullScreenShader::LinearizeDepthShader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getDepthStencilTexture())); DrawFullScreenEffect<FullScreenShader::LinearizeDepthShader>(irr_driver->getSceneManager()->getActiveCamera()->getNearValue(), irr_driver->getSceneManager()->getActiveCamera()->getFarValue()); irr_driver->getFBO(FBO_SSAO).Bind(); - setTexture(FullScreenShader::SSAOShader::getInstance()->TU_dtex, irr_driver->getRenderTargetTexture(RTT_LINEAR_DEPTH), GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST); + FullScreenShader::SSAOShader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getRenderTargetTexture(RTT_LINEAR_DEPTH))); glGenerateMipmap(GL_TEXTURE_2D); DrawFullScreenEffect<FullScreenShader::SSAOShader>(irr_driver->getSSAORadius(), irr_driver->getSSAOK(), irr_driver->getSSAOSigma()); @@ -505,8 +450,8 @@ void PostProcessing::renderFog() glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - setTexture(FullScreenShader::FogShader::getInstance()->TU_tex, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); - DrawFullScreenEffect<FullScreenShader::FogShader>(fogmax, startH, endH, start, end, col); + FullScreenShader::FogShader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getDepthStencilTexture())); + DrawFullScreenEffect<FullScreenShader::FogShader>(fogmax, startH, endH, start, end, col); glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); @@ -533,10 +478,7 @@ void PostProcessing::renderMotionBlur(unsigned cam, FrameBuffer &in_fbo, FrameBu out_fbo.Bind(); glClear(GL_COLOR_BUFFER_BIT); - setTexture(FullScreenShader::MotionBlurShader::getInstance()->TU_cb, in_fbo.getRTT()[0], GL_LINEAR, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - setTexture(FullScreenShader::MotionBlurShader::getInstance()->TU_dtex, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); + FullScreenShader::MotionBlurShader::getInstance()->SetTextureUnits(createVector<GLuint>(in_fbo.getRTT()[0], irr_driver->getDepthStencilTexture())); DrawFullScreenEffect<FullScreenShader::MotionBlurShader>( // Todo : use a previousPVMatrix per cam, not global irr_driver->getPreviousPVMatrix(), @@ -549,7 +491,7 @@ static void renderGodFade(GLuint tex, const SColor &col) { glUseProgram(FullScreenShader::GodFadeShader::getInstance()->Program); glBindVertexArray(FullScreenShader::GodFadeShader::getInstance()->vao); - setTexture(FullScreenShader::GodFadeShader::getInstance()->TU_tex, tex, GL_LINEAR, GL_LINEAR); + FullScreenShader::GodFadeShader::getInstance()->SetTextureUnits(createVector<GLuint>(tex)); FullScreenShader::GodFadeShader::getInstance()->setUniforms(col); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -559,7 +501,7 @@ static void renderGodRay(GLuint tex, const core::vector2df &sunpos) { glUseProgram(FullScreenShader::GodRayShader::getInstance()->Program); glBindVertexArray(FullScreenShader::GodRayShader::getInstance()->vao); - setTexture(FullScreenShader::GodRayShader::getInstance()->TU_tex, tex, GL_LINEAR, GL_LINEAR); + FullScreenShader::GodRayShader::getInstance()->SetTextureUnits(createVector<GLuint>(tex)); FullScreenShader::GodRayShader::getInstance()->setUniforms(sunpos); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -568,15 +510,14 @@ static void renderGodRay(GLuint tex, const core::vector2df &sunpos) static void toneMap(FrameBuffer &fbo, GLuint rtt) { fbo.Bind(); - setTexture(FullScreenShader::ToneMapShader::getInstance()->TU_tex, rtt, GL_NEAREST, GL_NEAREST); + FullScreenShader::ToneMapShader::getInstance()->SetTextureUnits(createVector<GLuint>(rtt)); DrawFullScreenEffect<FullScreenShader::ToneMapShader>(); } static void renderDoF(FrameBuffer &fbo, GLuint rtt) { fbo.Bind(); - setTexture(FullScreenShader::DepthOfFieldShader::getInstance()->TU_tex, rtt, GL_LINEAR, GL_LINEAR); - setTexture(FullScreenShader::DepthOfFieldShader::getInstance()->TU_depth, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); + FullScreenShader::DepthOfFieldShader::getInstance()->SetTextureUnits(createVector<GLuint>(rtt, irr_driver->getDepthStencilTexture())); DrawFullScreenEffect<FullScreenShader::DepthOfFieldShader>(); } @@ -592,8 +533,8 @@ void PostProcessing::applyMLAA() glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // Pass 1: color edge detection - setTexture(FullScreenShader::MLAAColorEdgeDetectionSHader::getInstance()->TU_colorMapG, irr_driver->getRenderTargetTexture(RTT_MLAA_COLORS), GL_NEAREST, GL_NEAREST); glUseProgram(FullScreenShader::MLAAColorEdgeDetectionSHader::getInstance()->Program); + FullScreenShader::MLAAColorEdgeDetectionSHader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getRenderTargetTexture(RTT_MLAA_COLORS))); FullScreenShader::MLAAColorEdgeDetectionSHader::getInstance()->setUniforms(PIXEL_SIZE); glBindVertexArray(FullScreenShader::MLAAColorEdgeDetectionSHader::getInstance()->vao); @@ -607,8 +548,7 @@ void PostProcessing::applyMLAA() glClear(GL_COLOR_BUFFER_BIT); glUseProgram(FullScreenShader::MLAABlendWeightSHader::getInstance()->Program); - setTexture(FullScreenShader::MLAABlendWeightSHader::getInstance()->TU_edgesMap, irr_driver->getRenderTargetTexture(RTT_MLAA_TMP), GL_LINEAR, GL_LINEAR); - setTexture(FullScreenShader::MLAABlendWeightSHader::getInstance()->TU_areaMap, getTextureGLuint(m_areamap), GL_NEAREST, GL_NEAREST); + FullScreenShader::MLAABlendWeightSHader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getRenderTargetTexture(RTT_MLAA_TMP), getTextureGLuint(m_areamap))); FullScreenShader::MLAABlendWeightSHader::getInstance()->setUniforms(PIXEL_SIZE); glBindVertexArray(FullScreenShader::MLAABlendWeightSHader::getInstance()->vao); @@ -621,8 +561,7 @@ void PostProcessing::applyMLAA() irr_driver->getFBO(FBO_MLAA_COLORS).Bind(); glUseProgram(FullScreenShader::MLAAGatherSHader::getInstance()->Program); - setTexture(FullScreenShader::MLAAGatherSHader::getInstance()->TU_colorMap, irr_driver->getRenderTargetTexture(RTT_MLAA_TMP), GL_NEAREST, GL_NEAREST); - setTexture(FullScreenShader::MLAAGatherSHader::getInstance()->TU_blendMap, irr_driver->getRenderTargetTexture(RTT_MLAA_BLEND), GL_NEAREST, GL_NEAREST); + FullScreenShader::MLAAGatherSHader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getRenderTargetTexture(RTT_MLAA_BLEND), irr_driver->getRenderTargetTexture(RTT_MLAA_TMP))); FullScreenShader::MLAAGatherSHader::getInstance()->setUniforms(PIXEL_SIZE); glBindVertexArray(FullScreenShader::MLAAGatherSHader::getInstance()->vao); @@ -661,8 +600,10 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, boo if (World::getWorld() != NULL) hasgodrays = World::getWorld()->getTrack()->hasGodRays(); - if (isRace && UserConfigParams::m_light_shaft && m_sunpixels > 30 && hasgodrays) + if (isRace && UserConfigParams::m_light_shaft && hasgodrays) { + Track* track = World::getWorld()->getTrack(); + glEnable(GL_DEPTH_TEST); // Grab the sky out_fbo->Bind(); @@ -670,12 +611,14 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, boo irr_driver->renderSkybox(camnode); // Set the sun's color - const SColor col = World::getWorld()->getTrack()->getSunColor(); + const SColor col = track->getGodRaysColor(); ColorizeProvider * const colcb = (ColorizeProvider *)irr_driver->getCallback(ES_COLORIZE); colcb->setColor(col.getRed() / 255.0f, col.getGreen() / 255.0f, col.getBlue() / 255.0f); // The sun interposer STKMeshSceneNode *sun = irr_driver->getSunInterposer(); + sun->setPosition(track->getGodRaysPosition()); + sun->updateAbsolutePosition(); irr_driver->getSceneManager()->drawAll(ESNRP_CAMERA); irr_driver->setPhase(GLOW_PASS); sun->render(); @@ -690,7 +633,7 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, boo renderGaussian3Blur(irr_driver->getFBO(FBO_QUARTER1), irr_driver->getFBO(FBO_QUARTER2)); // Calculate the sun's position in texcoords - const core::vector3df pos = sun->getPosition(); + const core::vector3df pos = track->getGodRaysPosition(); float ndc[4]; core::matrix4 trans = camnode->getProjectionMatrix(); trans *= camnode->getViewMatrix(); @@ -753,9 +696,8 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, boo glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); - setTexture(FullScreenShader::BloomBlendShader::getInstance()->TU_tex_128, irr_driver->getRenderTargetTexture(RTT_BLOOM_128), GL_LINEAR, GL_LINEAR); - setTexture(FullScreenShader::BloomBlendShader::getInstance()->TU_tex_256, irr_driver->getRenderTargetTexture(RTT_BLOOM_256), GL_LINEAR, GL_LINEAR); - setTexture(FullScreenShader::BloomBlendShader::getInstance()->TU_tex_512, irr_driver->getRenderTargetTexture(RTT_BLOOM_512), GL_LINEAR, GL_LINEAR); + FullScreenShader::BloomBlendShader::getInstance()->SetTextureUnits(createVector<GLuint>( + irr_driver->getRenderTargetTexture(RTT_BLOOM_128), irr_driver->getRenderTargetTexture(RTT_BLOOM_256), irr_driver->getRenderTargetTexture(RTT_BLOOM_512) )); DrawFullScreenEffect<FullScreenShader::BloomBlendShader>(); glDisable(GL_BLEND); @@ -784,6 +726,10 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, boo PROFILER_POP_CPU_MARKER(); } + // Workaround a bug with srgb fbo on sandy bridge windows + if (irr_driver->needUBOWorkaround()) + return in_fbo; + glEnable(GL_FRAMEBUFFER_SRGB); irr_driver->getFBO(FBO_MLAA_COLORS).Bind(); renderPassThrough(in_fbo->getRTT()[0]); diff --git a/src/graphics/referee.cpp b/src/graphics/referee.cpp index ced299263..8dc78b7e1 100644 --- a/src/graphics/referee.cpp +++ b/src/graphics/referee.cpp @@ -19,6 +19,7 @@ #include "graphics/referee.hpp" #include "graphics/irr_driver.hpp" +#include "graphics/light.hpp" #include "graphics/mesh_tools.hpp" #include "karts/abstract_kart.hpp" #include "io/file_manager.hpp" @@ -36,7 +37,6 @@ Vec3 Referee::m_st_start_offset = Vec3(-2, 2, 2); Vec3 Referee::m_st_start_rotation = Vec3(0, 180, 0); Vec3 Referee::m_st_scale = Vec3(1, 1, 1); scene::IAnimatedMesh *Referee::m_st_referee_mesh = NULL; -video::ITexture *Referee::m_st_traffic_lights[3] = {NULL, NULL, NULL}; // ---------------------------------------------------------------------------- /** Loads the static mesh. @@ -93,23 +93,6 @@ void Referee::init() * RAD_TO_DEGREE; m_st_start_rotation.setY(m_st_start_rotation.getY()+angle_to_kart); - std::vector<std::string> colors; - node->get("colors", &colors); - - if(colors.size()>3) - Log::warn("referee", "Too many colors for referee defined, " - "only first three will be used."); - if(colors.size()<3) - { - Log::fatal("referee", - "Not enough colors for referee defined, aborting."); - } - for(unsigned int i=0; i<3; i++) - { - m_st_traffic_lights[i] = irr_driver->getTexture(FileManager::MODEL, colors[i]); - } - - for(unsigned int i=0; i<m_st_referee_mesh->getMeshBufferCount(); i++) { scene::IMeshBuffer *mb = m_st_referee_mesh->getMeshBuffer(i); @@ -119,7 +102,7 @@ void Referee::init() std::string name=StringUtils::getBasename(t->getName() .getInternalName().c_str()); - if(name==colors[0] || name==colors[1] ||name==colors[2] ) + if (name == "traffic_light.png") { m_st_traffic_buffer = i; break; @@ -166,6 +149,16 @@ Referee::Referee() m_st_last_start_frame); irr_driver->applyObjectPassShader(m_scene_node); + + if (irr_driver->isGLSL() && UserConfigParams::m_dynamic_lights) + { + m_light = irr_driver->addLight(core::vector3df(0.0f, 0.0f, 0.6f), 0.7f, 2.0f, + 0.7f /* r */, 0.0 /* g */, 0.0f /* b */, false /* sun */, m_scene_node); + } + else + { + m_light = NULL; + } } // Referee // ---------------------------------------------------------------------------- @@ -212,6 +205,9 @@ void Referee::attachToSceneNode() if(!m_scene_node->getParent()) m_scene_node->setParent(irr_driver->getSceneManager() ->getRootSceneNode()); + + if (m_light != NULL) + m_light->setVisible(true); } // attachToSceneNode // ---------------------------------------------------------------------------- @@ -223,6 +219,8 @@ void Referee::removeFromSceneGraph() { if(isAttached()) irr_driver->removeNode(m_scene_node); + if (m_light != NULL) + m_light->setVisible(false); } // removeFromSceneGraph // ---------------------------------------------------------------------------- @@ -232,9 +230,31 @@ void Referee::removeFromSceneGraph() */ void Referee::selectReadySetGo(int rsg) { - if(m_st_traffic_buffer<0) return; - video::SMaterial &m = m_scene_node->getMesh()->getMeshBuffer(m_st_traffic_buffer)->getMaterial(); - m.setTexture(0, m_st_traffic_lights[rsg]); + if (m_st_traffic_buffer < 0) + return; + video::SMaterial &m = m_scene_node->getMaterial(m_st_traffic_buffer); // m_scene_node->getMesh()->getMeshBuffer(m_st_traffic_buffer)->getMaterial(); + + //if (irr_driver->isGLSL() && UserConfigParams::m_dynamic_lights) + // m.MaterialType = irr_driver->getShader(ES_OBJECT_UNLIT); + + core::matrix4* matrix = &m.getTextureMatrix(0); + matrix->setTextureTranslate(0.0f, rsg*0.333f); + + if (m_light != NULL) + { + if (rsg == 0) + { + ((LightNode*)m_light)->setColor(0.6f, 0.0f, 0.0f); + } + else if (rsg == 1) + { + ((LightNode*)m_light)->setColor(0.7f, 0.23f, 0.0f); + } + else if (rsg == 2) + { + ((LightNode*)m_light)->setColor(0.0f, 0.6f, 0.0f); + } + } // disable lighting, we need to see the traffic light even if facing away // from the sun diff --git a/src/graphics/referee.hpp b/src/graphics/referee.hpp index 93941f051..754d5ef86 100644 --- a/src/graphics/referee.hpp +++ b/src/graphics/referee.hpp @@ -79,6 +79,8 @@ private: /** The scene node for an instance of the referee. */ scene::IAnimatedMeshSceneNode *m_scene_node; + scene::ISceneNode* m_light; + public: Referee(); Referee(const AbstractKart &kart); diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 28544dc33..ee510d776 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -34,7 +34,6 @@ #include "graphics/screenquad.hpp" #include "graphics/shaders.hpp" #include "graphics/stkmeshscenenode.hpp" -#include "graphics/stkinstancedscenenode.hpp" #include "graphics/wind.hpp" #include "io/file_manager.hpp" #include "items/item.hpp" @@ -47,6 +46,7 @@ #include "utils/helpers.hpp" #include "utils/log.hpp" #include "utils/profiler.hpp" +#include "stkscenemanager.hpp" #include <algorithm> #include <limits> @@ -148,8 +148,12 @@ void IrrDriver::renderGLSL(float dt) // TODO: put this outside of the rendering loop generateDiffuseCoefficients(); + PROFILER_PUSH_CPU_MARKER("Update Light Info", 0xFF, 0x0, 0x0); unsigned plc = UpdateLightsInfo(camnode, dt); + PROFILER_POP_CPU_MARKER(); + PROFILER_PUSH_CPU_MARKER("Compute camera matrix", 0x0, 0xFF, 0x0); computeCameraMatrix(camnode, viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X, viewport.LowerRightCorner.Y - viewport.UpperLeftCorner.Y); + PROFILER_POP_CPU_MARKER(); renderScene(camnode, plc, glows, dt, track->hasShadows(), false); // Debug physic @@ -272,22 +276,30 @@ void IrrDriver::renderGLSL(float dt) void IrrDriver::renderScene(scene::ICameraSceneNode * const camnode, unsigned pointlightcount, std::vector<GlowData>& glows, float dt, bool hasShadow, bool forceRTT) { glBindBufferBase(GL_UNIFORM_BUFFER, 0, SharedObject::ViewProjectionMatrixesUBO); + m_scene_manager->setActiveCamera(camnode); + PROFILER_PUSH_CPU_MARKER("- Draw Call Generation", 0xFF, 0xFF, 0xFF); + PrepareDrawCalls(camnode); + PROFILER_POP_CPU_MARKER(); // Shadows { - PROFILER_PUSH_CPU_MARKER("- Shadow", 0x30, 0x6F, 0x90); - ScopedGPUTimer Timer(getGPUTimer(Q_SHADOWS)); // To avoid wrong culling, use the largest view possible m_scene_manager->setActiveCamera(m_suncam); if (!m_mipviz && !m_wireframe && UserConfigParams::m_dynamic_lights && UserConfigParams::m_shadows && !irr_driver->needUBOWorkaround() && hasShadow) { + PROFILER_PUSH_CPU_MARKER("- Shadow", 0x30, 0x6F, 0x90); renderShadows(); + PROFILER_POP_CPU_MARKER(); if (UserConfigParams::m_gi) + { + PROFILER_PUSH_CPU_MARKER("- RSM", 0xFF, 0x0, 0xFF); renderRSM(); + PROFILER_POP_CPU_MARKER(); + } } m_scene_manager->setActiveCamera(camnode); - PROFILER_POP_CPU_MARKER(); + } PROFILER_PUSH_CPU_MARKER("- Solid Pass 1", 0xFF, 0x00, 0x00); @@ -323,6 +335,8 @@ void IrrDriver::renderScene(scene::ICameraSceneNode * const camnode, unsigned po renderSolidSecondPass(); PROFILER_POP_CPU_MARKER(); + m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + if (getNormals()) { m_rtts->getFBO(FBO_NORMAL_AND_DEPTHS).Bind(); @@ -480,29 +494,25 @@ void IrrDriver::computeSunVisibility() hasgodrays = World::getWorld()->getTrack()->hasGodRays(); } - irr::video::COpenGLDriver* gl_driver = (irr::video::COpenGLDriver*)m_device->getVideoDriver(); - if (UserConfigParams::m_light_shaft && hasgodrays)//hasflare || hasgodrays) + if (UserConfigParams::m_light_shaft && hasgodrays) { GLuint res = 0; if (m_query_issued) - gl_driver->extGlGetQueryObjectuiv(m_lensflare_query, GL_QUERY_RESULT, &res); + glGetQueryObjectuiv(m_lensflare_query, GL_QUERY_RESULT, &res); m_post_processing->setSunPixels(res); // Prepare the query for the next frame. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - gl_driver->extGlBeginQuery(GL_SAMPLES_PASSED_ARB, m_lensflare_query); + glBeginQuery(GL_SAMPLES_PASSED_ARB, m_lensflare_query); m_scene_manager->setCurrentRendertime(scene::ESNRP_SOLID); m_scene_manager->drawAll(scene::ESNRP_CAMERA); irr_driver->setPhase(GLOW_PASS); m_sun_interposer->render(); - gl_driver->extGlEndQuery(GL_SAMPLES_PASSED_ARB); + glEndQuery(GL_SAMPLES_PASSED_ARB); m_query_issued = true; m_lensflare->setStrength(res / 4000.0f); - if (hasflare) - m_lensflare->OnRegisterSceneNode(); - // Make sure the color mask is reset glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } @@ -514,7 +524,9 @@ void IrrDriver::renderParticles() glDisable(GL_CULL_FACE); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - m_scene_manager->drawAll(scene::ESNRP_TRANSPARENT_EFFECT); + for (unsigned i = 0; i < ParticlesList::getInstance()->size(); ++i) + ParticlesList::getInstance()->at(i)->render(); +// m_scene_manager->drawAll(scene::ESNRP_TRANSPARENT_EFFECT); } /** Given a matrix transform and a set of points returns an orthogonal projection matrix that maps coordinates of @@ -584,14 +596,20 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz 50., }; - float *tmp = new float[18 * 8]; + float tmp[16 * 9 + 2]; memcpy(tmp, irr_driver->getViewMatrix().pointer(), 16 * sizeof(float)); memcpy(&tmp[16], irr_driver->getProjMatrix().pointer(), 16 * sizeof(float)); memcpy(&tmp[32], irr_driver->getInvViewMatrix().pointer(), 16 * sizeof(float)); memcpy(&tmp[48], irr_driver->getInvProjMatrix().pointer(), 16 * sizeof(float)); + memcpy(&tmp[64], irr_driver->getProjViewMatrix().pointer(), 16 * sizeof(float)); const core::matrix4 &SunCamViewMatrix = m_suncam->getViewMatrix(); + for (unsigned i = 0; i < 4; i++) + { + if (!m_shadow_camnodes[i]) + m_shadow_camnodes[i] = (scene::ICameraSceneNode *) m_suncam->clone(); + } sun_ortho_matrix.clear(); if (World::getWorld() && World::getWorld()->getTrack()) @@ -669,8 +687,8 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz const float units_per_w = w / 1024; const float units_per_h = h / 1024;*/ - m_suncam->setProjectionMatrix(getTighestFitOrthoProj(SunCamViewMatrix, vectors) , true); - m_suncam->render(); + m_shadow_camnodes[i]->setProjectionMatrix(getTighestFitOrthoProj(SunCamViewMatrix, vectors) , true); + m_shadow_camnodes[i]->render(); sun_ortho_matrix.push_back(getVideoDriver()->getTransform(video::ETS_PROJECTION) * getVideoDriver()->getTransform(video::ETS_VIEW)); } @@ -702,18 +720,17 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz assert(sun_ortho_matrix.size() == 4); camnode->setNearValue(oldnear); camnode->setFarValue(oldfar); + camnode->render(); size_t size = irr_driver->getShadowViewProj().size(); for (unsigned i = 0; i < size; i++) - memcpy(&tmp[16 * i + 64], irr_driver->getShadowViewProj()[i].pointer(), 16 * sizeof(float)); + memcpy(&tmp[16 * i + 80], irr_driver->getShadowViewProj()[i].pointer(), 16 * sizeof(float)); } - tmp[128] = float(width); - tmp[129] = float(height); - + tmp[144] = float(width); + tmp[145] = float(height); glBindBuffer(GL_UNIFORM_BUFFER, SharedObject::ViewProjectionMatrixesUBO); - glBufferSubData(GL_UNIFORM_BUFFER, 0, (16 * 8 + 2) * sizeof(float), tmp); - delete []tmp; + glBufferSubData(GL_UNIFORM_BUFFER, 0, (16 * 9 + 2) * sizeof(float), tmp); } @@ -770,20 +787,40 @@ void IrrDriver::renderGlow(std::vector<GlowData>& glows) glDepthMask(GL_FALSE); glDisable(GL_BLEND); - glBindVertexArray(getVAO(EVT_STANDARD)); + if (irr_driver->hasARB_base_instance()) + glBindVertexArray(VAOManager::getInstance()->getVAO(EVT_STANDARD)); for (u32 i = 0; i < glowcount; i++) { const GlowData &dat = glows[i]; - scene::ISceneNode * const cur = dat.node; + scene::ISceneNode * cur = dat.node; - //TODO : implement culling on gpu - // Quick box-based culling -// const core::aabbox3df nodebox = cur->getTransformedBoundingBox(); -// if (!nodebox.intersectsWithBox(cambox)) -// continue; + STKMeshSceneNode *node = static_cast<STKMeshSceneNode *>(cur); + node->setGlowColors(SColor(0, (unsigned) (dat.b * 255.f), (unsigned)(dat.g * 255.f), (unsigned)(dat.r * 255.f))); + if (!irr_driver->hasARB_draw_indirect()) + node->render(); + } - cb->setColor(dat.r, dat.g, dat.b); - cur->render(); + if (irr_driver->hasARB_draw_indirect()) + { + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, GlowPassCmd::getInstance()->drawindirectcmd); + glUseProgram(MeshShader::InstancedColorizeShader::getInstance()->Program); + + glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(video::EVT_STANDARD, InstanceTypeGlow)); + if (UserConfigParams::m_azdo) + { + if (GlowPassCmd::getInstance()->Size) + { + glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, + (const void*)(GlowPassCmd::getInstance()->Offset * sizeof(DrawElementsIndirectCommand)), + GlowPassCmd::getInstance()->Size, + sizeof(DrawElementsIndirectCommand)); + } + } + else + { + for (unsigned i = 0; i < ListInstancedGlow::getInstance()->size(); i++) + glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)((GlowPassCmd::getInstance()->Offset + i) * sizeof(DrawElementsIndirectCommand))); + } } glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); diff --git a/src/graphics/render_geometry.cpp b/src/graphics/render_geometry.cpp index e589d9453..74c89078b 100644 --- a/src/graphics/render_geometry.cpp +++ b/src/graphics/render_geometry.cpp @@ -16,7 +16,6 @@ #include "graphics/screenquad.hpp" #include "graphics/shaders.hpp" #include "graphics/stkmeshscenenode.hpp" -#include "graphics/stkinstancedscenenode.hpp" #include "graphics/wind.hpp" #include "io/file_manager.hpp" #include "items/item.hpp" @@ -29,6 +28,7 @@ #include "utils/log.hpp" #include "utils/profiler.hpp" #include "utils/tuple.hpp" +#include "stkscenemanager.hpp" #include <algorithm> @@ -116,19 +116,24 @@ struct custom_unroll_args<N, List...> template<typename Shader, enum E_VERTEX_TYPE VertexType, int ...List, typename... TupleType> -void renderMeshes1stPass(const std::vector<TexUnit> &TexUnits, std::vector<STK::Tuple<TupleType...> > *meshes) +void renderMeshes1stPass(const std::vector<TexUnit> &TexUnits, std::vector<STK::Tuple<TupleType...> > &meshes) { glUseProgram(Shader::getInstance()->Program); - glBindVertexArray(getVAO(VertexType)); - for (unsigned i = 0; i < meshes->size(); i++) + if (irr_driver->hasARB_base_instance()) + glBindVertexArray(VAOManager::getInstance()->getVAO(VertexType)); + for (unsigned i = 0; i < meshes.size(); i++) { - GLMesh &mesh = *(STK::tuple_get<0>(meshes->at(i))); + std::vector<GLuint> Textures; + std::vector<uint64_t> Handles; + GLMesh &mesh = *(STK::tuple_get<0>(meshes.at(i))); + if (!irr_driver->hasARB_base_instance()) + glBindVertexArray(mesh.vao); for (unsigned j = 0; j < TexUnits.size(); j++) { - if (!mesh.textures[j]) - mesh.textures[j] = getUnicolorTexture(video::SColor(255, 255, 255, 255)); - compressTexture(mesh.textures[j], TexUnits[j].m_premul_alpha); - setTexture(TexUnits[j].m_id, getTextureGLuint(mesh.textures[j]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + if (UserConfigParams::m_azdo) + Handles.push_back(mesh.TextureHandles[TexUnits[j].m_id]); + else + Textures.push_back(getTextureGLuint(mesh.textures[TexUnits[j].m_id])); } if (mesh.VAOType != VertexType) { @@ -137,68 +142,61 @@ void renderMeshes1stPass(const std::vector<TexUnit> &TexUnits, std::vector<STK:: #endif continue; } - custom_unroll_args<List...>::template exec(Shader::getInstance(), meshes->at(i)); + + if (UserConfigParams::m_azdo) + Shader::getInstance()->SetTextureHandles(Handles); + else + Shader::getInstance()->SetTextureUnits(Textures); + custom_unroll_args<List...>::template exec(Shader::getInstance(), meshes.at(i)); } } -template<int...List> -struct instanced_custom_unroll_args; - -template<> -struct instanced_custom_unroll_args<> -{ - template<typename T, typename ...TupleTypes, typename ...Args> - static void exec(const T *Shader, const STK::Tuple<TupleTypes...> &t, Args... args) - { - const GLMesh *mesh = STK::tuple_get<0>(t); - size_t instance_count = STK::tuple_get<1>(t); - irr_driver->IncreaseObjectCount(); - GLenum ptype = mesh->PrimitiveType; - GLenum itype = mesh->IndexType; - size_t count = mesh->IndexCount; - - Shader->setUniforms(args...); - glDrawElementsInstanced(ptype, count, itype, 0, instance_count); - } -}; - -template<int N, int...List> -struct instanced_custom_unroll_args<N, List...> -{ - template<typename T, typename ...TupleTypes, typename ...Args> - static void exec(const T *Shader, const STK::Tuple<TupleTypes...> &t, Args... args) - { - instanced_custom_unroll_args<List...>::template exec<T>(Shader, t, STK::tuple_get<N>(t), args...); - } -}; - -template<typename Shader, enum E_VERTEX_TYPE VertexType, int ...List, typename... TupleType> -void renderInstancedMeshes1stPass(const std::vector<TexUnit> &TexUnits, std::vector<STK::Tuple<TupleType...> > *meshes) +#ifdef Draw_Indirect +template<typename Shader, MeshMaterial Mat, video::E_VERTEX_TYPE VT, typename...Args> +void renderInstancedMeshes1stPass(const std::vector<TexUnit> &TexUnits, std::vector<GLMesh *> &meshes, Args...args) { glUseProgram(Shader::getInstance()->Program); - for (unsigned i = 0; i < meshes->size(); i++) + glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(VT, InstanceTypeDefault)); + for (unsigned i = 0; i < meshes.size(); i++) { - GLMesh &mesh = *(STK::tuple_get<0>(meshes->at(i))); + std::vector<GLuint> Textures; + GLMesh *mesh = meshes[i]; #ifdef DEBUG - if (mesh.VAOType != VertexType) + if (mesh->VAOType != VT) Log::error("RenderGeometry", "Wrong instanced vertex format"); #endif - glBindVertexArray(mesh.vao); for (unsigned j = 0; j < TexUnits.size(); j++) - { - if (!mesh.textures[j]) - mesh.textures[j] = getUnicolorTexture(video::SColor(255, 255, 255, 255)); - compressTexture(mesh.textures[j], TexUnits[j].m_premul_alpha); - setTexture(TexUnits[j].m_id, getTextureGLuint(mesh.textures[j]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - } - instanced_custom_unroll_args<List...>::template exec(Shader::getInstance(), meshes->at(i)); + Textures.push_back(getTextureGLuint(mesh->textures[TexUnits[j].m_id])); + Shader::getInstance()->SetTextureUnits(Textures); + + Shader::getInstance()->setUniforms(args...); + glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)((SolidPassCmd::getInstance()->Offset[Mat] + i) * sizeof(DrawElementsIndirectCommand))); } } +#endif -static GLsync m_sync; +#ifdef Multi_Draw_Indirect +template<typename Shader, MeshMaterial Mat, video::E_VERTEX_TYPE VT, typename...Args> +void multidraw1stPass(Args...args) +{ + glUseProgram(Shader::getInstance()->Program); + glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(VT, InstanceTypeDefault)); + if (SolidPassCmd::getInstance()->Size[Mat]) + { + Shader::getInstance()->setUniforms(args...); + glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, + (const void*)(SolidPassCmd::getInstance()->Offset[Mat] * sizeof(DrawElementsIndirectCommand)), + SolidPassCmd::getInstance()->Size[Mat], + sizeof(DrawElementsIndirectCommand)); + } +} +#endif + +static core::vector3df windDir; void IrrDriver::renderSolidFirstPass() { + windDir = getWindDir(); m_rtts->getFBO(FBO_NORMAL_AND_DEPTHS).Bind(); glClearColor(0., 0., 0., 0.); glDepthMask(GL_TRUE); @@ -209,96 +207,96 @@ void IrrDriver::renderSolidFirstPass() glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); glEnable(GL_CULL_FACE); - irr_driver->setPhase(SOLID_NORMAL_AND_DEPTH_PASS); - ListMatDefault::getInstance()->clear(); - ListMatAlphaRef::getInstance()->clear(); - ListMatSphereMap::getInstance()->clear(); - ListMatDetails::getInstance()->clear(); - ListMatUnlit::getInstance()->clear(); - ListMatNormalMap::getInstance()->clear(); - ListMatGrass::getInstance()->clear(); - ListMatSplatting::getInstance()->clear(); - ListInstancedMatDefault::getInstance()->clear(); - ListInstancedMatAlphaRef::getInstance()->clear(); - ListInstancedMatGrass::getInstance()->clear(); - ListInstancedMatNormalMap::getInstance()->clear(); - // Add a 30 ms timeout - GLenum reason = glClientWaitSync(m_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 30000000); -/* switch (reason) - { - case GL_ALREADY_SIGNALED: - printf("Already Signaled\n"); - break; - case GL_TIMEOUT_EXPIRED: - printf("Timeout Expired\n"); - break; - case GL_CONDITION_SATISFIED: - printf("Condition Satisfied\n"); - break; - case GL_WAIT_FAILED: - printf("Wait Failed\n"); - break; - }*/ - m_scene_manager->drawAll(scene::ESNRP_SOLID); if (!UserConfigParams::m_dynamic_lights) return; { ScopedGPUTimer Timer(getGPUTimer(Q_SOLID_PASS1)); + irr_driver->setPhase(SOLID_NORMAL_AND_DEPTH_PASS); - std::vector<TexUnit> object_pass1_texunits = TexUnits(TexUnit(MeshShader::ObjectPass1Shader::getInstance()->TU_tex, true) ); - renderMeshes1stPass<MeshShader::ObjectPass1Shader, video::EVT_STANDARD, 2, 1>(object_pass1_texunits, ListMatDefault::getInstance()); - renderMeshes1stPass<MeshShader::ObjectPass1Shader, video::EVT_STANDARD, 2, 1>(object_pass1_texunits, ListMatSphereMap::getInstance()); - renderMeshes1stPass<MeshShader::ObjectPass1Shader, video::EVT_2TCOORDS, 2, 1>(object_pass1_texunits, ListMatDetails::getInstance()); - renderMeshes1stPass<MeshShader::ObjectPass1Shader, video::EVT_2TCOORDS, 2, 1>(object_pass1_texunits, ListMatSplatting::getInstance()); - renderMeshes1stPass<MeshShader::ObjectRefPass1Shader, video::EVT_STANDARD, 3, 2, 1>(object_pass1_texunits, ListMatUnlit::getInstance()); - renderMeshes1stPass<MeshShader::ObjectRefPass1Shader, video::EVT_STANDARD, 3, 2, 1>(TexUnits(TexUnit(MeshShader::ObjectRefPass1Shader::getInstance()->TU_tex, true)), ListMatAlphaRef::getInstance()); - renderMeshes1stPass<MeshShader::GrassPass1Shader, video::EVT_STANDARD, 3, 2, 1>(TexUnits(TexUnit(MeshShader::GrassPass1Shader::getInstance()->TU_tex, true)), ListMatGrass::getInstance()); + for (unsigned i = 0; i < ImmediateDrawList::getInstance()->size(); i++) + ImmediateDrawList::getInstance()->at(i)->render(); + + std::vector<TexUnit> object_pass1_texunits = TexUnits(TexUnit(0, true) ); + renderMeshes1stPass<MeshShader::ObjectPass1Shader, video::EVT_STANDARD, 2, 1>(object_pass1_texunits, ListMatDefault::getInstance()->SolidPass); + renderMeshes1stPass<MeshShader::ObjectPass1Shader, video::EVT_2TCOORDS, 2, 1>(object_pass1_texunits, ListMatSplatting::getInstance()->SolidPass); + renderMeshes1stPass<MeshShader::ObjectRefPass1Shader, video::EVT_STANDARD, 3, 2, 1>(object_pass1_texunits, ListMatUnlit::getInstance()->SolidPass); + renderMeshes1stPass<MeshShader::ObjectRefPass1Shader, video::EVT_STANDARD, 3, 2, 1>(TexUnits(TexUnit(0, true)), ListMatAlphaRef::getInstance()->SolidPass); + renderMeshes1stPass<MeshShader::GrassPass1Shader, video::EVT_STANDARD, 3, 2, 1>(TexUnits(TexUnit(0, true)), ListMatGrass::getInstance()->SolidPass); renderMeshes1stPass<MeshShader::NormalMapShader, video::EVT_TANGENTS, 2, 1>(TexUnits( - TexUnit(MeshShader::NormalMapShader::getInstance()->TU_glossy, true), - TexUnit(MeshShader::NormalMapShader::getInstance()->TU_normalmap, false) - ), ListMatNormalMap::getInstance()); + TexUnit(1, false), + TexUnit(0, true) + ), ListMatNormalMap::getInstance()->SolidPass); + renderMeshes1stPass<MeshShader::ObjectPass1Shader, video::EVT_STANDARD, 2, 1>(object_pass1_texunits, ListMatSphereMap::getInstance()->SolidPass); + renderMeshes1stPass<MeshShader::ObjectPass1Shader, video::EVT_2TCOORDS, 2, 1>(object_pass1_texunits, ListMatDetails::getInstance()->SolidPass); - renderInstancedMeshes1stPass<MeshShader::InstancedObjectPass1Shader, video::EVT_STANDARD>( - TexUnits(TexUnit(MeshShader::InstancedObjectPass1Shader::getInstance()->TU_tex, true)), - ListInstancedMatDefault::getInstance()); - renderInstancedMeshes1stPass<MeshShader::InstancedObjectRefPass1Shader, video::EVT_STANDARD>( - TexUnits(TexUnit(MeshShader::InstancedObjectRefPass1Shader::getInstance()->TU_tex, true)), - ListInstancedMatAlphaRef::getInstance()); - renderInstancedMeshes1stPass<MeshShader::InstancedGrassPass1Shader, video::EVT_STANDARD, 2>( - TexUnits(TexUnit(MeshShader::InstancedGrassPass1Shader::getInstance()->TU_tex, true)), - ListInstancedMatGrass::getInstance()); - renderInstancedMeshes1stPass<MeshShader::InstancedNormalMapShader, video::EVT_TANGENTS>( - TexUnits(TexUnit(MeshShader::InstancedNormalMapShader::getInstance()->TU_glossy, true), TexUnit(MeshShader::InstancedNormalMapShader::getInstance()->TU_normalmap, false)), - ListInstancedMatNormalMap::getInstance()); + if (irr_driver->hasARB_draw_indirect()) + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, SolidPassCmd::getInstance()->drawindirectcmd); + + if (UserConfigParams::m_azdo) + { +#ifdef Multi_Draw_Indirect + multidraw1stPass<MeshShader::InstancedObjectPass1Shader, MAT_DEFAULT, video::EVT_STANDARD>(); + multidraw1stPass<MeshShader::InstancedObjectRefPass1Shader, MAT_ALPHA_REF, video::EVT_STANDARD>(); + multidraw1stPass<MeshShader::InstancedNormalMapShader, MAT_NORMAL_MAP, video::EVT_TANGENTS>(); + multidraw1stPass<MeshShader::InstancedObjectPass1Shader, MAT_SPHEREMAP, video::EVT_STANDARD>(); + multidraw1stPass<MeshShader::InstancedObjectPass1Shader, MAT_DETAIL, video::EVT_2TCOORDS>(); + multidraw1stPass<MeshShader::InstancedObjectRefPass1Shader, MAT_UNLIT, video::EVT_STANDARD>(); + multidraw1stPass<MeshShader::InstancedGrassPass1Shader, MAT_GRASS, video::EVT_STANDARD>(windDir); +#endif + } +#ifdef Draw_Indirect + else if (irr_driver->hasARB_draw_indirect()) + { + // Default + renderInstancedMeshes1stPass<MeshShader::InstancedObjectPass1Shader, MAT_DEFAULT, video::EVT_STANDARD>( + TexUnits(TexUnit(0, true)), ListInstancedMatDefault::getInstance()->SolidPass); + // Alpha ref + renderInstancedMeshes1stPass<MeshShader::InstancedObjectRefPass1Shader, MAT_ALPHA_REF, video::EVT_STANDARD>( + TexUnits(TexUnit(0, true)), ListInstancedMatAlphaRef::getInstance()->SolidPass); + // Unlit + renderInstancedMeshes1stPass<MeshShader::InstancedObjectPass1Shader, MAT_UNLIT, video::EVT_STANDARD>( + TexUnits(TexUnit(0, true)), ListInstancedMatUnlit::getInstance()->SolidPass); + // Spheremap + renderInstancedMeshes1stPass<MeshShader::InstancedObjectPass1Shader, MAT_SPHEREMAP, video::EVT_STANDARD>( + TexUnits(TexUnit(0, true)), ListInstancedMatSphereMap::getInstance()->SolidPass); + // Grass + renderInstancedMeshes1stPass<MeshShader::InstancedGrassPass1Shader, MAT_GRASS, video::EVT_STANDARD>( + TexUnits(TexUnit(0, true)), ListInstancedMatGrass::getInstance()->SolidPass, windDir); + + // Detail + renderInstancedMeshes1stPass<MeshShader::InstancedObjectPass1Shader, MAT_DETAIL, video::EVT_2TCOORDS>( + TexUnits(TexUnit(0, true)), ListInstancedMatDetails::getInstance()->SolidPass); + + // Normal Map + renderInstancedMeshes1stPass<MeshShader::InstancedNormalMapShader, MAT_NORMAL_MAP, video::EVT_TANGENTS>( + TexUnits(TexUnit(1, false), TexUnit(0, true)), ListInstancedMatNormalMap::getInstance()->SolidPass); + } +#endif } } template<typename Shader, enum E_VERTEX_TYPE VertexType, int...List, typename... TupleType> -void renderMeshes2ndPass(const std::vector<TexUnit> &TexUnits, std::vector<STK::Tuple<TupleType...> > *meshes) +void renderMeshes2ndPass(const std::vector<TexUnit> &TexUnits, std::vector<STK::Tuple<TupleType...> > &meshes, const std::vector<uint64_t> &Prefilled_Handle, + const std::vector<GLuint> &Prefilled_Tex) { glUseProgram(Shader::getInstance()->Program); - glBindVertexArray(getVAO(VertexType)); - for (unsigned i = 0; i < meshes->size(); i++) + if (irr_driver->hasARB_base_instance()) + glBindVertexArray(VAOManager::getInstance()->getVAO(VertexType)); + for (unsigned i = 0; i < meshes.size(); i++) { - GLMesh &mesh = *(STK::tuple_get<0>(meshes->at(i))); + std::vector<uint64_t> Handles(Prefilled_Handle); + std::vector<GLuint> Textures(Prefilled_Tex); + GLMesh &mesh = *(STK::tuple_get<0>(meshes.at(i))); + if (!irr_driver->hasARB_base_instance()) + glBindVertexArray(mesh.vao); for (unsigned j = 0; j < TexUnits.size(); j++) { - if (!mesh.textures[j]) - mesh.textures[j] = getUnicolorTexture(video::SColor(255, 255, 255, 255)); - compressTexture(mesh.textures[j], TexUnits[j].m_premul_alpha); - setTexture(TexUnits[j].m_id, getTextureGLuint(mesh.textures[j]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - if (irr_driver->getLightViz()) - { - GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ALPHA }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } + if (UserConfigParams::m_azdo) + Handles.push_back(mesh.TextureHandles[TexUnits[j].m_id]); else - { - GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } + Textures.push_back(getTextureGLuint(mesh.textures[TexUnits[j].m_id])); } if (mesh.VAOType != VertexType) @@ -308,39 +306,51 @@ void renderMeshes2ndPass(const std::vector<TexUnit> &TexUnits, std::vector<STK:: #endif continue; } - custom_unroll_args<List...>::template exec(Shader::getInstance(), meshes->at(i)); + + if (UserConfigParams::m_azdo) + Shader::getInstance()->SetTextureHandles(Handles); + else + Shader::getInstance()->SetTextureUnits(Textures); + custom_unroll_args<List...>::template exec(Shader::getInstance(), meshes.at(i)); } } -template<typename Shader, int...List, typename... TupleType> -void renderInstancedMeshes2ndPass(const std::vector<TexUnit> &TexUnits, std::vector<STK::Tuple<TupleType...> > *meshes) +#ifdef Draw_Indirect +template<typename Shader, MeshMaterial Mat, video::E_VERTEX_TYPE VT, typename...Args> +void renderInstancedMeshes2ndPass(const std::vector<TexUnit> &TexUnits, const std::vector<GLuint> &Prefilled_tex, std::vector<GLMesh *> &meshes, Args...args) { glUseProgram(Shader::getInstance()->Program); - for (unsigned i = 0; i < meshes->size(); i++) + glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(VT, InstanceTypeDefault)); + for (unsigned i = 0; i < meshes.size(); i++) { - GLMesh &mesh = *(STK::tuple_get<0>(meshes->at(i))); - glBindVertexArray(mesh.vao); + GLMesh *mesh = meshes[i]; + std::vector<GLuint> Textures(Prefilled_tex); for (unsigned j = 0; j < TexUnits.size(); j++) - { - if (!mesh.textures[j]) - mesh.textures[j] = getUnicolorTexture(video::SColor(255, 255, 255, 255)); - compressTexture(mesh.textures[j], TexUnits[j].m_premul_alpha); - setTexture(TexUnits[j].m_id, getTextureGLuint(mesh.textures[j]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - if (irr_driver->getLightViz()) - { - GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ALPHA }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - else - { - GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - } - - instanced_custom_unroll_args<List...>::template exec(Shader::getInstance(), meshes->at(i)); + Textures.push_back(getTextureGLuint(mesh->textures[TexUnits[j].m_id])); + Shader::getInstance()->SetTextureUnits(Textures); + Shader::getInstance()->setUniforms(args...); + glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)((SolidPassCmd::getInstance()->Offset[Mat] + i) * sizeof(DrawElementsIndirectCommand))); } } +#endif + +#ifdef Multi_Draw_Indirect +template<typename Shader, MeshMaterial Mat, video::E_VERTEX_TYPE VT, typename...Args> +void multidraw2ndPass(const std::vector<uint64_t> &Handles, Args... args) +{ + glUseProgram(Shader::getInstance()->Program); + glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(VT, InstanceTypeDefault)); + if (SolidPassCmd::getInstance()->Size[Mat]) + { + Shader::getInstance()->SetTextureHandles(Handles); + Shader::getInstance()->setUniforms(args...); + glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, + (const void*)(SolidPassCmd::getInstance()->Offset[Mat] * sizeof(DrawElementsIndirectCommand)), + SolidPassCmd::getInstance()->Size[Mat], + sizeof(DrawElementsIndirectCommand)); + } +} +#endif void IrrDriver::renderSolidSecondPass() { @@ -364,77 +374,122 @@ void IrrDriver::renderSolidSecondPass() glEnable(GL_DEPTH_TEST); glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); - setTexture(0, m_rtts->getRenderTarget(RTT_TMP1), GL_NEAREST, GL_NEAREST); - setTexture(1, m_rtts->getRenderTarget(RTT_TMP2), GL_NEAREST, GL_NEAREST); - setTexture(2, m_rtts->getRenderTarget(RTT_HALF1_R), GL_LINEAR, GL_LINEAR); + + uint64_t DiffuseHandle = 0, SpecularHandle = 0, SSAOHandle = 0, DepthHandle = 0; + + if (UserConfigParams::m_azdo) + { +#ifdef Bindless_Texture_Support + DiffuseHandle = glGetTextureSamplerHandleARB(m_rtts->getRenderTarget(RTT_DIFFUSE), MeshShader::ObjectPass2Shader::getInstance()->SamplersId[0]); + if (!glIsTextureHandleResidentARB(DiffuseHandle)) + glMakeTextureHandleResidentARB(DiffuseHandle); + + SpecularHandle = glGetTextureSamplerHandleARB(m_rtts->getRenderTarget(RTT_SPECULAR), MeshShader::ObjectPass2Shader::getInstance()->SamplersId[1]); + if (!glIsTextureHandleResidentARB(SpecularHandle)) + glMakeTextureHandleResidentARB(SpecularHandle); + + SSAOHandle = glGetTextureSamplerHandleARB(m_rtts->getRenderTarget(RTT_HALF1_R), MeshShader::ObjectPass2Shader::getInstance()->SamplersId[2]); + if (!glIsTextureHandleResidentARB(SSAOHandle)) + glMakeTextureHandleResidentARB(SSAOHandle); + + DepthHandle = glGetTextureSamplerHandleARB(getDepthStencilTexture(), MeshShader::ObjectPass2Shader::getInstance()->SamplersId[3]); + if (!glIsTextureHandleResidentARB(DepthHandle)) + glMakeTextureHandleResidentARB(DepthHandle); +#endif + } { ScopedGPUTimer Timer(getGPUTimer(Q_SOLID_PASS2)); - m_scene_manager->drawAll(scene::ESNRP_SOLID); + irr_driver->setPhase(SOLID_LIT_PASS); + + for (unsigned i = 0; i < ImmediateDrawList::getInstance()->size(); i++) + ImmediateDrawList::getInstance()->at(i)->render(); + + std::vector<GLuint> DiffSpecSSAOTex = createVector<GLuint>(m_rtts->getRenderTarget(RTT_DIFFUSE), m_rtts->getRenderTarget(RTT_SPECULAR), m_rtts->getRenderTarget(RTT_HALF1_R)); renderMeshes2ndPass<MeshShader::ObjectPass2Shader, video::EVT_STANDARD, 3, 1>(TexUnits( - TexUnit(MeshShader::ObjectPass2Shader::getInstance()->TU_Albedo, true) - ), ListMatDefault::getInstance()); - + TexUnit(0, true) + ), ListMatDefault::getInstance()->SolidPass, + createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex); renderMeshes2ndPass<MeshShader::ObjectRefPass2Shader, video::EVT_STANDARD, 3, 1 >(TexUnits( - TexUnit(MeshShader::ObjectRefPass2Shader::getInstance()->TU_Albedo, true) - ), ListMatAlphaRef::getInstance()); - - renderMeshes2ndPass<MeshShader::SphereMapShader, video::EVT_STANDARD, 2, 1>(TexUnits( - TexUnit(MeshShader::SphereMapShader::getInstance()->TU_tex, true) - ), ListMatSphereMap::getInstance()); - - renderMeshes2ndPass<MeshShader::DetailledObjectPass2Shader, video::EVT_2TCOORDS, 1>(TexUnits( - TexUnit(MeshShader::DetailledObjectPass2Shader::getInstance()->TU_Albedo, true), - TexUnit(MeshShader::DetailledObjectPass2Shader::getInstance()->TU_detail, true) - ), ListMatDetails::getInstance()); - - renderMeshes2ndPass<MeshShader::GrassPass2Shader, video::EVT_STANDARD, 3, 1>(TexUnits( - TexUnit(MeshShader::GrassPass2Shader::getInstance()->TU_Albedo, true) - ), ListMatGrass::getInstance()); - - renderMeshes2ndPass<MeshShader::ObjectUnlitShader, video::EVT_STANDARD, 1>(TexUnits( - TexUnit(MeshShader::ObjectUnlitShader::getInstance()->TU_tex, true) - ), ListMatUnlit::getInstance()); - + TexUnit(0, true) + ), ListMatAlphaRef::getInstance()->SolidPass, createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex); + renderMeshes2ndPass<MeshShader::ObjectUnlitShader, video::EVT_STANDARD, 3, 1>(TexUnits( + TexUnit(0, true) + ), ListMatUnlit::getInstance()->SolidPass, createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex); renderMeshes2ndPass<MeshShader::SplattingShader, video::EVT_2TCOORDS, 1>(TexUnits( - TexUnit(8, true), - TexUnit(MeshShader::SplattingShader::getInstance()->TU_tex_layout, false), - TexUnit(MeshShader::SplattingShader::getInstance()->TU_tex_detail0, true), - TexUnit(MeshShader::SplattingShader::getInstance()->TU_tex_detail1, true), - TexUnit(MeshShader::SplattingShader::getInstance()->TU_tex_detail2, true), - TexUnit(MeshShader::SplattingShader::getInstance()->TU_tex_detail3, true) - ), ListMatSplatting::getInstance()); - + TexUnit(1, false), + TexUnit(2, true), + TexUnit(3, true), + TexUnit(4, true), + TexUnit(0, true) + ), ListMatSplatting::getInstance()->SolidPass, createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex); + renderMeshes2ndPass<MeshShader::SphereMapShader, video::EVT_STANDARD, 2, 1>(TexUnits( + TexUnit(0, true) + ), ListMatSphereMap::getInstance()->SolidPass, createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex); + renderMeshes2ndPass<MeshShader::DetailledObjectPass2Shader, video::EVT_2TCOORDS, 1>(TexUnits( + TexUnit(0, true), + TexUnit(1, true) + ), ListMatDetails::getInstance()->SolidPass, createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex); + renderMeshes2ndPass<MeshShader::GrassPass2Shader, video::EVT_STANDARD, 3, 1>(TexUnits( + TexUnit(0, true) + ), ListMatGrass::getInstance()->SolidPass, createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex); renderMeshes2ndPass<MeshShader::ObjectPass2Shader, video::EVT_TANGENTS, 3, 1>(TexUnits( - TexUnit(MeshShader::ObjectPass2Shader::getInstance()->TU_Albedo, true) - ), ListMatNormalMap::getInstance()); + TexUnit(0, true) + ), ListMatNormalMap::getInstance()->SolidPass, createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle), DiffSpecSSAOTex); + if (UserConfigParams::m_azdo) + { +#ifdef Multi_Draw_Indirect + multidraw2ndPass<MeshShader::InstancedObjectPass2Shader, MAT_DEFAULT, video::EVT_STANDARD>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0)); + multidraw2ndPass<MeshShader::InstancedObjectPass2Shader, MAT_NORMAL_MAP, video::EVT_TANGENTS>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0)); + multidraw2ndPass<MeshShader::InstancedObjectRefPass2Shader, MAT_ALPHA_REF, video::EVT_STANDARD>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0)); + multidraw2ndPass<MeshShader::InstancedSphereMapShader, MAT_SPHEREMAP, video::EVT_STANDARD>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0)); + multidraw2ndPass<MeshShader::InstancedDetailledObjectPass2Shader, MAT_DETAIL, video::EVT_2TCOORDS>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0, 0)); + multidraw2ndPass<MeshShader::InstancedObjectUnlitShader, MAT_UNLIT, video::EVT_STANDARD>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0)); + SunLightProvider * const cb = (SunLightProvider *)irr_driver->getCallback(ES_SUNLIGHT); + multidraw2ndPass<MeshShader::InstancedGrassPass2Shader, MAT_GRASS, video::EVT_STANDARD>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, DepthHandle, 0), windDir, cb->getPosition()); +#endif + } +#ifdef Draw_Indirect + else if (irr_driver->hasARB_draw_indirect()) + { + // Default + renderInstancedMeshes2ndPass<MeshShader::InstancedObjectPass2Shader, MAT_DEFAULT, video::EVT_STANDARD>( + TexUnits(TexUnit(0, true)), DiffSpecSSAOTex, ListInstancedMatDefault::getInstance()->SolidPass); + // Alpha ref + renderInstancedMeshes2ndPass<MeshShader::InstancedObjectRefPass2Shader, MAT_ALPHA_REF, video::EVT_STANDARD>( + TexUnits(TexUnit(0, true)), DiffSpecSSAOTex, ListInstancedMatAlphaRef::getInstance()->SolidPass); + // Unlit + renderInstancedMeshes2ndPass<MeshShader::InstancedObjectUnlitShader, MAT_UNLIT, video::EVT_STANDARD>( + TexUnits(TexUnit(0, true)), DiffSpecSSAOTex, ListInstancedMatUnlit::getInstance()->SolidPass); + // Spheremap + renderInstancedMeshes2ndPass<MeshShader::InstancedSphereMapShader, MAT_SPHEREMAP, video::EVT_STANDARD>( + TexUnits(TexUnit(0, true)), DiffSpecSSAOTex, ListInstancedMatSphereMap::getInstance()->SolidPass); + // Details + renderInstancedMeshes2ndPass<MeshShader::InstancedDetailledObjectPass2Shader, MAT_DETAIL, video::EVT_2TCOORDS>( + TexUnits(TexUnit(0, true), TexUnit(1, false)), DiffSpecSSAOTex, ListInstancedMatDetails::getInstance()->SolidPass); - renderInstancedMeshes2ndPass<MeshShader::InstancedObjectPass2Shader>( - TexUnits(TexUnit(MeshShader::InstancedObjectPass2Shader::getInstance()->TU_Albedo, true)), - ListInstancedMatDefault::getInstance()); - renderInstancedMeshes2ndPass<MeshShader::InstancedObjectPass2Shader>( - TexUnits(TexUnit(MeshShader::InstancedObjectPass2Shader::getInstance()->TU_Albedo, true)), - ListInstancedMatNormalMap::getInstance()); - renderInstancedMeshes2ndPass<MeshShader::InstancedObjectRefPass2Shader>( - TexUnits(TexUnit(MeshShader::InstancedObjectRefPass2Shader::getInstance()->TU_Albedo, true)), - ListInstancedMatAlphaRef::getInstance()); - setTexture(MeshShader::InstancedGrassPass2Shader::getInstance()->TU_dtex, - irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); - renderInstancedMeshes2ndPass<MeshShader::InstancedGrassPass2Shader, 3, 2>( - TexUnits(TexUnit(MeshShader::InstancedGrassPass2Shader::getInstance()->TU_Albedo, true)), - ListInstancedMatGrass::getInstance()); + // Normal map + renderInstancedMeshes2ndPass<MeshShader::InstancedObjectPass2Shader, MAT_NORMAL_MAP, video::EVT_TANGENTS>( + TexUnits(TexUnit(0, true)), DiffSpecSSAOTex, ListInstancedMatNormalMap::getInstance()->SolidPass); + + // Grass + SunLightProvider * const cb = (SunLightProvider *)irr_driver->getCallback(ES_SUNLIGHT); + DiffSpecSSAOTex.push_back(irr_driver->getDepthStencilTexture()); + renderInstancedMeshes2ndPass<MeshShader::InstancedGrassPass2Shader, MAT_GRASS, video::EVT_STANDARD>( + TexUnits(TexUnit(0, true)), DiffSpecSSAOTex, ListInstancedMatGrass::getInstance()->SolidPass, windDir, cb->getPosition()); + } +#endif } - m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); } template<enum E_VERTEX_TYPE VertexType, typename... TupleType> static void renderMeshNormals(std::vector<STK::Tuple<TupleType...> > *meshes) { glUseProgram(MeshShader::NormalVisualizer::getInstance()->Program); - glBindVertexArray(getVAO(VertexType)); + glBindVertexArray(VAOManager::getInstance()->getVAO(VertexType)); for (unsigned i = 0; i < meshes->size(); i++) { GLMesh &mesh = *(STK::tuple_get<0>(meshes->at(i))); @@ -452,60 +507,100 @@ static void renderMeshNormals(std::vector<STK::Tuple<TupleType...> > *meshes) void IrrDriver::renderNormalsVisualisation() { - renderMeshNormals<video::EVT_STANDARD>(ListMatDefault::getInstance()); - renderMeshNormals<video::EVT_STANDARD>(ListMatAlphaRef::getInstance()); - renderMeshNormals<video::EVT_STANDARD>(ListMatSphereMap::getInstance()); +// renderMeshNormals<video::EVT_STANDARD>(ListMatDefault::getInstance()); +// renderMeshNormals<video::EVT_STANDARD>(ListMatAlphaRef::getInstance()); +// renderMeshNormals<video::EVT_STANDARD>(ListMatSphereMap::getInstance()); // renderMeshNormals<video::EVT_STANDARD>(ListMatGrass::getInstance()); - renderMeshNormals<video::EVT_2TCOORDS>(ListMatDetails::getInstance()); - renderMeshNormals<video::EVT_STANDARD>(ListMatUnlit::getInstance()); - renderMeshNormals<video::EVT_2TCOORDS>(ListMatSplatting::getInstance()); - renderMeshNormals<video::EVT_TANGENTS>(ListMatNormalMap::getInstance()); - +// renderMeshNormals<video::EVT_2TCOORDS>(ListMatDetails::getInstance()); +// renderMeshNormals<video::EVT_STANDARD>(ListMatUnlit::getInstance()); +// renderMeshNormals<video::EVT_2TCOORDS>(ListMatSplatting::getInstance()); +// renderMeshNormals<video::EVT_TANGENTS>(ListMatNormalMap::getInstance()); } +template<typename Shader, enum E_VERTEX_TYPE VertexType, int...List, typename... TupleType> +void renderTransparenPass(const std::vector<TexUnit> &TexUnits, std::vector<STK::Tuple<TupleType...> > *meshes) +{ + glUseProgram(Shader::getInstance()->Program); + if (irr_driver->hasARB_base_instance()) + glBindVertexArray(VAOManager::getInstance()->getVAO(VertexType)); + for (unsigned i = 0; i < meshes->size(); i++) + { + std::vector<uint64_t> Handles; + std::vector<GLuint> Textures; + GLMesh &mesh = *(STK::tuple_get<0>(meshes->at(i))); + if (!irr_driver->hasARB_base_instance()) + glBindVertexArray(mesh.vao); + for (unsigned j = 0; j < TexUnits.size(); j++) + { + if (!mesh.textures[TexUnits[j].m_id]) + mesh.textures[TexUnits[j].m_id] = getUnicolorTexture(video::SColor(255, 255, 255, 255)); + compressTexture(mesh.textures[TexUnits[j].m_id], TexUnits[j].m_premul_alpha); + if (UserConfigParams::m_azdo) + { +#ifdef Bindless_Texture_Support + if (!mesh.TextureHandles[TexUnits[j].m_id]) + mesh.TextureHandles[TexUnits[j].m_id] = glGetTextureSamplerHandleARB(getTextureGLuint(mesh.textures[TexUnits[j].m_id]), Shader::getInstance()->SamplersId[Handles.size()]); + if (!glIsTextureHandleResidentARB(mesh.TextureHandles[TexUnits[j].m_id])) + glMakeTextureHandleResidentARB(mesh.TextureHandles[TexUnits[j].m_id]); +#endif + Handles.push_back(mesh.TextureHandles[TexUnits[j].m_id]); + } + else + Textures.push_back(getTextureGLuint(mesh.textures[TexUnits[j].m_id])); + } + if (mesh.VAOType != VertexType) + { +#ifdef DEBUG + Log::error("Materials", "Wrong vertex Type associed to pass 2 (hint texture : %s)", mesh.textures[0]->getName().getPath().c_str()); +#endif + continue; + } + + if (UserConfigParams::m_azdo) + Shader::getInstance()->SetTextureHandles(Handles); + else + Shader::getInstance()->SetTextureUnits(Textures); + custom_unroll_args<List...>::template exec(Shader::getInstance(), meshes->at(i)); + } +} static video::ITexture *displaceTex = 0; void IrrDriver::renderTransparent() { - irr_driver->setPhase(TRANSPARENT_PASS); glEnable(GL_DEPTH_TEST); glDisable(GL_ALPHA_TEST); glDepthMask(GL_FALSE); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glDisable(GL_CULL_FACE); - ListBlendTransparent::getInstance()->clear(); - ListAdditiveTransparent::getInstance()->clear(); - ListBlendTransparentFog::getInstance()->clear(); - ListAdditiveTransparentFog::getInstance()->clear(); - ListDisplacement::getInstance()->clear(); - m_scene_manager->drawAll(scene::ESNRP_TRANSPARENT); - glBindVertexArray(getVAO(EVT_STANDARD)); + irr_driver->setPhase(TRANSPARENT_PASS); + + for (unsigned i = 0; i < ImmediateDrawList::getInstance()->size(); i++) + ImmediateDrawList::getInstance()->at(i)->render(); + + if (irr_driver->hasARB_base_instance()) + glBindVertexArray(VAOManager::getInstance()->getVAO(EVT_STANDARD)); if (World::getWorld() && World::getWorld()->isFogEnabled()) { glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - renderMeshes2ndPass<MeshShader::TransparentFogShader, video::EVT_STANDARD, 8, 7, 6, 5, 4, 3, 2, 1>(TexUnits( - TexUnit(MeshShader::TransparentFogShader::getInstance()->TU_tex, true) - ), ListBlendTransparentFog::getInstance()); + renderTransparenPass<MeshShader::TransparentFogShader, video::EVT_STANDARD, 8, 7, 6, 5, 4, 3, 2, 1>(TexUnits( + TexUnit(0, true)), ListBlendTransparentFog::getInstance()); glBlendFunc(GL_ONE, GL_ONE); - renderMeshes2ndPass<MeshShader::TransparentFogShader, video::EVT_STANDARD, 8, 7, 6, 5, 4, 3, 2, 1>(TexUnits( - TexUnit(MeshShader::TransparentFogShader::getInstance()->TU_tex, true) - ), ListAdditiveTransparentFog::getInstance()); + renderTransparenPass<MeshShader::TransparentFogShader, video::EVT_STANDARD, 8, 7, 6, 5, 4, 3, 2, 1>(TexUnits( + TexUnit(0, true)), ListAdditiveTransparentFog::getInstance()); } else { glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - renderMeshes2ndPass<MeshShader::TransparentShader, video::EVT_STANDARD, 2, 1>(TexUnits( - TexUnit(MeshShader::TransparentShader::getInstance()->TU_tex, true) - ), ListBlendTransparent::getInstance()); + renderTransparenPass<MeshShader::TransparentShader, video::EVT_STANDARD, 2, 1>(TexUnits( + TexUnit(0, true)), ListBlendTransparent::getInstance()); glBlendFunc(GL_ONE, GL_ONE); - renderMeshes2ndPass<MeshShader::TransparentShader, video::EVT_STANDARD, 2, 1>(TexUnits( - TexUnit(MeshShader::TransparentShader::getInstance()->TU_tex, true) - ), ListAdditiveTransparent::getInstance()); + renderTransparenPass<MeshShader::TransparentShader, video::EVT_STANDARD, 2, 1>(TexUnits( + TexUnit(0, true)), ListAdditiveTransparent::getInstance()); } if (!UserConfigParams::m_dynamic_lights) @@ -529,13 +624,16 @@ void IrrDriver::renderTransparent() glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - glBindVertexArray(getVAO(EVT_2TCOORDS)); + if (irr_driver->hasARB_base_instance()) + glBindVertexArray(VAOManager::getInstance()->getVAO(EVT_2TCOORDS)); // Generate displace mask // Use RTT_TMP4 as displace mask irr_driver->getFBO(FBO_TMP1_WITH_DS).Bind(); for (unsigned i = 0; i < ListDisplacement::getInstance()->size(); i++) { const GLMesh &mesh = *(STK::tuple_get<0>(ListDisplacement::getInstance()->at(i))); + if (!irr_driver->hasARB_base_instance()) + glBindVertexArray(mesh.vao); const core::matrix4 &AbsoluteTransformation = STK::tuple_get<1>(ListDisplacement::getInstance()->at(i)); if (mesh.VAOType != video::EVT_2TCOORDS) { @@ -560,6 +658,8 @@ void IrrDriver::renderTransparent() for (unsigned i = 0; i < ListDisplacement::getInstance()->size(); i++) { const GLMesh &mesh = *(STK::tuple_get<0>(ListDisplacement::getInstance()->at(i))); + if (!irr_driver->hasARB_base_instance()) + glBindVertexArray(mesh.vao); const core::matrix4 &AbsoluteTransformation = STK::tuple_get<1>(ListDisplacement::getInstance()->at(i)); if (mesh.VAOType != video::EVT_2TCOORDS) continue; @@ -568,10 +668,11 @@ void IrrDriver::renderTransparent() GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; // Render the effect - setTexture(MeshShader::DisplaceShader::getInstance()->TU_displacement_tex, getTextureGLuint(displaceTex), GL_LINEAR, GL_LINEAR, true); - setTexture(MeshShader::DisplaceShader::getInstance()->TU_mask_tex, irr_driver->getRenderTargetTexture(RTT_TMP1), GL_LINEAR, GL_LINEAR, true); - setTexture(MeshShader::DisplaceShader::getInstance()->TU_color_tex, irr_driver->getRenderTargetTexture(RTT_COLOR), GL_LINEAR, GL_LINEAR, true); - setTexture(MeshShader::DisplaceShader::getInstance()->TU_tex, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR, true); + MeshShader::DisplaceShader::getInstance()->SetTextureUnits( + createVector<GLuint>(getTextureGLuint(displaceTex), + irr_driver->getRenderTargetTexture(RTT_COLOR), + irr_driver->getRenderTargetTexture(RTT_TMP1), + getTextureGLuint(mesh.textures[0]))); glUseProgram(MeshShader::DisplaceShader::getInstance()->Program); MeshShader::DisplaceShader::getInstance()->setUniforms(AbsoluteTransformation, core::vector2df(cb->getDirX(), cb->getDirY()), @@ -588,15 +689,15 @@ void IrrDriver::renderTransparent() } template<typename T, typename...uniforms> -void drawShadow(const T *Shader, const GLMesh *mesh, uniforms... Args) +void drawShadow(const T *Shader, unsigned cascade, const GLMesh *mesh, uniforms... Args) { irr_driver->IncreaseObjectCount(); GLenum ptype = mesh->PrimitiveType; GLenum itype = mesh->IndexType; size_t count = mesh->IndexCount; - Shader->setUniforms(Args...); - glDrawElementsInstancedBaseVertex(ptype, count, itype, (GLvoid *)mesh->vaoOffset, 4, mesh->vaoBaseVertex); + Shader->setUniforms(cascade, Args...); + glDrawElementsBaseVertex(ptype, count, itype, (GLvoid *)mesh->vaoOffset, mesh->vaoBaseVertex); } template<int...List> @@ -606,9 +707,9 @@ template<> struct shadow_custom_unroll_args<> { template<typename T, typename ...TupleTypes, typename ...Args> - static void exec(const T *Shader, const STK::Tuple<TupleTypes...> &t, Args... args) + static void exec(const T *Shader, unsigned cascade, const STK::Tuple<TupleTypes...> &t, Args... args) { - drawShadow<T>(Shader, STK::tuple_get<0>(t), args...); + drawShadow<T>(Shader, cascade, STK::tuple_get<0>(t), args...); } }; @@ -616,81 +717,82 @@ template<int N, int...List> struct shadow_custom_unroll_args<N, List...> { template<typename T, typename ...TupleTypes, typename ...Args> - static void exec(const T *Shader, const STK::Tuple<TupleTypes...> &t, Args... args) + static void exec(const T *Shader, unsigned cascade, const STK::Tuple<TupleTypes...> &t, Args... args) { - shadow_custom_unroll_args<List...>::template exec<T>(Shader, t, STK::tuple_get<N>(t), args...); + shadow_custom_unroll_args<List...>::template exec<T>(Shader, cascade, t, STK::tuple_get<N>(t), args...); } }; template<typename T, enum E_VERTEX_TYPE VertexType, int...List, typename... Args> -void renderShadow(const std::vector<GLuint> TextureUnits, const std::vector<STK::Tuple<Args...> > *t) +void renderShadow(const std::vector<GLuint> TextureUnits, unsigned cascade, const std::vector<STK::Tuple<Args...> > &t) { glUseProgram(T::getInstance()->Program); - glBindVertexArray(getVAO(VertexType)); - for (unsigned i = 0; i < t->size(); i++) + if (irr_driver->hasARB_base_instance()) + glBindVertexArray(VAOManager::getInstance()->getVAO(VertexType)); + for (unsigned i = 0; i < t.size(); i++) { - const GLMesh *mesh = STK::tuple_get<0>(t->at(i)); + std::vector<uint64_t> Handles; + std::vector<GLuint> Textures; + GLMesh *mesh = STK::tuple_get<0>(t.at(i)); + if (!irr_driver->hasARB_base_instance()) + glBindVertexArray(mesh->vao); for (unsigned j = 0; j < TextureUnits.size(); j++) { - compressTexture(mesh->textures[j], true); - setTexture(TextureUnits[j], getTextureGLuint(mesh->textures[j]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + compressTexture(mesh->textures[TextureUnits[j]], true); + if (UserConfigParams::m_azdo) + Handles.push_back(mesh->TextureHandles[TextureUnits[j]]); + else + Textures.push_back(getTextureGLuint(mesh->textures[TextureUnits[j]])); } - - shadow_custom_unroll_args<List...>::template exec<T>(T::getInstance(), t->at(i)); + if (UserConfigParams::m_azdo) + T::getInstance()->SetTextureHandles(Handles); + else + T::getInstance()->SetTextureUnits(Textures); + shadow_custom_unroll_args<List...>::template exec<T>(T::getInstance(), cascade, t.at(i)); } } -template<int...List> -struct instanced_shadow_custom_unroll_args; - -template<> -struct instanced_shadow_custom_unroll_args<> +#ifdef Draw_Indirect +template<typename Shader, MeshMaterial Mat, video::E_VERTEX_TYPE VT, typename...Args> +void renderInstancedShadow(const std::vector<GLuint> TextureUnits, unsigned cascade, const std::vector<GLMesh *> &t, Args ...args) { - template<typename T, typename ...TupleTypes, typename ...Args> - static void exec(const T *Shader, const STK::Tuple<TupleTypes...> &t, Args... args) + glUseProgram(Shader::getInstance()->Program); + glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(VT, InstanceTypeShadow)); + for (unsigned i = 0; i < t.size(); i++) { - const GLMesh *mesh = STK::tuple_get<0>(t); - size_t instance_count = STK::tuple_get<1>(t); - irr_driver->IncreaseObjectCount(); - GLenum ptype = mesh->PrimitiveType; - GLenum itype = mesh->IndexType; - size_t count = mesh->IndexCount; + std::vector<uint64_t> Handles; + std::vector<GLuint> Textures; + GLMesh *mesh = t[i]; - Shader->setUniforms(args...); - glDrawElementsInstanced(ptype, count, itype, 0, 4 * instance_count); - } -}; - -template<int N, int...List> -struct instanced_shadow_custom_unroll_args<N, List...> -{ - template<typename T, typename ...TupleTypes, typename ...Args> - static void exec(const T *Shader, const STK::Tuple<TupleTypes...> &t, Args... args) - { - instanced_shadow_custom_unroll_args<List...>::template exec<T>(Shader, t, STK::tuple_get<N>(t), args...); - } -}; - -template<typename T, int...List, typename... Args> -void renderInstancedShadow(const std::vector<GLuint> TextureUnits, const std::vector<STK::Tuple<Args...> > *t) -{ - glUseProgram(T::getInstance()->Program); - for (unsigned i = 0; i < t->size(); i++) - { - const GLMesh *mesh = STK::tuple_get<0>(t->at(i)); - glBindVertexArray(mesh->vao_shadow_pass); for (unsigned j = 0; j < TextureUnits.size(); j++) - { - compressTexture(mesh->textures[j], true); - setTexture(TextureUnits[j], getTextureGLuint(mesh->textures[j]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - } + Textures.push_back(getTextureGLuint(mesh->textures[TextureUnits[j]])); - instanced_shadow_custom_unroll_args<List...>::template exec<T>(T::getInstance(), t->at(i)); + Shader::getInstance()->SetTextureUnits(Textures); + Shader::getInstance()->setUniforms(cascade, args...); + size_t tmp = ShadowPassCmd::getInstance()->Offset[cascade][Mat] + i; + glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)((tmp) * sizeof(DrawElementsIndirectCommand))); } } +#endif + +#ifdef Multi_Draw_Indirect +template<typename Shader, MeshMaterial Mat, video::E_VERTEX_TYPE VT, typename...Args> +static void multidrawShadow(unsigned i, Args ...args) +{ + glUseProgram(Shader::getInstance()->Program); + glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(VT, InstanceTypeShadow)); + if (ShadowPassCmd::getInstance()->Size[i][Mat]) + { + Shader::getInstance()->setUniforms(i, args...); + glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)(ShadowPassCmd::getInstance()->Offset[i][Mat] * sizeof(DrawElementsIndirectCommand)), ShadowPassCmd::getInstance()->Size[i][Mat], sizeof(DrawElementsIndirectCommand)); + } +} +#endif void IrrDriver::renderShadows() { + ScopedGPUTimer Timer(getGPUTimer(Q_SHADOWS)); + glDepthFunc(GL_LEQUAL); glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); @@ -702,35 +804,47 @@ void IrrDriver::renderShadows() glClear(GL_DEPTH_BUFFER_BIT); glDrawBuffer(GL_NONE); - irr_driver->setPhase(SHADOW_PASS); - ListMatDefault::getInstance()->clear(); - ListMatAlphaRef::getInstance()->clear(); - ListMatSphereMap::getInstance()->clear(); - ListMatDetails::getInstance()->clear(); - ListMatUnlit::getInstance()->clear(); - ListMatNormalMap::getInstance()->clear(); - ListMatGrass::getInstance()->clear(); - ListMatSplatting::getInstance()->clear(); - ListInstancedMatDefault::getInstance()->clear(); - ListInstancedMatAlphaRef::getInstance()->clear(); - ListInstancedMatGrass::getInstance()->clear(); - ListInstancedMatNormalMap::getInstance()->clear(); - m_scene_manager->drawAll(scene::ESNRP_SOLID); - std::vector<GLuint> noTexUnits; - renderShadow<MeshShader::ShadowShader, EVT_STANDARD, 1>(noTexUnits, ListMatDefault::getInstance()); - renderShadow<MeshShader::ShadowShader, EVT_STANDARD, 1>(noTexUnits, ListMatSphereMap::getInstance()); - renderShadow<MeshShader::ShadowShader, EVT_2TCOORDS, 1>(noTexUnits, ListMatDetails::getInstance()); - renderShadow<MeshShader::ShadowShader, EVT_2TCOORDS, 1>(noTexUnits, ListMatSplatting::getInstance()); - renderShadow<MeshShader::ShadowShader, EVT_TANGENTS, 1>(noTexUnits, ListMatNormalMap::getInstance()); - renderShadow<MeshShader::RefShadowShader, EVT_STANDARD, 1>(std::vector<GLuint>{ MeshShader::RefShadowShader::getInstance()->TU_tex }, ListMatAlphaRef::getInstance()); - renderShadow<MeshShader::RefShadowShader, EVT_STANDARD, 1>(std::vector<GLuint>{ MeshShader::RefShadowShader::getInstance()->TU_tex }, ListMatUnlit::getInstance()); - renderShadow<MeshShader::GrassShadowShader, EVT_STANDARD, 3, 1>(std::vector<GLuint>{ MeshShader::GrassShadowShader::getInstance()->TU_tex }, ListMatGrass::getInstance()); + for (unsigned cascade = 0; cascade < 4; cascade++) + { - renderInstancedShadow<MeshShader::InstancedShadowShader>(noTexUnits, ListInstancedMatDefault::getInstance()); - renderInstancedShadow<MeshShader::InstancedRefShadowShader>(std::vector<GLuint>{ MeshShader::InstancedRefShadowShader::getInstance()->TU_tex }, ListInstancedMatAlphaRef::getInstance()); - renderInstancedShadow<MeshShader::InstancedGrassShadowShader, 2>(std::vector<GLuint>{ MeshShader::InstancedGrassShadowShader::getInstance()->TU_tex }, ListInstancedMatGrass::getInstance()); - renderInstancedShadow<MeshShader::InstancedShadowShader>(noTexUnits, ListInstancedMatNormalMap::getInstance()); + std::vector<GLuint> noTexUnits; + + renderShadow<MeshShader::ShadowShader, EVT_STANDARD, 1>(noTexUnits, cascade, ListMatDefault::getInstance()->Shadows[cascade]); + renderShadow<MeshShader::ShadowShader, EVT_STANDARD, 1>(noTexUnits, cascade, ListMatSphereMap::getInstance()->Shadows[cascade]); + renderShadow<MeshShader::ShadowShader, EVT_2TCOORDS, 1>(noTexUnits, cascade, ListMatDetails::getInstance()->Shadows[cascade]); + renderShadow<MeshShader::ShadowShader, EVT_2TCOORDS, 1>(noTexUnits, cascade, ListMatSplatting::getInstance()->Shadows[cascade]); + renderShadow<MeshShader::ShadowShader, EVT_TANGENTS, 1>(noTexUnits, cascade, ListMatNormalMap::getInstance()->Shadows[cascade]); + renderShadow<MeshShader::RefShadowShader, EVT_STANDARD, 1>(std::vector<GLuint>{ 0 }, cascade, ListMatAlphaRef::getInstance()->Shadows[cascade]); + renderShadow<MeshShader::RefShadowShader, EVT_STANDARD, 1>(std::vector<GLuint>{ 0 }, cascade, ListMatUnlit::getInstance()->Shadows[cascade]); + renderShadow<MeshShader::GrassShadowShader, EVT_STANDARD, 3, 1>(std::vector<GLuint>{ 0 }, cascade, ListMatGrass::getInstance()->Shadows[cascade]); + + if (irr_driver->hasARB_draw_indirect()) + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, ShadowPassCmd::getInstance()->drawindirectcmd); + + if (UserConfigParams::m_azdo) + { +#ifdef Multi_Draw_Indirect + multidrawShadow<MeshShader::InstancedShadowShader, MAT_DEFAULT, video::EVT_STANDARD>(cascade); + multidrawShadow<MeshShader::InstancedShadowShader, MAT_DETAIL, video::EVT_2TCOORDS>(cascade); + multidrawShadow<MeshShader::InstancedShadowShader, MAT_NORMAL_MAP, video::EVT_TANGENTS>(cascade); + multidrawShadow<MeshShader::InstancedRefShadowShader, MAT_ALPHA_REF, video::EVT_STANDARD>(cascade); + multidrawShadow<MeshShader::InstancedRefShadowShader, MAT_UNLIT, video::EVT_STANDARD>(cascade); + multidrawShadow<MeshShader::InstancedGrassShadowShader, MAT_GRASS, video::EVT_STANDARD>(cascade, windDir); +#endif + } +#ifdef Draw_Indirect + else if (irr_driver->hasARB_draw_indirect()) + { + renderInstancedShadow<MeshShader::InstancedShadowShader, MAT_DEFAULT, video::EVT_STANDARD>(noTexUnits, cascade, ListInstancedMatDefault::getInstance()->Shadows[cascade]); + renderInstancedShadow<MeshShader::InstancedShadowShader, MAT_DETAIL, video::EVT_2TCOORDS>(noTexUnits, cascade, ListInstancedMatDetails::getInstance()->Shadows[cascade]); + renderInstancedShadow<MeshShader::InstancedRefShadowShader, MAT_ALPHA_REF, video::EVT_STANDARD>(std::vector < GLuint > { 0 }, cascade, ListInstancedMatAlphaRef::getInstance()->Shadows[cascade]); + renderInstancedShadow<MeshShader::InstancedRefShadowShader, MAT_UNLIT, video::EVT_STANDARD>(std::vector < GLuint > { 0 }, cascade, ListInstancedMatUnlit::getInstance()->Shadows[cascade]); + renderInstancedShadow<MeshShader::InstancedGrassShadowShader, MAT_GRASS, video::EVT_STANDARD>(std::vector < GLuint > { 0 }, cascade, ListInstancedMatGrass::getInstance()->Shadows[cascade], windDir); + renderInstancedShadow<MeshShader::InstancedShadowShader, MAT_NORMAL_MAP, video::EVT_TANGENTS>(noTexUnits, cascade, ListInstancedMatNormalMap::getInstance()->Shadows[cascade]); + } +#endif + } glDisable(GL_POLYGON_OFFSET_FILL); } @@ -761,41 +875,94 @@ struct rsm_custom_unroll_args<N, List...> }; template<typename T, enum E_VERTEX_TYPE VertexType, int... Selector, typename... Args> -void drawRSM(const core::matrix4 & rsm_matrix, const std::vector<GLuint> &TextureUnits, std::vector<STK::Tuple<Args...> > *t) +void drawRSM(const core::matrix4 & rsm_matrix, const std::vector<GLuint> &TextureUnits, const std::vector<STK::Tuple<Args...> > &t) { glUseProgram(T::getInstance()->Program); - glBindVertexArray(getVAO(VertexType)); - for (unsigned i = 0; i < t->size(); i++) + if (irr_driver->hasARB_base_instance()) + glBindVertexArray(VAOManager::getInstance()->getVAO(VertexType)); + for (unsigned i = 0; i < t.size(); i++) { - GLMesh *mesh = STK::tuple_get<0>(t->at(i)); + std::vector<GLuint> Textures; + GLMesh *mesh = STK::tuple_get<0>(t.at(i)); + if (!irr_driver->hasARB_base_instance()) + glBindVertexArray(mesh->vao); for (unsigned j = 0; j < TextureUnits.size(); j++) - { - if (!mesh->textures[j]) - mesh->textures[j] = getUnicolorTexture(video::SColor(255, 255, 255, 255)); - compressTexture(mesh->textures[j], true); - setTexture(TextureUnits[j], getTextureGLuint(mesh->textures[j]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - } - rsm_custom_unroll_args<Selector...>::template exec<T>(rsm_matrix, t->at(i)); + Textures.push_back(getTextureGLuint(mesh->textures[TextureUnits[j]])); + T::getInstance()->SetTextureUnits(Textures); + rsm_custom_unroll_args<Selector...>::template exec<T>(rsm_matrix, t.at(i)); } } +#ifdef Draw_Indirect +template<typename Shader, MeshMaterial Mat, video::E_VERTEX_TYPE VT, typename...Args> +void renderRSMShadow(const std::vector<GLuint> TextureUnits, const std::vector<GLMesh *> &t, Args ...args) +{ + glUseProgram(Shader::getInstance()->Program); + glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(VT, InstanceTypeRSM)); + for (unsigned i = 0; i < t.size(); i++) + { + std::vector<uint64_t> Handles; + std::vector<GLuint> Textures; + GLMesh *mesh = t[i]; + + for (unsigned j = 0; j < TextureUnits.size(); j++) + Textures.push_back(getTextureGLuint(mesh->textures[TextureUnits[j]])); + + Shader::getInstance()->SetTextureUnits(Textures); + Shader::getInstance()->setUniforms(args...); + glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)((RSMPassCmd::getInstance()->Offset[Mat] + i)* sizeof(DrawElementsIndirectCommand))); + } +} +#endif + +#ifdef Multi_Draw_Indirect +template<typename Shader, MeshMaterial Mat, enum E_VERTEX_TYPE VertexType, typename... Args> +void multidrawRSM(Args...args) +{ + glUseProgram(Shader::getInstance()->Program); + glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(VertexType, InstanceTypeRSM)); + if (RSMPassCmd::getInstance()->Size[Mat]) + { + Shader::getInstance()->setUniforms(args...); + glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)(RSMPassCmd::getInstance()->Offset[Mat] * sizeof(DrawElementsIndirectCommand)), RSMPassCmd::getInstance()->Size[Mat], sizeof(DrawElementsIndirectCommand)); + } +} +#endif + void IrrDriver::renderRSM() { + ScopedGPUTimer Timer(getGPUTimer(Q_RSM)); m_rtts->getRSM().Bind(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - drawRSM<MeshShader::RSMShader, EVT_STANDARD, 3, 1>(rsm_matrix, std::vector<GLuint>{ MeshShader::RSMShader::getInstance()->TU_tex }, ListMatDefault::getInstance()); - drawRSM<MeshShader::RSMShader, EVT_STANDARD, 3, 1>(rsm_matrix, std::vector<GLuint>{ MeshShader::RSMShader::getInstance()->TU_tex }, ListMatAlphaRef::getInstance()); - drawRSM<MeshShader::RSMShader, EVT_TANGENTS, 3, 1>(rsm_matrix, std::vector<GLuint>{ MeshShader::RSMShader::getInstance()->TU_tex }, ListMatNormalMap::getInstance()); - drawRSM<MeshShader::RSMShader, EVT_STANDARD, 3, 1>(rsm_matrix, std::vector<GLuint>{ MeshShader::RSMShader::getInstance()->TU_tex }, ListMatUnlit::getInstance()); - drawRSM<MeshShader::RSMShader, EVT_2TCOORDS, 3, 1>(rsm_matrix, std::vector<GLuint>{ MeshShader::RSMShader::getInstance()->TU_tex }, ListMatDetails::getInstance()); - drawRSM<MeshShader::SplattingRSMShader, EVT_2TCOORDS, 1>(rsm_matrix, - std::vector<GLuint>{ - 8, - MeshShader::SplattingRSMShader::getInstance()->TU_layout, - MeshShader::SplattingRSMShader::getInstance()->TU_detail0, - MeshShader::SplattingRSMShader::getInstance()->TU_detail1, - MeshShader::SplattingRSMShader::getInstance()->TU_detail2, - MeshShader::SplattingRSMShader::getInstance()->TU_detail3}, - ListMatSplatting::getInstance()); + drawRSM<MeshShader::RSMShader, EVT_STANDARD, 3, 1>(rsm_matrix, std::vector<GLuint>{ 0 }, ListMatDefault::getInstance()->RSM); + drawRSM<MeshShader::RSMShader, EVT_STANDARD, 3, 1>(rsm_matrix, std::vector<GLuint>{ 0 }, ListMatAlphaRef::getInstance()->RSM); + drawRSM<MeshShader::RSMShader, EVT_TANGENTS, 3, 1>(rsm_matrix, std::vector<GLuint>{ 0 }, ListMatNormalMap::getInstance()->RSM); + drawRSM<MeshShader::RSMShader, EVT_STANDARD, 3, 1>(rsm_matrix, std::vector<GLuint>{ 0 }, ListMatUnlit::getInstance()->RSM); + drawRSM<MeshShader::RSMShader, EVT_2TCOORDS, 3, 1>(rsm_matrix, std::vector<GLuint>{ 0 }, ListMatDetails::getInstance()->RSM); + drawRSM<MeshShader::SplattingRSMShader, EVT_2TCOORDS, 1>(rsm_matrix, createVector<GLuint>(1, 2, 3, 4, 5), ListMatSplatting::getInstance()->RSM); + + if (irr_driver->hasARB_draw_indirect()) + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, RSMPassCmd::getInstance()->drawindirectcmd); + + if (UserConfigParams::m_azdo) + { +#ifdef Multi_Draw_Indirect + multidrawRSM<MeshShader::InstancedRSMShader, MAT_DEFAULT, video::EVT_STANDARD>(rsm_matrix); + multidrawRSM<MeshShader::InstancedRSMShader, MAT_NORMAL_MAP, video::EVT_TANGENTS>(rsm_matrix); + multidrawRSM<MeshShader::InstancedRSMShader, MAT_ALPHA_REF, video::EVT_STANDARD>(rsm_matrix); + multidrawRSM<MeshShader::InstancedRSMShader, MAT_UNLIT, video::EVT_STANDARD>(rsm_matrix); + multidrawRSM<MeshShader::InstancedRSMShader, MAT_DETAIL, video::EVT_2TCOORDS>(rsm_matrix); +#endif + } +#ifdef Draw_Indirect + else if (irr_driver->hasARB_draw_indirect()) + { + renderRSMShadow<MeshShader::InstancedRSMShader, MAT_DEFAULT, video::EVT_STANDARD>(std::vector < GLuint > { 0 }, ListInstancedMatDefault::getInstance()->RSM, rsm_matrix); + renderRSMShadow<MeshShader::InstancedRSMShader, MAT_ALPHA_REF, video::EVT_STANDARD>(std::vector < GLuint > { 0 }, ListInstancedMatAlphaRef::getInstance()->RSM, rsm_matrix); + renderRSMShadow<MeshShader::InstancedRSMShader, MAT_UNLIT, video::EVT_STANDARD>(std::vector < GLuint > { 0 }, ListInstancedMatUnlit::getInstance()->RSM, rsm_matrix); + renderRSMShadow<MeshShader::InstancedRSMShader, MAT_NORMAL_MAP, video::EVT_TANGENTS>(std::vector < GLuint > { 0 }, ListInstancedMatNormalMap::getInstance()->RSM, rsm_matrix); + renderRSMShadow<MeshShader::InstancedRSMShader, MAT_DETAIL, video::EVT_2TCOORDS>(std::vector < GLuint > { 0 }, ListInstancedMatDetails::getInstance()->RSM, rsm_matrix); + } +#endif } diff --git a/src/graphics/render_lighting.cpp b/src/graphics/render_lighting.cpp index d53416f87..d69c7a843 100644 --- a/src/graphics/render_lighting.cpp +++ b/src/graphics/render_lighting.cpp @@ -16,7 +16,6 @@ #include "graphics/screenquad.hpp" #include "graphics/shaders.hpp" #include "graphics/stkmeshscenenode.hpp" -#include "graphics/stkinstancedscenenode.hpp" #include "graphics/wind.hpp" #include "io/file_manager.hpp" #include "items/item.hpp" @@ -45,17 +44,13 @@ static void renderPointLights(unsigned count) glEnable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); - glUseProgram(LightShader::PointLightShader::Program); - glBindVertexArray(LightShader::PointLightShader::vao); - glBindBuffer(GL_ARRAY_BUFFER, LightShader::PointLightShader::vbo); + glUseProgram(LightShader::PointLightShader::getInstance()->Program); + glBindVertexArray(LightShader::PointLightShader::getInstance()->vao); + glBindBuffer(GL_ARRAY_BUFFER, LightShader::PointLightShader::getInstance()->vbo); glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(LightShader::PointLightInfo), PointLightsInfo); - setTexture(0, irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), GL_NEAREST, GL_NEAREST); - setTexture(1, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); - LightShader::PointLightShader - ::setUniforms(core::vector2df(float(UserConfigParams::m_width), - float(UserConfigParams::m_height)), - 200, 0, 1); + LightShader::PointLightShader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), irr_driver->getDepthStencilTexture())); + LightShader::PointLightShader::getInstance()->setUniforms(); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, count); } @@ -68,6 +63,9 @@ unsigned IrrDriver::UpdateLightsInfo(scene::ICameraSceneNode * const camnode, fl std::vector<LightNode *> BucketedLN[15]; for (unsigned int i = 0; i < lightcount; i++) { + if (!m_lights[i]->isVisible()) + continue; + if (!m_lights[i]->isPointLight()) { m_lights[i]->render(); @@ -140,9 +138,8 @@ void IrrDriver::renderLights(unsigned pointlightcount) if (irr_driver->needRHWorkaround()) { glUseProgram(FullScreenShader::NVWorkaroundRadianceHintsConstructionShader::getInstance()->Program); - setTexture(FullScreenShader::NVWorkaroundRadianceHintsConstructionShader::getInstance()->TU_ctex, m_rtts->getRSM().getRTT()[0], GL_LINEAR, GL_LINEAR); - setTexture(FullScreenShader::NVWorkaroundRadianceHintsConstructionShader::getInstance()->TU_ntex, m_rtts->getRSM().getRTT()[1], GL_LINEAR, GL_LINEAR); - setTexture(FullScreenShader::NVWorkaroundRadianceHintsConstructionShader::getInstance()->TU_dtex, m_rtts->getRSM().getDepthTexture(), GL_LINEAR, GL_LINEAR); + FullScreenShader::NVWorkaroundRadianceHintsConstructionShader::getInstance()->SetTextureUnits( + createVector<GLuint>(m_rtts->getRSM().getRTT()[0], m_rtts->getRSM().getRTT()[1], m_rtts->getRSM().getDepthTexture())); for (unsigned i = 0; i < 32; i++) { FullScreenShader::NVWorkaroundRadianceHintsConstructionShader::getInstance()->setUniforms(rsm_matrix, rh_matrix, rh_extend, i); @@ -152,9 +149,13 @@ void IrrDriver::renderLights(unsigned pointlightcount) else { glUseProgram(FullScreenShader::RadianceHintsConstructionShader::getInstance()->Program); - setTexture(FullScreenShader::RadianceHintsConstructionShader::getInstance()->TU_ctex, m_rtts->getRSM().getRTT()[0], GL_LINEAR, GL_LINEAR); - setTexture(FullScreenShader::RadianceHintsConstructionShader::getInstance()->TU_ntex, m_rtts->getRSM().getRTT()[1], GL_LINEAR, GL_LINEAR); - setTexture(FullScreenShader::RadianceHintsConstructionShader::getInstance()->TU_dtex, m_rtts->getRSM().getDepthTexture(), GL_LINEAR, GL_LINEAR); + FullScreenShader::RadianceHintsConstructionShader::getInstance()->SetTextureUnits( + createVector<GLuint>( + m_rtts->getRSM().getRTT()[0], + m_rtts->getRSM().getRTT()[1], + m_rtts->getRSM().getDepthTexture() + ) + ); FullScreenShader::RadianceHintsConstructionShader::getInstance()->setUniforms(rsm_matrix, rh_matrix, rh_extend); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 32); } @@ -162,14 +163,14 @@ void IrrDriver::renderLights(unsigned pointlightcount) for (unsigned i = 0; i < sun_ortho_matrix.size(); i++) sun_ortho_matrix[i] *= getInvViewMatrix(); - m_rtts->getFBO(FBO_COMBINED_TMP1_TMP2).Bind(); + m_rtts->getFBO(FBO_COMBINED_DIFFUSE_SPECULAR).Bind(); if (!UserConfigParams::m_dynamic_lights) glClearColor(.5, .5, .5, .5); glClear(GL_COLOR_BUFFER_BIT); if (!UserConfigParams::m_dynamic_lights) return; - m_rtts->getFBO(FBO_TMP1_WITH_DS).Bind(); + m_rtts->getFBO(FBO_DIFFUSE).Bind(); if (UserConfigParams::m_gi) { ScopedGPUTimer timer(irr_driver->getGPUTimer(Q_GI)); @@ -181,7 +182,7 @@ void IrrDriver::renderLights(unsigned pointlightcount) m_post_processing->renderDiffuseEnvMap(blueSHCoeff, greenSHCoeff, redSHCoeff); } - m_rtts->getFBO(FBO_COMBINED_TMP1_TMP2).Bind(); + m_rtts->getFBO(FBO_COMBINED_DIFFUSE_SPECULAR).Bind(); // Render sunlight if and only if track supports shadow if (!World::getWorld() || World::getWorld()->getTrack()->hasShadows()) diff --git a/src/graphics/render_skybox.cpp b/src/graphics/render_skybox.cpp index adafbf66e..8fcd5c9a6 100644 --- a/src/graphics/render_skybox.cpp +++ b/src/graphics/render_skybox.cpp @@ -16,7 +16,6 @@ #include "graphics/screenquad.hpp" #include "graphics/shaders.hpp" #include "graphics/stkmeshscenenode.hpp" -#include "graphics/stkinstancedscenenode.hpp" #include "graphics/wind.hpp" #include "io/file_manager.hpp" #include "items/item.hpp" @@ -440,6 +439,7 @@ GLuint generateCubeMapFromTextures(const std::vector<video::ITexture *> &texture swapPixels(tmp, rgba[i], size, x, y, (size - y - 1), x); } } + free(tmp); } glBindTexture(GL_TEXTURE_CUBE_MAP, result); @@ -448,6 +448,7 @@ GLuint generateCubeMapFromTextures(const std::vector<video::ITexture *> &texture else glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_SRGB_ALPHA, size, size, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid*)rgba[i]); } + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); for (unsigned i = 0; i < 6; i++) delete[] rgba[i]; return result; @@ -552,7 +553,7 @@ void IrrDriver::renderSkybox(const scene::ICameraSceneNode *camera) return; if (!SkyboxCubeMap) generateSkyboxCubemap(); - glBindVertexArray(MeshShader::SkyboxShader::cubevao); + glBindVertexArray(MeshShader::SkyboxShader::getInstance()->cubevao); glDisable(GL_CULL_FACE); assert(SkyboxTextures.size() == 6); @@ -567,15 +568,10 @@ void IrrDriver::renderSkybox(const scene::ICameraSceneNode *camera) core::matrix4 invtransform; transform.getInverse(invtransform); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, SkyboxCubeMap); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glUseProgram(MeshShader::SkyboxShader::Program); - MeshShader::SkyboxShader::setUniforms(transform, - core::vector2df(float(UserConfigParams::m_width), - float(UserConfigParams::m_height)), - 0); + glUseProgram(MeshShader::SkyboxShader::getInstance()->Program); + MeshShader::SkyboxShader::getInstance()->setUniforms(transform); + MeshShader::SkyboxShader::getInstance()->SetTextureUnits(createVector<GLuint>(SkyboxCubeMap)); + glDrawElements(GL_TRIANGLES, 6 * 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0); } \ No newline at end of file diff --git a/src/graphics/rtts.cpp b/src/graphics/rtts.cpp index aa6ecb6e2..c37c097fb 100644 --- a/src/graphics/rtts.cpp +++ b/src/graphics/rtts.cpp @@ -29,11 +29,9 @@ static GLuint generateRTT3D(GLenum target, size_t w, size_t h, size_t d, GLint i GLuint result; glGenTextures(1, &result); glBindTexture(target, result); -#if WIN32 - if (irr_driver->getGLSLVersion() >= 420) + if (irr_driver->hasARBTextureStorage()) glTexStorage3D(target, 1, internalFormat, w, h, d); else -#endif glTexImage3D(target, 0, internalFormat, w, h, d, 0, format, type, 0); return result; } @@ -43,11 +41,9 @@ static GLuint generateRTT(const core::dimension2du &res, GLint internalFormat, G GLuint result; glGenTextures(1, &result); glBindTexture(GL_TEXTURE_2D, result); -#if WIN32 - if (irr_driver->getGLSLVersion() >= 420) + if (irr_driver->hasARBTextureStorage()) glTexStorage2D(GL_TEXTURE_2D, mipmaplevel, internalFormat, res.Width, res.Height); else -#endif glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, res.Width, res.Height, 0, format, type, 0); return result; } @@ -115,6 +111,8 @@ RTT::RTT(size_t width, size_t height) RenderTargetTextures[RTT_MLAA_BLEND] = generateRTT(res, GL_SRGB8_ALPHA8, GL_BGR, GL_UNSIGNED_BYTE); RenderTargetTextures[RTT_SSAO] = generateRTT(res, GL_R16F, GL_RED, GL_FLOAT); RenderTargetTextures[RTT_DISPLACE] = generateRTT(res, GL_RGBA16F, GL_BGRA, GL_FLOAT); + RenderTargetTextures[RTT_DIFFUSE] = generateRTT(res, GL_RGBA16F, GL_BGRA, GL_FLOAT); + RenderTargetTextures[RTT_SPECULAR] = generateRTT(res, GL_RGBA16F, GL_BGRA, GL_FLOAT); RenderTargetTextures[RTT_HALF1] = generateRTT(half, GL_RGBA16F, GL_BGRA, GL_FLOAT); RenderTargetTextures[RTT_QUARTER1] = generateRTT(quarter, GL_RGBA16F, GL_BGRA, GL_FLOAT); @@ -133,7 +131,6 @@ RTT::RTT(size_t width, size_t height) RenderTargetTextures[RTT_TMP_256] = generateRTT(shadowsize2, GL_RGBA16F, GL_BGR, GL_FLOAT); RenderTargetTextures[RTT_BLOOM_128] = generateRTT(shadowsize3, GL_RGBA16F, GL_BGR, GL_FLOAT); RenderTargetTextures[RTT_TMP_128] = generateRTT(shadowsize3, GL_RGBA16F, GL_BGR, GL_FLOAT); - RenderTargetTextures[RTT_LOG_LUMINANCE] = generateRTT(shadowsize0, GL_R16F, GL_RED, GL_FLOAT); std::vector<GLuint> somevector; somevector.push_back(RenderTargetTextures[RTT_SSAO]); @@ -143,14 +140,17 @@ RTT::RTT(size_t width, size_t height) somevector.push_back(RenderTargetTextures[RTT_NORMAL_AND_DEPTH]); FrameBuffers.push_back(new FrameBuffer(somevector, DepthStencilTexture, res.Width, res.Height)); somevector.clear(); - somevector.push_back(RenderTargetTextures[RTT_TMP1]); - somevector.push_back(RenderTargetTextures[RTT_TMP2]); + somevector.push_back(RenderTargetTextures[RTT_DIFFUSE]); + somevector.push_back(RenderTargetTextures[RTT_SPECULAR]); FrameBuffers.push_back(new FrameBuffer(somevector, DepthStencilTexture, res.Width, res.Height)); somevector.clear(); somevector.push_back(RenderTargetTextures[RTT_COLOR]); FrameBuffers.push_back(new FrameBuffer(somevector, DepthStencilTexture, res.Width, res.Height)); somevector.clear(); - somevector.push_back(RenderTargetTextures[RTT_LOG_LUMINANCE]); + somevector.push_back(RenderTargetTextures[RTT_DIFFUSE]); + FrameBuffers.push_back(new FrameBuffer(somevector, res.Width, res.Height)); + somevector.clear(); + somevector.push_back(RenderTargetTextures[RTT_SPECULAR]); FrameBuffers.push_back(new FrameBuffer(somevector, res.Width, res.Height)); somevector.clear(); somevector.push_back(RenderTargetTextures[RTT_MLAA_COLORS]); diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index 289a68f76..0b1391a8e 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -103,10 +103,7 @@ using namespace video; -GLuint getUniformLocation(GLuint program, const char* name) -{ - return glGetUniformLocation(program, name); -} +std::vector<void(*)()> CleanTable; Shaders::Shaders() { @@ -294,7 +291,7 @@ static void initShadowVPMUBO() { glGenBuffers(1, &SharedObject::ViewProjectionMatrixesUBO); glBindBuffer(GL_UNIFORM_BUFFER, SharedObject::ViewProjectionMatrixesUBO); - glBufferData(GL_UNIFORM_BUFFER, (16 * 8 + 2) * sizeof(float), 0, GL_STATIC_DRAW); + glBufferData(GL_UNIFORM_BUFFER, (16 * 9 + 2) * sizeof(float), 0, GL_STREAM_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); } @@ -402,6 +399,7 @@ void Shaders::loadShaders() } initGL(); + CleanTable.clear(); initQuadVBO(); initQuadBuffer(); initBillboardVBO(); @@ -409,14 +407,17 @@ void Shaders::loadShaders() initFrustrumVBO(); initShadowVPMUBO(); initParticleQuadVBO(); - FullScreenShader::DiffuseEnvMapShader::init(); MeshShader::BubbleShader::init(); - LightShader::PointLightShader::init(); - MeshShader::SkyboxShader::init(); MeshShader::ViewFrustrumShader::init(); UtilShader::ColoredLine::init(); } +void Shaders::killShaders() +{ + for (unsigned i = 0; i < CleanTable.size(); i++) + CleanTable[i](); +} + Shaders::~Shaders() { u32 i; @@ -565,41 +566,209 @@ namespace UtilShader } using namespace UtilShader; -void glUniformMatrix4fvWraper(GLuint a, size_t b, unsigned c, const float *d) -{ - glUniformMatrix4fv(a, b, c, d); -} - -void glUniform3fWraper(GLuint a, float b, float c, float d) -{ - glUniform3f(a, b, c, d); -} - -void glUniform4iWraper(GLuint a, int b, int c, int d, int e) -{ - glUniform4i(a, b, c, d, e); -} - -void glUniform2fWraper(GLuint a, float b, float c) -{ - glUniform2f(a, b, c); -} - -void glUniform1fWrapper(GLuint a, float b) -{ - glUniform1f(a, b); -} - -void glUniform1iWrapper(GLuint a, int b) -{ - glUniform1i(a, b); -} - bool needsUBO() { return irr_driver->needUBOWorkaround(); } +void setTextureSampler(GLenum tp, GLuint texunit, GLuint tid, GLuint sid) +{ +#ifdef GL_VERSION_3_3 + glActiveTexture(GL_TEXTURE0 + texunit); + glBindTexture(tp, tid); + glBindSampler(texunit, sid); +#endif +} + + +GLuint createNearestSampler() +{ +#ifdef GL_VERSION_3_3 + unsigned id; + glGenSamplers(1, &id); + glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glSamplerParameteri(id, GL_TEXTURE_WRAP_S, GL_REPEAT); + glSamplerParameteri(id, GL_TEXTURE_WRAP_T, GL_REPEAT); + glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.); + return id; +#endif +} + +void BindTextureNearest(GLuint TU, GLuint tex) +{ + glActiveTexture(GL_TEXTURE0 + TU); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.); +} + +GLuint createBilinearSampler() +{ +#ifdef GL_VERSION_3_3 + unsigned id; + glGenSamplers(1, &id); + glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(id, GL_TEXTURE_WRAP_S, GL_REPEAT); + glSamplerParameteri(id, GL_TEXTURE_WRAP_T, GL_REPEAT); + glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.); + return id; +#endif +} + +void BindTextureBilinear(GLuint TU, GLuint tex) +{ + glActiveTexture(GL_TEXTURE0 + TU); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.); +} + +GLuint createBilinearClampedSampler() +{ +#ifdef GL_VERSION_3_3 + unsigned id; + glGenSamplers(1, &id); + glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.); + return id; +#endif +} + +void BindTextureBilinearClamped(GLuint TU, GLuint tex) +{ + glActiveTexture(GL_TEXTURE0 + TU); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.); +} + +GLuint createSemiTrilinearSampler() +{ +#ifdef GL_VERSION_3_3 + unsigned id; + glGenSamplers(1, &id); + glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + glSamplerParameteri(id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.); + return id; +#endif +} + +void BindTextureSemiTrilinear(GLuint TU, GLuint tex) +{ + glActiveTexture(GL_TEXTURE0 + TU); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.); +} + +GLuint createTrilinearSampler() +{ +#ifdef GL_VERSION_3_3 + unsigned id; + glGenSamplers(1, &id); + glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glSamplerParameteri(id, GL_TEXTURE_WRAP_S, GL_REPEAT); + glSamplerParameteri(id, GL_TEXTURE_WRAP_T, GL_REPEAT); + + int aniso = UserConfigParams::m_anisotropic; + if (aniso == 0) aniso = 1; + glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)aniso); + return id; +#endif +} + +void BindTextureTrilinearAnisotropic(GLuint TU, GLuint tex) +{ + glActiveTexture(GL_TEXTURE0 + TU); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + int aniso = UserConfigParams::m_anisotropic; + if (aniso == 0) aniso = 1; + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)aniso); +} + +void BindCubemapTrilinear(unsigned TU, unsigned tex) +{ + glActiveTexture(GL_TEXTURE0 + TU); + glBindTexture(GL_TEXTURE_CUBE_MAP, tex); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_REPEAT); + + int aniso = UserConfigParams::m_anisotropic; + if (aniso == 0) aniso = 1; + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)aniso); +} + +GLuint createShadowSampler() +{ +#ifdef GL_VERSION_3_3 + unsigned id; + glGenSamplers(1, &id); + glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(id, GL_TEXTURE_WRAP_S, GL_REPEAT); + glSamplerParameteri(id, GL_TEXTURE_WRAP_T, GL_REPEAT); + glSamplerParameterf(id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glSamplerParameterf(id, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + return id; +#endif +} + +void BindTextureShadow(GLuint TU, GLuint tex) +{ + glActiveTexture(GL_TEXTURE0 + TU); + glBindTexture(GL_TEXTURE_2D_ARRAY, tex); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); +} + +void BindTextureVolume(GLuint TU, GLuint tex) +{ + glActiveTexture(GL_TEXTURE0 + TU); + glBindTexture(GL_TEXTURE_3D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.); +} + +unsigned getGLSLVersion() +{ + return irr_driver->getGLSLVersion(); +} + namespace MeshShader { // Solid Normal and depth pass shaders @@ -614,8 +783,7 @@ namespace MeshShader GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + AssignSamplerNames(Program, 0, "tex"); } ObjectRefPass1Shader::ObjectRefPass1Shader() @@ -629,8 +797,7 @@ namespace MeshShader GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + AssignSamplerNames(Program, 0, "tex"); } GrassPass1Shader::GrassPass1Shader() @@ -640,8 +807,8 @@ namespace MeshShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/objectref_pass1.frag").c_str()); AssignUniforms("ModelMatrix", "InverseModelMatrix", "windDir"); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); } NormalMapShader::NormalMapShader() @@ -655,9 +822,7 @@ namespace MeshShader GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_normalmap = 1; - TU_glossy = 0; - AssignTextureUnit(Program, TexUnit(TU_normalmap, "normalMap"), TexUnit(TU_glossy, "DiffuseForAlpha")); + AssignSamplerNames(Program, 1, "normalMap", 0, "DiffuseForAlpha"); } InstancedObjectPass1Shader::InstancedObjectPass1Shader() @@ -666,10 +831,10 @@ namespace MeshShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_pass1.frag").c_str()); - TU_tex = 0; + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_object_pass1.frag").c_str()); + AssignUniforms(); - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + AssignSamplerNames(Program, 0, "tex"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); @@ -681,10 +846,10 @@ namespace MeshShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/objectref_pass1.frag").c_str()); - TU_tex = 0; + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_objectref_pass1.frag").c_str()); + AssignUniforms(); - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + AssignSamplerNames(Program, 0, "tex"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); @@ -696,10 +861,10 @@ namespace MeshShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_grass.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/objectref_pass1.frag").c_str()); + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_objectref_pass1.frag").c_str()); AssignUniforms("windDir"); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); @@ -711,15 +876,13 @@ namespace MeshShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/normalmap.frag").c_str()); + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_normalmap.frag").c_str()); AssignUniforms(); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_normalmap = 1; - TU_glossy = 0; - AssignTextureUnit(Program, TexUnit(TU_normalmap, "normalMap"), TexUnit(TU_glossy, "DiffuseForAlpha")); + AssignSamplerNames(Program, 0, "normalMap", 1, "DiffuseForAlpha"); } // Solid Lit pass shaders @@ -734,14 +897,7 @@ namespace MeshShader GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_Albedo = 3; - - AssignTextureUnit(Program, - TexUnit(0, "DiffuseMap"), - TexUnit(1, "SpecularMap"), - TexUnit(2, "SSAO"), - TexUnit(TU_Albedo, "Albedo") - ); + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo"); } InstancedObjectPass2Shader::InstancedObjectPass2Shader() @@ -750,16 +906,10 @@ namespace MeshShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_pass2.frag").c_str()); + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_object_pass2.frag").c_str()); AssignUniforms(); - TU_Albedo = 3; - AssignTextureUnit(Program, - TexUnit(0, "DiffuseMap"), - TexUnit(1, "SpecularMap"), - TexUnit(2, "SSAO"), - TexUnit(TU_Albedo, "Albedo") - ); + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); @@ -772,16 +922,10 @@ namespace MeshShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/objectref_pass2.frag").c_str()); + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_objectref_pass2.frag").c_str()); AssignUniforms(); - TU_Albedo = 3; - AssignTextureUnit(Program, - TexUnit(0, "DiffuseMap"), - TexUnit(1, "SpecularMap"), - TexUnit(2, "SSAO"), - TexUnit(TU_Albedo, "Albedo") - ); + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); @@ -796,16 +940,23 @@ namespace MeshShader AssignUniforms("ModelMatrix"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_Albedo = 3; - TU_detail = 4; - AssignTextureUnit(Program, - TexUnit(0, "DiffuseMap"), - TexUnit(1, "SpecularMap"), - TexUnit(2, "SSAO"), - TexUnit(TU_Albedo, "Albedo"), - TexUnit(TU_detail, "Detail") - ); + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo", 4, "Detail"); + } + + InstancedDetailledObjectPass2Shader::InstancedDetailledObjectPass2Shader() + { + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), + GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_detailledobject_pass2.frag").c_str()); + AssignUniforms(); + + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo", 4, "Detail"); + + GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); + glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); } ObjectUnlitShader::ObjectUnlitShader() @@ -813,14 +964,26 @@ namespace MeshShader Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/object_pass.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str()); - AssignUniforms("ModelMatrix"); + AssignUniforms("ModelMatrix", "TextureMatrix"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_tex = 3; + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "tex"); + } - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + InstancedObjectUnlitShader::InstancedObjectUnlitShader() + { + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), + GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_object_unlit.frag").c_str()); + AssignUniforms(); + + GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); + glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); + + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "tex"); } ObjectRefPass2Shader::ObjectRefPass2Shader() @@ -834,14 +997,7 @@ namespace MeshShader GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_Albedo = 3; - - AssignTextureUnit(Program, - TexUnit(0, "DiffuseMap"), - TexUnit(1, "SpecularMap"), - TexUnit(2, "SSAO"), - TexUnit(TU_Albedo, "Albedo") - ); + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo"); } GrassPass2Shader::GrassPass2Shader() @@ -851,14 +1007,8 @@ namespace MeshShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/grass_pass2.frag").c_str()); AssignUniforms("ModelMatrix", "windDir"); - TU_Albedo = 3; - AssignTextureUnit(Program, - TexUnit(0, "DiffuseMap"), - TexUnit(1, "SpecularMap"), - TexUnit(2, "SSAO"), - TexUnit(TU_Albedo, "Albedo") - ); + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo"); } InstancedGrassPass2Shader::InstancedGrassPass2Shader() @@ -867,18 +1017,10 @@ namespace MeshShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_grass.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/grass_pass2.frag").c_str()); + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_grass_pass2.frag").c_str()); AssignUniforms("windDir", "SunDir"); - TU_Albedo = 3; - TU_dtex = 4; - AssignTextureUnit(Program, - TexUnit(0, "DiffuseMap"), - TexUnit(1, "SpecularMap"), - TexUnit(2, "SSAO"), - TexUnit(TU_Albedo, "Albedo"), - TexUnit(TU_dtex, "dtex") - ); + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "dtex", 4, "Albedo"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); @@ -896,14 +1038,23 @@ namespace MeshShader GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_tex = 3; + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "tex"); + } - AssignTextureUnit(Program, - TexUnit(0, "DiffuseMap"), - TexUnit(1, "SpecularMap"), - TexUnit(2, "SSAO"), - TexUnit(TU_tex, "tex") - ); + InstancedSphereMapShader::InstancedSphereMapShader() + { + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), + GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_object_pass.vert").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_objectpass_spheremap.frag").c_str()); + AssignUniforms(); + + GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); + glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); + + AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "tex"); } SplattingShader::SplattingShader() @@ -913,22 +1064,16 @@ namespace MeshShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/splatting.frag").c_str()); AssignUniforms("ModelMatrix"); - TU_tex_layout = 3; - TU_tex_detail0 = 4; - TU_tex_detail1 = 5; - TU_tex_detail2 = 6; - TU_tex_detail3 = 7; - AssignTextureUnit(Program, - TexUnit(0, "DiffuseMap"), - TexUnit(1, "SpecularMap"), - TexUnit(2, "SSAO"), - TexUnit(TU_tex_layout, "tex_layout"), - TexUnit(TU_tex_detail0, "tex_detail0"), - TexUnit(TU_tex_detail1, "tex_detail1"), - TexUnit(TU_tex_detail2, "tex_detail2"), - TexUnit(TU_tex_detail3, "tex_detail3") - ); + AssignSamplerNames(Program, + 0, "DiffuseMap", + 1, "SpecularMap", + 2, "SSAO", + 3, "tex_layout", + 4, "tex_detail0", + 5, "tex_detail1", + 6, "tex_detail2", + 7, "tex_detail3"); } GLuint BubbleShader::Program; @@ -965,9 +1110,7 @@ namespace MeshShader GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_tex = 0; - - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + AssignSamplerNames(Program, 0, "tex"); } TransparentFogShader::TransparentFogShader() @@ -980,9 +1123,7 @@ namespace MeshShader GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_tex = 0; - - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + AssignSamplerNames(Program, 0, "tex"); } BillboardShader::BillboardShader() @@ -995,9 +1136,7 @@ namespace MeshShader glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); AssignUniforms("ModelViewMatrix", "ProjectionMatrix", "Position", "Size"); - TU_tex = 0; - - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + AssignSamplerNames(Program, 0, "tex"); } ColorizeShader::ColorizeShader() @@ -1011,6 +1150,18 @@ namespace MeshShader glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); } + InstancedColorizeShader::InstancedColorizeShader() + { + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), + GL_VERTEX_SHADER, file_manager->getAsset("shaders/glow_object.vert").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/glow_object.frag").c_str()); + AssignUniforms(); + + GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); + glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); + } + ShadowShader::ShadowShader() { // Geometry shader needed @@ -1029,7 +1180,7 @@ namespace MeshShader GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/white.frag").c_str()); } - AssignUniforms("ModelMatrix"); + AssignUniforms("layer", "ModelMatrix"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); } @@ -1039,9 +1190,23 @@ namespace MeshShader Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/rsm.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/rsm.frag").c_str()); - TU_tex = 0; + AssignUniforms("RSMMatrix", "ModelMatrix", "TextureMatrix"); - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + AssignSamplerNames(Program, 0, "tex"); + + GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); + glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); + } + + InstancedRSMShader::InstancedRSMShader() + { + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), + GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_rsm.vert").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_rsm.frag").c_str()); + + AssignUniforms("RSMMatrix"); + AssignSamplerNames(Program, 0, "tex"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); @@ -1052,13 +1217,9 @@ namespace MeshShader Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/rsm.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/splatting_rsm.frag").c_str()); - TU_layout = 0; - TU_detail0 = 1; - TU_detail1 = 2; - TU_detail2 = 3; - TU_detail3 = 4; + AssignUniforms("RSMMatrix", "ModelMatrix"); - AssignTextureUnit(Program, TexUnit(TU_layout, "tex_layout"), TexUnit(TU_detail0, "tex_detail0"), TexUnit(TU_detail1, "tex_detail1"), TexUnit(TU_detail2, "tex_detail2"), TexUnit(TU_detail3, "tex_detail3")); + AssignSamplerNames(Program, 0, "tex_layout", 1, "tex_detail0", 2, "tex_detail1", 3, "tex_detail2", 4, "tex_detail3"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); @@ -1081,9 +1242,10 @@ namespace MeshShader Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedshadow.vert").c_str(), - GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(), + GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/instanced_shadow.geom").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/white.frag").c_str()); } + AssignUniforms("layer"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); } @@ -1106,12 +1268,11 @@ namespace MeshShader GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str()); } - AssignUniforms("ModelMatrix"); + AssignUniforms("layer", "ModelMatrix"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_tex = 0; - AssignTextureUnit(Program, { TexUnit(TU_tex, "tex") }); + AssignSamplerNames(Program, 0, "tex"); } InstancedRefShadowShader::InstancedRefShadowShader() @@ -1124,18 +1285,18 @@ namespace MeshShader Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedshadow.vert").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str()); + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_shadowref.frag").c_str()); } else { Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedshadow.vert").c_str(), - GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str()); + GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/instanced_shadow.geom").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_shadowref.frag").c_str()); } - TU_tex = 0; - AssignTextureUnit(Program, { TexUnit(TU_tex, "tex") }); + AssignUniforms("layer"); + AssignSamplerNames(Program, 0, "tex"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); } @@ -1158,12 +1319,11 @@ namespace MeshShader GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str()); } - AssignUniforms("ModelMatrix", "windDir"); + AssignUniforms("layer", "ModelMatrix", "windDir"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); - TU_tex = 0; - AssignTextureUnit(Program, { TexUnit(TU_tex, "tex") }); + AssignSamplerNames(Program, 0, "tex"); } InstancedGrassShadowShader::InstancedGrassShadowShader() @@ -1176,20 +1336,20 @@ namespace MeshShader Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedgrassshadow.vert").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str()); + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_shadowref.frag").c_str()); } else { Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedgrassshadow.vert").c_str(), - GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str()); + GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/instanced_shadow.geom").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_shadowref.frag").c_str()); } - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); - AssignUniforms("windDir"); + AssignSamplerNames(Program, 0, "tex"); + + AssignUniforms("layer", "windDir"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); } @@ -1212,34 +1372,23 @@ namespace MeshShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/displace.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/displace.frag").c_str()); AssignUniforms("ModelMatrix", "dir", "dir2"); - TU_displacement_tex = 0; - TU_color_tex = 1; - TU_mask_tex = 2; - TU_tex = 3; - AssignTextureUnit(Program, - TexUnit(TU_displacement_tex, "displacement_tex"), - TexUnit(TU_color_tex, "color_tex"), - TexUnit(TU_mask_tex, "mask_tex"), - TexUnit(TU_tex, "tex") - ); + + AssignSamplerNames(Program, + 0, "displacement_tex", + 1, "color_tex", + 2, "mask_tex", + 3, "tex"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); } - GLuint SkyboxShader::Program; - GLuint SkyboxShader::attrib_position; - GLuint SkyboxShader::uniform_MM; - GLuint SkyboxShader::uniform_tex; - GLuint SkyboxShader::cubevao; - - void SkyboxShader::init() + SkyboxShader::SkyboxShader() { Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/object_pass.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/sky.frag").c_str()); - attrib_position = glGetAttribLocation(Program, "Position"); - uniform_MM = glGetUniformLocation(Program, "ModelMatrix"); - uniform_tex = glGetUniformLocation(Program, "tex"); + AssignUniforms("ModelMatrix"); + AssignSamplerNames(Program, 0, "tex"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); @@ -1247,20 +1396,12 @@ namespace MeshShader glGenVertexArrays(1, &cubevao); glBindVertexArray(cubevao); glBindBuffer(GL_ARRAY_BUFFER, SharedObject::cubevbo); - glEnableVertexAttribArray(attrib_position); - glVertexAttribPointer(attrib_position, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedObject::cubeindexes); glBindVertexArray(0); } - void SkyboxShader::setUniforms(const core::matrix4 &ModelMatrix, const core::vector2df &screen, unsigned TU_tex) - { - if (irr_driver->needUBOWorkaround()) - bypassUBO(Program); - glUniformMatrix4fv(uniform_MM, 1, GL_FALSE, ModelMatrix.pointer()); - glUniform1i(uniform_tex, TU_tex); - } - NormalVisualizer::NormalVisualizer() { Program = LoadProgram( @@ -1310,19 +1451,7 @@ namespace MeshShader namespace LightShader { - - GLuint PointLightShader::Program; - GLuint PointLightShader::attrib_Position; - GLuint PointLightShader::attrib_Color; - GLuint PointLightShader::attrib_Energy; - GLuint PointLightShader::attrib_Radius; - GLuint PointLightShader::uniform_ntex; - GLuint PointLightShader::uniform_dtex; - GLuint PointLightShader::uniform_spec; - GLuint PointLightShader::vbo; - GLuint PointLightShader::vao; - - void PointLightShader::init() + PointLightShader::PointLightShader() { Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/pointlight.vert").c_str(), @@ -1330,13 +1459,9 @@ namespace LightShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getSpecular.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/pointlight.frag").c_str()); - attrib_Position = glGetAttribLocation(Program, "Position"); - attrib_Color = glGetAttribLocation(Program, "Color"); - attrib_Energy = glGetAttribLocation(Program, "Energy"); - attrib_Radius = glGetAttribLocation(Program, "Radius"); - uniform_ntex = glGetUniformLocation(Program, "ntex"); - uniform_dtex = glGetUniformLocation(Program, "dtex"); - uniform_spec = glGetUniformLocation(Program, "spec"); + + AssignUniforms(); + AssignSamplerNames(Program, 0, "ntex", 1, "dtex"); glGenVertexArrays(1, &vao); glBindVertexArray(vao); @@ -1345,6 +1470,11 @@ namespace LightShader glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, MAXLIGHT * sizeof(PointLightInfo), 0, GL_DYNAMIC_DRAW); + GLuint attrib_Position = glGetAttribLocation(Program, "Position"); + GLuint attrib_Color = glGetAttribLocation(Program, "Color"); + GLuint attrib_Energy = glGetAttribLocation(Program, "Energy"); + GLuint attrib_Radius = glGetAttribLocation(Program, "Radius"); + glEnableVertexAttribArray(attrib_Position); glVertexAttribPointer(attrib_Position, 3, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), 0); glEnableVertexAttribArray(attrib_Energy); @@ -1359,17 +1489,6 @@ namespace LightShader glVertexAttribDivisor(attrib_Color, 1); glVertexAttribDivisor(attrib_Radius, 1); } - - void PointLightShader::setUniforms(const core::vector2df &screen, unsigned spec, unsigned TU_ntex, unsigned TU_dtex) - { - if (irr_driver->needUBOWorkaround()) - bypassUBO(Program); - glUniform1f(uniform_spec, 200); - - glUniform1i(uniform_ntex, TU_ntex); - glUniform1i(uniform_dtex, TU_dtex); - } - } @@ -1409,9 +1528,7 @@ namespace ParticleShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/particle.frag").c_str()); AssignUniforms("color_from", "color_to"); - TU_tex = 0; - TU_dtex = 1; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex"), TexUnit(TU_dtex, "dtex")); + AssignSamplerNames(Program, 0, "tex", 1, "dtex"); } FlipParticleRender::FlipParticleRender() @@ -1422,9 +1539,7 @@ namespace ParticleShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/particle.frag").c_str()); AssignUniforms(); - TU_tex = 0; - TU_dtex = 1; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex"), TexUnit(TU_dtex, "dtex")); + AssignSamplerNames(Program, 0, "tex", 1, "dtex"); } } @@ -1453,8 +1568,8 @@ namespace FullScreenShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getCIEXYZ.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/bloom.frag").c_str()); AssignUniforms(); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); } BloomBlendShader::BloomBlendShader() @@ -1463,10 +1578,8 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/bloomblend.frag").c_str()); AssignUniforms(); - TU_tex_128 = 0; - TU_tex_256 = 1; - TU_tex_512 = 2; - AssignTextureUnit(Program, TexUnit(TU_tex_128, "tex_128"), TexUnit(TU_tex_256, "tex_256"), TexUnit(TU_tex_512, "tex_512")); + + AssignSamplerNames(Program, 0, "tex_128", 1, "tex_256", 2, "tex_512"); } ToneMapShader::ToneMapShader() @@ -1477,8 +1590,8 @@ namespace FullScreenShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getCIEXYZ.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/tonemap.frag").c_str()); AssignUniforms(); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "text")); + + AssignSamplerNames(Program, 0, "text"); } DepthOfFieldShader::DepthOfFieldShader() @@ -1486,10 +1599,9 @@ namespace FullScreenShader Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/dof.frag").c_str()); - TU_tex = 0; - TU_depth = 1; + AssignUniforms(); - AssignTextureUnit(Program, TexUnit(TU_tex, "tex"), TexUnit(TU_depth, "dtex")); + AssignSamplerNames(Program, 0, "tex", 1, "dtex"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); @@ -1503,42 +1615,22 @@ namespace FullScreenShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getSpecular.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/sunlight.frag").c_str()); - TU_ntex = 0; - TU_dtex = 1; - AssignTextureUnit(Program, TexUnit(TU_ntex, "ntex"), TexUnit(TU_dtex, "dtex")); + + AssignSamplerNames(Program, 0, "ntex", 1, "dtex"); AssignUniforms("direction", "col"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); } - GLuint DiffuseEnvMapShader::Program; - GLuint DiffuseEnvMapShader::uniform_ntex; - GLuint DiffuseEnvMapShader::uniform_blueLmn; - GLuint DiffuseEnvMapShader::uniform_greenLmn; - GLuint DiffuseEnvMapShader::uniform_redLmn; - GLuint DiffuseEnvMapShader::uniform_TVM; - - void DiffuseEnvMapShader::init() + DiffuseEnvMapShader::DiffuseEnvMapShader() { Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/decodeNormal.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/diffuseenvmap.frag").c_str()); - uniform_ntex = glGetUniformLocation(Program, "ntex"); - uniform_blueLmn = glGetUniformLocation(Program, "blueLmn[0]"); - uniform_greenLmn = glGetUniformLocation(Program, "greenLmn[0]"); - uniform_redLmn = glGetUniformLocation(Program, "redLmn[0]"); - uniform_TVM = glGetUniformLocation(Program, "TransposeViewMatrix"); - } - - void DiffuseEnvMapShader::setUniforms(const core::matrix4 &TransposeViewMatrix, const float *blueSHCoeff, const float *greenSHCoeff, const float *redSHCoeff, unsigned TU_ntex) - { - glUniformMatrix4fv(uniform_TVM, 1, GL_FALSE, TransposeViewMatrix.pointer()); - glUniform1i(uniform_ntex, TU_ntex); - glUniform1fv(uniform_blueLmn, 9, blueSHCoeff); - glUniform1fv(uniform_greenLmn, 9, greenSHCoeff); - glUniform1fv(uniform_redLmn, 9, redSHCoeff); + AssignUniforms("TransposeViewMatrix", "blueLmn[0]", "greenLmn[0]", "redLmn[0]"); + AssignSamplerNames(Program, 0, "ntex"); } ShadowedSunLightShader::ShadowedSunLightShader() @@ -1549,10 +1641,9 @@ namespace FullScreenShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getSpecular.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/sunlightshadow.frag").c_str()); - TU_ntex = 0; - TU_dtex = 1; - TU_shadowtex = 2; - AssignTextureUnit(Program, TexUnit(TU_ntex, "ntex"), TexUnit(TU_dtex, "dtex"), TexUnit(TU_shadowtex, "shadowtex")); + + // Use 8 to circumvent a catalyst bug when binding sampler + AssignSamplerNames(Program, 0, "ntex", 1, "dtex", 8, "shadowtex"); AssignUniforms("direction", "col"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); @@ -1578,10 +1669,7 @@ namespace FullScreenShader } AssignUniforms("RSMMatrix", "RHMatrix", "extents"); - TU_ctex = 0; - TU_ntex = 1; - TU_dtex = 2; - AssignTextureUnit(Program, TexUnit(TU_ctex, "ctex"), TexUnit(TU_ntex, "ntex"), TexUnit(TU_dtex, "dtex")); + AssignSamplerNames(Program, 0, "ctex", 1, "ntex", 2, "dtex"); } NVWorkaroundRadianceHintsConstructionShader::NVWorkaroundRadianceHintsConstructionShader() @@ -1594,10 +1682,8 @@ namespace FullScreenShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/rh.frag").c_str()); AssignUniforms("RSMMatrix", "RHMatrix", "extents", "slice"); - TU_ctex = 0; - TU_ntex = 1; - TU_dtex = 2; - AssignTextureUnit(Program, TexUnit(TU_ctex, "ctex"), TexUnit(TU_ntex, "ntex"), TexUnit(TU_dtex, "dtex")); + + AssignSamplerNames(Program, 0, "ctex", 1, "ntex", 2, "dtex"); } RHDebug::RHDebug() @@ -1623,12 +1709,8 @@ namespace FullScreenShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/gi.frag").c_str()); AssignUniforms("RHMatrix", "InvRHMatrix", "extents"); - TU_ntex = 0; - TU_dtex = 1; - TU_SHR = 2; - TU_SHG = 3; - TU_SHB = 4; - AssignTextureUnit(Program, TexUnit(TU_ntex, "ntex"), TexUnit(TU_dtex, "dtex"), TexUnit(TU_SHR, "SHR"), TexUnit(TU_SHG, "SHG"), TexUnit(TU_SHB, "SHB")); + + AssignSamplerNames(Program, 0, "ntex", 1, "dtex", 2, "SHR", 3, "SHG", 4, "SHB"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); } @@ -1639,15 +1721,14 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/bilateralH.frag").c_str()); AssignUniforms("pixel"); - TU_tex = 0; - TU_depth = 1; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex"), TexUnit(TU_depth, "depth")); + + AssignSamplerNames(Program, 0, "tex", 1, "depth"); } ComputeGaussian17TapHShader::ComputeGaussian17TapHShader() { -#if WIN32 - if (irr_driver->getGLSLVersion() < 420) + + if (irr_driver->hasARBComputeShaders()) return; Program = LoadProgram( GL_COMPUTE_SHADER, file_manager->getAsset("shaders/bilateralH.comp").c_str()); @@ -1656,7 +1737,6 @@ namespace FullScreenShader TU_dest = 2; AssignUniforms(); AssignTextureUnit(Program, TexUnit(TU_source, "source"), TexUnit(TU_depth, "depth"), TexUnit(TU_dest, "dest")); -#endif } Gaussian6HBlurShader::Gaussian6HBlurShader() @@ -1665,8 +1745,8 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/gaussian6h.frag").c_str()); AssignUniforms("pixel"); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); } Gaussian3HBlurShader::Gaussian3HBlurShader() @@ -1675,8 +1755,8 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/gaussian3h.frag").c_str()); AssignUniforms("pixel"); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); } Gaussian17TapVShader::Gaussian17TapVShader() @@ -1685,15 +1765,13 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/bilateralV.frag").c_str()); AssignUniforms("pixel"); - TU_tex = 0; - TU_depth = 1; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex"), TexUnit(TU_depth, "depth")); + + AssignSamplerNames(Program, 0, "tex", 1, "depth"); } ComputeGaussian17TapVShader::ComputeGaussian17TapVShader() { -#if WIN32 - if (irr_driver->getGLSLVersion() < 420) + if (irr_driver->hasARBComputeShaders()) return; Program = LoadProgram( GL_COMPUTE_SHADER, file_manager->getAsset("shaders/bilateralV.comp").c_str()); @@ -1701,7 +1779,6 @@ namespace FullScreenShader TU_depth = 1; TU_dest = 2; AssignTextureUnit(Program, TexUnit(TU_source, "source"), TexUnit(TU_depth, "depth"), TexUnit(TU_dest, "dest")); -#endif } Gaussian6VBlurShader::Gaussian6VBlurShader() @@ -1710,8 +1787,8 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/gaussian6v.frag").c_str()); AssignUniforms("pixel"); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); } Gaussian3VBlurShader::Gaussian3VBlurShader() @@ -1720,8 +1797,8 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/gaussian3v.frag").c_str()); AssignUniforms("pixel"); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); } PassThroughShader::PassThroughShader() @@ -1729,9 +1806,9 @@ namespace FullScreenShader Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/texturedquad.frag").c_str()); - TU_tex = 0; + AssignUniforms(); - AssignTextureUnit(Program, TexUnit(TU_tex, "texture")); + AssignSamplerNames(Program, 0, "texture"); vao = createVAO(Program); } @@ -1752,8 +1829,8 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/linearizedepth.frag").c_str()); AssignUniforms("zn", "zf"); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "texture")); + + AssignSamplerNames(Program, 0, "texture"); } GlowShader::GlowShader() @@ -1762,8 +1839,8 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/glow.frag").c_str()); AssignUniforms(); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); vao = createVAO(Program); } @@ -1774,8 +1851,8 @@ namespace FullScreenShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/decodeNormal.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/ssao.frag").c_str()); - TU_dtex = 0; - AssignTextureUnit(Program, TexUnit(TU_dtex, "dtex")); + + AssignSamplerNames(Program, 0, "dtex"); AssignUniforms("radius", "k", "sigma"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); @@ -1788,9 +1865,9 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/fog.frag").c_str()); - TU_tex = 0; + AssignUniforms("fogmax", "startH", "endH", "start", "end", "col"); - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + AssignSamplerNames(Program, 0, "tex"); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); @@ -1803,9 +1880,8 @@ namespace FullScreenShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/motion_blur.frag").c_str()); AssignUniforms("previous_viewproj", "center", "boost_amount", "mask_radius"); - TU_cb = 0; - TU_dtex = 1; - AssignTextureUnit(Program, TexUnit(TU_dtex, "dtex"), TexUnit(TU_cb, "color_buffer")); + + AssignSamplerNames(Program, 0, "color_buffer", 1, "dtex"); } GodFadeShader::GodFadeShader() @@ -1814,8 +1890,8 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/godfade.frag").c_str()); AssignUniforms("col"); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); vao = createVAO(Program); } @@ -1824,9 +1900,9 @@ namespace FullScreenShader Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/godray.frag").c_str()); - TU_tex = 0; + AssignUniforms("sunpos"); - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + AssignSamplerNames(Program, 0, "tex"); vao = createVAO(Program); } @@ -1836,8 +1912,8 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/mlaa_offset.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/mlaa_color1.frag").c_str()); AssignUniforms("PIXEL_SIZE"); - TU_colorMapG = 0; - AssignTextureUnit(Program, TexUnit(TU_colorMapG, "colorMapG")); + + AssignSamplerNames(Program, 0, "colorMapG"); vao = createVAO(Program); } @@ -1847,9 +1923,8 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/mlaa_blend2.frag").c_str()); AssignUniforms("PIXEL_SIZE"); - TU_edgesMap = 0; - TU_areaMap = 1; - AssignTextureUnit(Program, TexUnit(TU_edgesMap, "edgesMap"), TexUnit(TU_areaMap, "areaMap")); + + AssignSamplerNames(Program, 0, "edgesMap", 1, "areaMap"); vao = createVAO(Program); } @@ -1859,9 +1934,8 @@ namespace FullScreenShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/mlaa_offset.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/mlaa_neigh3.frag").c_str()); AssignUniforms("PIXEL_SIZE"); - TU_blendMap = 0; - TU_colorMap = 1; - AssignTextureUnit(Program, TexUnit(TU_blendMap, "blendMap"), TexUnit(TU_colorMap, "colorMap")); + + AssignSamplerNames(Program, 0, "blendMap", 1, "colorMap"); vao = createVAO(Program); } } @@ -1874,8 +1948,8 @@ namespace UIShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/texturedquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/texturedquad.frag").c_str()); AssignUniforms("center", "size", "texcenter", "texsize"); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); } UniformColoredTextureRectShader::UniformColoredTextureRectShader() @@ -1885,8 +1959,8 @@ namespace UIShader GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/uniformcolortexturedquad.frag").c_str()); AssignUniforms("center", "size", "texcenter", "texsize", "color"); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); } ColoredTextureRectShader::ColoredTextureRectShader() @@ -1895,8 +1969,8 @@ namespace UIShader GL_VERTEX_SHADER, file_manager->getAsset("shaders/colortexturedquad.vert").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/colortexturedquad.frag").c_str()); AssignUniforms("center", "size", "texcenter", "texsize"); - TU_tex = 0; - AssignTextureUnit(Program, TexUnit(TU_tex, "tex")); + + AssignSamplerNames(Program, 0, "tex"); glGenVertexArrays(1, &vao); glBindVertexArray(vao); diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index 606070ff4..b5c5adbe5 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -23,7 +23,8 @@ #include "config/user_config.hpp" #include "utils/singleton.hpp" -typedef unsigned int GLuint; +#include "gl_headers.hpp" + using namespace irr; class ParticleSystemProxy; @@ -51,14 +52,10 @@ public: }; } -void glUniformMatrix4fvWraper(GLuint, size_t, unsigned, const float *mat); -void glUniform3fWraper(GLuint, float, float, float); -void glUniform4iWraper(GLuint, int, int, int, int); -void glUniform2fWraper(GLuint a, float b, float c); -void glUniform1fWrapper(GLuint, float); -void glUniform1iWrapper(GLuint, int); bool needsUBO(); +unsigned getGLSLVersion(); + struct UniformHelper { template<unsigned N = 0> @@ -69,31 +66,28 @@ struct UniformHelper template<unsigned N = 0, typename... Args> static void setUniformsHelper(const std::vector<GLuint> &uniforms, const core::matrix4 &mat, Args... arg) { -#ifndef GL_FALSE -#define GL_FALSE 0 -#endif - glUniformMatrix4fvWraper(uniforms[N], 1, GL_FALSE, mat.pointer()); + glUniformMatrix4fv(uniforms[N], 1, GL_FALSE, mat.pointer()); setUniformsHelper<N + 1>(uniforms, arg...); } template<unsigned N = 0, typename... Args> static void setUniformsHelper(const std::vector<GLuint> &uniforms, const video::SColorf &col, Args... arg) { - glUniform3fWraper(uniforms[N], col.r, col.g, col.b); + glUniform3f(uniforms[N], col.r, col.g, col.b); setUniformsHelper<N + 1>(uniforms, arg...); } template<unsigned N = 0, typename... Args> static void setUniformsHelper(const std::vector<GLuint> &uniforms, const video::SColor &col, Args... arg) { - glUniform4iWraper(uniforms[N], col.getRed(), col.getGreen(), col.getBlue(), col.getAlpha()); + glUniform4i(uniforms[N], col.getRed(), col.getGreen(), col.getBlue(), col.getAlpha()); setUniformsHelper<N + 1>(uniforms, arg...); } template<unsigned N = 0, typename... Args> static void setUniformsHelper(const std::vector<GLuint> &uniforms, const core::vector3df &v, Args... arg) { - glUniform3fWraper(uniforms[N], v.X, v.Y, v.Z); + glUniform3f(uniforms[N], v.X, v.Y, v.Z); setUniformsHelper<N + 1>(uniforms, arg...); } @@ -101,35 +95,43 @@ struct UniformHelper template<unsigned N = 0, typename... Args> static void setUniformsHelper(const std::vector<GLuint> &uniforms, const core::vector2df &v, Args... arg) { - glUniform2fWraper(uniforms[N], v.X, v.Y); + glUniform2f(uniforms[N], v.X, v.Y); setUniformsHelper<N + 1>(uniforms, arg...); } template<unsigned N = 0, typename... Args> static void setUniformsHelper(const std::vector<GLuint> &uniforms, const core::dimension2df &v, Args... arg) { - glUniform2fWraper(uniforms[N], v.Width, v.Height); + glUniform2f(uniforms[N], v.Width, v.Height); setUniformsHelper<N + 1>(uniforms, arg...); } template<unsigned N = 0, typename... Args> static void setUniformsHelper(const std::vector<GLuint> &uniforms, float f, Args... arg) { - glUniform1fWrapper(uniforms[N], f); + glUniform1f(uniforms[N], f); setUniformsHelper<N + 1>(uniforms, arg...); } template<unsigned N = 0, typename... Args> static void setUniformsHelper(const std::vector<GLuint> &uniforms, int f, Args... arg) { - glUniform1iWrapper(uniforms[N], f); + glUniform1i(uniforms[N], f); + setUniformsHelper<N + 1>(uniforms, arg...); + } + + template<unsigned N = 0, typename... Args> + static void setUniformsHelper(const std::vector<GLuint> &uniforms, const std::vector<float> &v, Args... arg) + { + glUniform1fv(uniforms[N], v.size(), v.data()); setUniformsHelper<N + 1>(uniforms, arg...); } }; void bypassUBO(GLuint Program); -GLuint getUniformLocation(GLuint program, const char* name); + +extern std::vector<void(*)()> CleanTable; template<typename T, typename... Args> class ShaderHelperSingleton : public Singleton<T> @@ -144,7 +146,7 @@ protected: template<typename... U> void AssignUniforms_impl(const char* name, U... rest) { - uniforms.push_back(getUniformLocation(Program, name)); + uniforms.push_back(glGetUniformLocation(Program, name)); AssignUniforms_impl(rest...); } @@ -158,6 +160,16 @@ protected: public: GLuint Program; + ShaderHelperSingleton() + { + CleanTable.push_back(this->kill); + } + + ~ShaderHelperSingleton() + { + glDeleteProgram(Program); + } + void setUniforms(const Args & ... args) const { if (needsUBO()) @@ -166,146 +178,429 @@ public: } }; +enum SamplerType { + Trilinear_Anisotropic_Filtered, + Semi_trilinear, + Bilinear_Filtered, + Bilinear_Clamped_Filtered, + Nearest_Filtered, + Shadow_Sampler, + Volume_Linear_Filtered, + Trilinear_cubemap, +}; + +void setTextureSampler(GLenum, GLuint, GLuint, GLuint); + +template<SamplerType...tp> +struct CreateSamplers; + +template<SamplerType...tp> +struct BindTexture; + +template<> +struct CreateSamplers<> +{ + static void exec(std::vector<unsigned> &, std::vector<GLenum> &e) + {} +}; + +template<> +struct BindTexture<> +{ + static void exec(const std::vector<unsigned> &TU, const std::vector<unsigned> &TexId, unsigned N) + {} +}; + +GLuint createNearestSampler(); + +template<SamplerType...tp> +struct CreateSamplers<Nearest_Filtered, tp...> +{ + static void exec(std::vector<unsigned> &v, std::vector<GLenum> &e) + { + v.push_back(createNearestSampler()); + e.push_back(GL_TEXTURE_2D); + CreateSamplers<tp...>::exec(v, e); + } +}; + +void BindTextureNearest(unsigned TU, unsigned tid); + +template<SamplerType...tp> +struct BindTexture<Nearest_Filtered, tp...> +{ + static void exec(const std::vector<unsigned> &TU, const std::vector<unsigned> &TexId, unsigned N) + { + BindTextureNearest(TU[N], TexId[N]); + BindTexture<tp...>::exec(TU, TexId, N + 1); + } +}; + +GLuint createBilinearSampler(); + +template<SamplerType...tp> +struct CreateSamplers<Bilinear_Filtered, tp...> +{ + static void exec(std::vector<unsigned> &v, std::vector<GLenum> &e) + { + v.push_back(createBilinearSampler()); + e.push_back(GL_TEXTURE_2D); + CreateSamplers<tp...>::exec(v, e); + } +}; + +void BindTextureBilinear(unsigned TU, unsigned tex); + +template<SamplerType...tp> +struct BindTexture<Bilinear_Filtered, tp...> +{ + static void exec(const std::vector<unsigned> &TU, const std::vector<unsigned> &TexId, unsigned N) + { + BindTextureBilinear(TU[N], TexId[N]); + BindTexture<tp...>::exec(TU, TexId, N + 1); + } +}; + +GLuint createBilinearClampedSampler(); + +template<SamplerType...tp> +struct CreateSamplers<Bilinear_Clamped_Filtered, tp...> +{ + static void exec(std::vector<unsigned> &v, std::vector<GLenum> &e) + { + v.push_back(createBilinearClampedSampler()); + e.push_back(GL_TEXTURE_2D); + CreateSamplers<tp...>::exec(v, e); + } +}; + +void BindTextureBilinearClamped(unsigned TU, unsigned tex); + +template<SamplerType...tp> +struct BindTexture<Bilinear_Clamped_Filtered, tp...> +{ + static void exec(const std::vector<unsigned> &TU, const std::vector<unsigned> &TexId, unsigned N) + { + BindTextureBilinearClamped(TU[N], TexId[N]); + BindTexture<tp...>::exec(TU, TexId, N + 1); + } +}; + +GLuint createSemiTrilinearSampler(); + +template<SamplerType...tp> +struct CreateSamplers<Semi_trilinear, tp...> +{ + static void exec(std::vector<unsigned> &v, std::vector<GLenum> &e) + { + v.push_back(createSemiTrilinearSampler()); + e.push_back(GL_TEXTURE_2D); + CreateSamplers<tp...>::exec(v, e); + } +}; + +void BindTextureSemiTrilinear(unsigned TU, unsigned tex); + +template<SamplerType...tp> +struct BindTexture<Semi_trilinear, tp...> +{ + static void exec(const std::vector<unsigned> &TU, const std::vector<unsigned> &TexId, unsigned N) + { + BindTextureSemiTrilinear(TU[N], TexId[N]); + BindTexture<tp...>::exec(TU, TexId, N + 1); + } +}; + +GLuint createTrilinearSampler(); + +template<SamplerType...tp> +struct CreateSamplers<Trilinear_Anisotropic_Filtered, tp...> +{ + static void exec(std::vector<unsigned> &v, std::vector<GLenum> &e) + { + v.push_back(createTrilinearSampler()); + e.push_back(GL_TEXTURE_2D); + CreateSamplers<tp...>::exec(v, e); + } +}; + +void BindTextureTrilinearAnisotropic(unsigned TU, unsigned tex); + +template<SamplerType...tp> +struct CreateSamplers<Trilinear_cubemap, tp...> +{ + static void exec(std::vector<unsigned> &v, std::vector<GLenum> &e) + { + v.push_back(createTrilinearSampler()); + e.push_back(GL_TEXTURE_CUBE_MAP); + CreateSamplers<tp...>::exec(v, e); + } +}; + +void BindCubemapTrilinear(unsigned TU, unsigned tex); + +template<SamplerType...tp> +struct BindTexture<Trilinear_cubemap, tp...> +{ + static void exec(const std::vector<unsigned> &TU, const std::vector<unsigned> &TexId, unsigned N) + { + BindCubemapTrilinear(TU[N], TexId[N]); + BindTexture<tp...>::exec(TU, TexId, N + 1); + } +}; + +template<SamplerType...tp> +struct BindTexture<Trilinear_Anisotropic_Filtered, tp...> +{ + static void exec(const std::vector<unsigned> &TU, const std::vector<unsigned> &TexId, unsigned N) + { + BindTextureTrilinearAnisotropic(TU[N], TexId[N]); + BindTexture<tp...>::exec(TU, TexId, N + 1); + } +}; + +template<SamplerType...tp> +struct CreateSamplers<Volume_Linear_Filtered, tp...> +{ + static void exec(std::vector<unsigned> &v, std::vector<GLenum> &e) + { + v.push_back(createBilinearSampler()); + e.push_back(GL_TEXTURE_3D); + CreateSamplers<tp...>::exec(v, e); + } +}; + +void BindTextureVolume(unsigned TU, unsigned tex); + +template<SamplerType...tp> +struct BindTexture<Volume_Linear_Filtered, tp...> +{ + static void exec(const std::vector<unsigned> &TU, const std::vector<unsigned> &TexId, unsigned N) + { + BindTextureVolume(TU[N], TexId[N]); + BindTexture<tp...>::exec(TU, TexId, N + 1); + } +}; + +GLuint createShadowSampler(); + +template<SamplerType...tp> +struct CreateSamplers<Shadow_Sampler, tp...> +{ + static void exec(std::vector<unsigned> &v, std::vector<GLenum> &e) + { + v.push_back(createShadowSampler()); + e.push_back(GL_TEXTURE_2D_ARRAY); + CreateSamplers<tp...>::exec(v, e); + } +}; + +void BindTextureShadow(unsigned TU, unsigned tex); + +template<SamplerType...tp> +struct BindTexture<Shadow_Sampler, tp...> +{ + static void exec(const std::vector<unsigned> &TU, const std::vector<unsigned> &TexId, unsigned N) + { + BindTextureShadow(TU[N], TexId[N]); + BindTexture<tp...>::exec(TU, TexId, N + 1); + } +}; + +template<SamplerType...tp> +class TextureRead +{ +private: + template<unsigned N, typename...Args> + void AssignTextureNames_impl(GLuint) + { + static_assert(N == sizeof...(tp), "Wrong number of texture name"); + } + + template<unsigned N, typename...Args> + void AssignTextureNames_impl(GLuint Program, GLuint TexUnit, const char *name, Args...args) + { + GLuint location = glGetUniformLocation(Program, name); + TextureLocation.push_back(location); + glUniform1i(location, TexUnit); + TextureUnits.push_back(TexUnit); + AssignTextureNames_impl<N + 1>(Program, args...); + } + +protected: + std::vector<GLuint> TextureUnits; + std::vector<GLenum> TextureType; + std::vector<GLenum> TextureLocation; + template<typename...Args> + void AssignSamplerNames(GLuint Program, Args...args) + { + CreateSamplers<tp...>::exec(SamplersId, TextureType); + + glUseProgram(Program); + AssignTextureNames_impl<0>(Program, args...); + glUseProgram(0); + } + +public: + std::vector<GLuint> SamplersId; + void SetTextureUnits(const std::vector<GLuint> &args) + { + assert(args.size() == sizeof...(tp) && "Too much texture unit provided"); + if (getGLSLVersion() >= 330) + { + for (unsigned i = 0; i < args.size(); i++) + { + setTextureSampler(TextureType[i], TextureUnits[i], args[i], SamplersId[i]); + } + } + else + BindTexture<tp...>::exec(TextureUnits, args, 0); + } + + ~TextureRead() + { + for (unsigned i = 0; i < SamplersId.size(); i++) + glDeleteSamplers(1, &SamplersId[i]); + } + + void SetTextureHandles(const std::vector<uint64_t> &args) + { + assert(args.size() == TextureLocation.size() && "Wrong Handle count"); + for (unsigned i = 0; i < args.size(); i++) + { +#ifdef Bindless_Texture_Support + if (args[i]) + glUniformHandleui64ARB(TextureLocation[i], args[i]); +#endif + } + } +}; + namespace MeshShader { -class ObjectPass1Shader : public ShaderHelperSingleton<ObjectPass1Shader, core::matrix4, core::matrix4> +class ObjectPass1Shader : public ShaderHelperSingleton<ObjectPass1Shader, core::matrix4, core::matrix4>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; ObjectPass1Shader(); }; -class ObjectRefPass1Shader : public ShaderHelperSingleton<ObjectRefPass1Shader, core::matrix4, core::matrix4, core::matrix4> +class ObjectRefPass1Shader : public ShaderHelperSingleton<ObjectRefPass1Shader, core::matrix4, core::matrix4, core::matrix4>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; ObjectRefPass1Shader(); }; -class GrassPass1Shader : public ShaderHelperSingleton<GrassPass1Shader, core::matrix4, core::matrix4, core::vector3df> +class GrassPass1Shader : public ShaderHelperSingleton<GrassPass1Shader, core::matrix4, core::matrix4, core::vector3df>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; - GrassPass1Shader(); }; -class NormalMapShader : public ShaderHelperSingleton<NormalMapShader, core::matrix4, core::matrix4> +class NormalMapShader : public ShaderHelperSingleton<NormalMapShader, core::matrix4, core::matrix4>, public TextureRead<Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_normalmap, TU_glossy; NormalMapShader(); }; -class InstancedObjectPass1Shader : public ShaderHelperSingleton<InstancedObjectPass1Shader> +class InstancedObjectPass1Shader : public ShaderHelperSingleton<InstancedObjectPass1Shader>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; - InstancedObjectPass1Shader(); }; -class InstancedObjectRefPass1Shader : public ShaderHelperSingleton<InstancedObjectRefPass1Shader> +class InstancedObjectRefPass1Shader : public ShaderHelperSingleton<InstancedObjectRefPass1Shader>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; - InstancedObjectRefPass1Shader(); }; -class InstancedGrassPass1Shader : public ShaderHelperSingleton<InstancedGrassPass1Shader, core::vector3df> +class InstancedGrassPass1Shader : public ShaderHelperSingleton<InstancedGrassPass1Shader, core::vector3df>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; - InstancedGrassPass1Shader(); }; -class InstancedNormalMapShader : public ShaderHelperSingleton<InstancedNormalMapShader> +class InstancedNormalMapShader : public ShaderHelperSingleton<InstancedNormalMapShader>, public TextureRead<Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_glossy, TU_normalmap; - InstancedNormalMapShader(); }; -class ObjectPass2Shader : public ShaderHelperSingleton<ObjectPass2Shader, core::matrix4, core::matrix4> +class ObjectPass2Shader : public ShaderHelperSingleton<ObjectPass2Shader, core::matrix4, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_Albedo; - ObjectPass2Shader(); }; -class InstancedObjectPass2Shader : public ShaderHelperSingleton<InstancedObjectPass2Shader> +class InstancedObjectPass2Shader : public ShaderHelperSingleton<InstancedObjectPass2Shader>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_Albedo; - InstancedObjectPass2Shader(); }; -class InstancedObjectRefPass2Shader : public ShaderHelperSingleton<InstancedObjectRefPass2Shader> +class InstancedObjectRefPass2Shader : public ShaderHelperSingleton<InstancedObjectRefPass2Shader>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_Albedo; - InstancedObjectRefPass2Shader(); }; -class DetailledObjectPass2Shader : public ShaderHelperSingleton<DetailledObjectPass2Shader, core::matrix4> +class DetailledObjectPass2Shader : public ShaderHelperSingleton<DetailledObjectPass2Shader, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_Albedo, TU_detail; - DetailledObjectPass2Shader(); }; -class ObjectUnlitShader : public ShaderHelperSingleton<ObjectUnlitShader, core::matrix4> +class InstancedDetailledObjectPass2Shader : public ShaderHelperSingleton<InstancedDetailledObjectPass2Shader>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; + InstancedDetailledObjectPass2Shader(); +}; +class ObjectUnlitShader : public ShaderHelperSingleton<ObjectUnlitShader, core::matrix4, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered> +{ +public: ObjectUnlitShader(); }; -class ObjectRefPass2Shader : public ShaderHelperSingleton<ObjectRefPass2Shader, core::matrix4, core::matrix4> +class InstancedObjectUnlitShader : public ShaderHelperSingleton<InstancedObjectUnlitShader>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_Albedo; + InstancedObjectUnlitShader(); +}; +class ObjectRefPass2Shader : public ShaderHelperSingleton<ObjectRefPass2Shader, core::matrix4, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered> +{ +public: ObjectRefPass2Shader(); }; -class GrassPass2Shader : public ShaderHelperSingleton<GrassPass2Shader, core::matrix4, core::vector3df> +class GrassPass2Shader : public ShaderHelperSingleton<GrassPass2Shader, core::matrix4, core::vector3df>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_Albedo; - GrassPass2Shader(); }; -class InstancedGrassPass2Shader : public ShaderHelperSingleton<InstancedGrassPass2Shader, core::vector3df, core::vector3df> +class InstancedGrassPass2Shader : public ShaderHelperSingleton<InstancedGrassPass2Shader, core::vector3df, core::vector3df>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Nearest_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_Albedo, TU_dtex; - InstancedGrassPass2Shader(); }; -class SphereMapShader : public ShaderHelperSingleton<SphereMapShader, core::matrix4, core::matrix4> +class SphereMapShader : public ShaderHelperSingleton<SphereMapShader, core::matrix4, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; - SphereMapShader(); }; -class SplattingShader : public ShaderHelperSingleton<SplattingShader, core::matrix4> +class InstancedSphereMapShader : public ShaderHelperSingleton<InstancedSphereMapShader>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex_layout, TU_tex_detail0, TU_tex_detail1, TU_tex_detail2, TU_tex_detail3; + InstancedSphereMapShader(); +}; +class SplattingShader : public ShaderHelperSingleton<SplattingShader, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered> +{ +public: SplattingShader(); }; @@ -319,27 +614,21 @@ public: static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_tex, float time, float transparency); }; -class TransparentShader : public ShaderHelperSingleton<TransparentShader, core::matrix4, core::matrix4> +class TransparentShader : public ShaderHelperSingleton<TransparentShader, core::matrix4, core::matrix4>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; - TransparentShader(); }; -class TransparentFogShader : public ShaderHelperSingleton<TransparentFogShader, core::matrix4, core::matrix4, float, float, float, float, float, video::SColorf> +class TransparentFogShader : public ShaderHelperSingleton<TransparentFogShader, core::matrix4, core::matrix4, float, float, float, float, float, video::SColorf>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; - TransparentFogShader(); }; -class BillboardShader : public ShaderHelperSingleton<BillboardShader, core::matrix4, core::matrix4, core::vector3df, core::dimension2df> +class BillboardShader : public ShaderHelperSingleton<BillboardShader, core::matrix4, core::matrix4, core::vector3df, core::dimension2df>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; - BillboardShader(); }; @@ -350,59 +639,64 @@ public: ColorizeShader(); }; -class ShadowShader : public ShaderHelperSingleton<ShadowShader, core::matrix4> +class InstancedColorizeShader : public ShaderHelperSingleton<InstancedColorizeShader> +{ +public: + InstancedColorizeShader(); +}; + +class ShadowShader : public ShaderHelperSingleton<ShadowShader, int, core::matrix4>, public TextureRead<> { public: ShadowShader(); }; -class RSMShader : public ShaderHelperSingleton<RSMShader, core::matrix4, core::matrix4, core::matrix4> +class RSMShader : public ShaderHelperSingleton<RSMShader, core::matrix4, core::matrix4, core::matrix4>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; - RSMShader(); }; -class SplattingRSMShader : public ShaderHelperSingleton<SplattingRSMShader, core::matrix4, core::matrix4> +class InstancedRSMShader : public ShaderHelperSingleton<InstancedRSMShader, core::matrix4>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_layout, TU_detail0, TU_detail1, TU_detail2, TU_detail3; + InstancedRSMShader(); +}; +class SplattingRSMShader : public ShaderHelperSingleton<SplattingRSMShader, core::matrix4, core::matrix4>, + public TextureRead<Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered> +{ +public: SplattingRSMShader(); }; -class InstancedShadowShader : public ShaderHelperSingleton<InstancedShadowShader> +class InstancedShadowShader : public ShaderHelperSingleton<InstancedShadowShader, int>, public TextureRead<> { public: InstancedShadowShader(); }; -class RefShadowShader : public ShaderHelperSingleton<RefShadowShader, core::matrix4> +class RefShadowShader : public ShaderHelperSingleton<RefShadowShader, int, core::matrix4>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; RefShadowShader(); }; -class InstancedRefShadowShader : public ShaderHelperSingleton<InstancedRefShadowShader> +class InstancedRefShadowShader : public ShaderHelperSingleton<InstancedRefShadowShader, int>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; InstancedRefShadowShader(); }; -class GrassShadowShader : public ShaderHelperSingleton<GrassShadowShader, core::matrix4, core::vector3df> +class GrassShadowShader : public ShaderHelperSingleton<GrassShadowShader, int, core::matrix4, core::vector3df>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; GrassShadowShader(); }; -class InstancedGrassShadowShader : public ShaderHelperSingleton<InstancedGrassShadowShader, core::vector3df> +class InstancedGrassShadowShader : public ShaderHelperSingleton<InstancedGrassShadowShader, int, core::vector3df>, public TextureRead<Trilinear_Anisotropic_Filtered> { public: - GLuint TU_tex; InstancedGrassShadowShader(); }; @@ -412,24 +706,17 @@ public: DisplaceMaskShader(); }; -class DisplaceShader : public ShaderHelperSingleton<DisplaceShader, core::matrix4, core::vector2df, core::vector2df> +class DisplaceShader : public ShaderHelperSingleton<DisplaceShader, core::matrix4, core::vector2df, core::vector2df>, public TextureRead<Bilinear_Filtered, Bilinear_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered> { public: - GLuint TU_displacement_tex, TU_mask_tex, TU_color_tex, TU_tex; - DisplaceShader(); }; -class SkyboxShader +class SkyboxShader : public ShaderHelperSingleton<SkyboxShader, core::matrix4>, public TextureRead<Trilinear_cubemap> { public: - static GLuint Program; - static GLuint attrib_position; - static GLuint uniform_MM, uniform_tex; - static GLuint cubevao; - - static void init(); - static void setUniforms(const core::matrix4 &ModelMatrix, const core::vector2df &screen, unsigned TU_tex); + SkyboxShader(); + GLuint cubevao; }; class NormalVisualizer : public ShaderHelperSingleton<NormalVisualizer, core::matrix4, core::matrix4, video::SColor> @@ -469,17 +756,12 @@ namespace LightShader }; - class PointLightShader + class PointLightShader : public ShaderHelperSingleton<PointLightShader>, public TextureRead<Nearest_Filtered, Nearest_Filtered> { public: - static GLuint Program; - static GLuint attrib_Position, attrib_Energy, attrib_Color, attrib_Radius; - static GLuint uniform_ntex, uniform_dtex, uniform_spec; - static GLuint vbo; - static GLuint vao; - - static void init(); - static void setUniforms(const core::vector2df &screen, unsigned spec, unsigned TU_ntex, unsigned TU_dtex); + GLuint vbo; + GLuint vao; + PointLightShader(); }; } @@ -502,19 +784,15 @@ public: HeightmapSimulationShader(); }; -class SimpleParticleRender : public ShaderHelperSingleton<SimpleParticleRender, video::SColorf, video::SColorf> +class SimpleParticleRender : public ShaderHelperSingleton<SimpleParticleRender, video::SColorf, video::SColorf>, public TextureRead<Trilinear_Anisotropic_Filtered, Nearest_Filtered> { public: - GLuint TU_tex, TU_dtex; - SimpleParticleRender(); }; -class FlipParticleRender : public ShaderHelperSingleton<FlipParticleRender> +class FlipParticleRender : public ShaderHelperSingleton<FlipParticleRender>, public TextureRead<Trilinear_Anisotropic_Filtered, Nearest_Filtered> { public: - GLuint TU_tex, TU_dtex; - FlipParticleRender(); }; } @@ -522,78 +800,58 @@ public: namespace FullScreenShader { -class BloomShader : public ShaderHelperSingleton<BloomShader> +class BloomShader : public ShaderHelperSingleton<BloomShader>, public TextureRead<Nearest_Filtered> { public: - GLuint TU_tex; - BloomShader(); }; -class BloomBlendShader : public ShaderHelperSingleton<BloomBlendShader> +class BloomBlendShader : public ShaderHelperSingleton<BloomBlendShader>, public TextureRead<Bilinear_Filtered, Bilinear_Filtered, Bilinear_Filtered> { public: - GLuint TU_tex_128, TU_tex_256, TU_tex_512; - BloomBlendShader(); }; -class ToneMapShader : public ShaderHelperSingleton<ToneMapShader> +class ToneMapShader : public ShaderHelperSingleton<ToneMapShader>, public TextureRead<Nearest_Filtered> { public: - GLuint TU_tex; - ToneMapShader(); }; -class DepthOfFieldShader : public ShaderHelperSingleton<DepthOfFieldShader> +class DepthOfFieldShader : public ShaderHelperSingleton<DepthOfFieldShader>, public TextureRead<Bilinear_Filtered, Nearest_Filtered> { public: - GLuint TU_tex, TU_depth; - DepthOfFieldShader(); }; -class SunLightShader : public ShaderHelperSingleton<SunLightShader, core::vector3df, video::SColorf> +class SunLightShader : public ShaderHelperSingleton<SunLightShader, core::vector3df, video::SColorf>, public TextureRead<Nearest_Filtered, Nearest_Filtered> { public: - GLuint TU_ntex, TU_dtex; - SunLightShader(); }; -class DiffuseEnvMapShader +class DiffuseEnvMapShader : public ShaderHelperSingleton<DiffuseEnvMapShader, core::matrix4, std::vector<float>, std::vector<float>, std::vector<float> >, public TextureRead<Nearest_Filtered> { public: - static GLuint Program; - static GLuint uniform_ntex, uniform_TVM, uniform_blueLmn, uniform_greenLmn, uniform_redLmn; - - static void init(); - static void setUniforms(const core::matrix4 &TransposeViewMatrix, const float *blueSHCoeff, const float *greenSHCoeff, const float *redSHCoeff, unsigned TU_ntex); + DiffuseEnvMapShader(); }; -class ShadowedSunLightShader : public ShaderHelperSingleton<ShadowedSunLightShader, core::vector3df, video::SColorf> +class ShadowedSunLightShader : public ShaderHelperSingleton<ShadowedSunLightShader, core::vector3df, video::SColorf>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Shadow_Sampler> { public: - GLuint TU_ntex, TU_dtex, TU_shadowtex; - ShadowedSunLightShader(); }; -class RadianceHintsConstructionShader : public ShaderHelperSingleton<RadianceHintsConstructionShader, core::matrix4, core::matrix4, core::vector3df> +class RadianceHintsConstructionShader : public ShaderHelperSingleton<RadianceHintsConstructionShader, core::matrix4, core::matrix4, core::vector3df>, public TextureRead<Bilinear_Filtered, Bilinear_Filtered, Bilinear_Filtered> { public: - GLuint TU_ctex, TU_ntex, TU_dtex; - RadianceHintsConstructionShader(); }; // Workaround for a bug found in kepler nvidia linux and fermi nvidia windows -class NVWorkaroundRadianceHintsConstructionShader : public ShaderHelperSingleton<NVWorkaroundRadianceHintsConstructionShader, core::matrix4, core::matrix4, core::vector3df, int> +class NVWorkaroundRadianceHintsConstructionShader : public ShaderHelperSingleton<NVWorkaroundRadianceHintsConstructionShader, core::matrix4, core::matrix4, core::vector3df, int>, public TextureRead<Bilinear_Filtered, Bilinear_Filtered, Bilinear_Filtered> { public: - GLuint TU_ctex, TU_ntex, TU_dtex; - NVWorkaroundRadianceHintsConstructionShader(); }; @@ -605,19 +863,16 @@ public: RHDebug(); }; -class GlobalIlluminationReconstructionShader : public ShaderHelperSingleton<GlobalIlluminationReconstructionShader, core::matrix4, core::matrix4, core::vector3df> +class GlobalIlluminationReconstructionShader : public ShaderHelperSingleton<GlobalIlluminationReconstructionShader, core::matrix4, core::matrix4, core::vector3df>, + public TextureRead<Nearest_Filtered, Nearest_Filtered, Volume_Linear_Filtered, Volume_Linear_Filtered, Volume_Linear_Filtered> { public: - GLuint TU_ntex, TU_dtex, TU_SHR, TU_SHG, TU_SHB, uniform_RHMatrix; - GlobalIlluminationReconstructionShader(); }; -class Gaussian17TapHShader : public ShaderHelperSingleton<Gaussian17TapHShader, core::vector2df> +class Gaussian17TapHShader : public ShaderHelperSingleton<Gaussian17TapHShader, core::vector2df>, public TextureRead<Bilinear_Clamped_Filtered, Bilinear_Clamped_Filtered> { public: - GLuint TU_tex, TU_depth; - Gaussian17TapHShader(); }; @@ -628,27 +883,21 @@ public: ComputeGaussian17TapHShader(); }; -class Gaussian6HBlurShader : public ShaderHelperSingleton<Gaussian6HBlurShader, core::vector2df> +class Gaussian6HBlurShader : public ShaderHelperSingleton<Gaussian6HBlurShader, core::vector2df>, public TextureRead<Bilinear_Clamped_Filtered> { public: - GLuint TU_tex; - Gaussian6HBlurShader(); }; -class Gaussian3HBlurShader : public ShaderHelperSingleton<Gaussian3HBlurShader, core::vector2df> +class Gaussian3HBlurShader : public ShaderHelperSingleton<Gaussian3HBlurShader, core::vector2df>, public TextureRead<Bilinear_Clamped_Filtered> { public: - GLuint TU_tex; - Gaussian3HBlurShader(); }; -class Gaussian17TapVShader : public ShaderHelperSingleton<Gaussian17TapVShader, core::vector2df> +class Gaussian17TapVShader : public ShaderHelperSingleton<Gaussian17TapVShader, core::vector2df>, public TextureRead<Bilinear_Clamped_Filtered, Bilinear_Clamped_Filtered> { public: - GLuint TU_tex, TU_depth; - Gaussian17TapVShader(); }; @@ -661,26 +910,21 @@ public: }; -class Gaussian6VBlurShader : public ShaderHelperSingleton<Gaussian6VBlurShader, core::vector2df> +class Gaussian6VBlurShader : public ShaderHelperSingleton<Gaussian6VBlurShader, core::vector2df>, public TextureRead<Bilinear_Clamped_Filtered> { public: - GLuint TU_tex; - Gaussian6VBlurShader(); }; -class Gaussian3VBlurShader : public ShaderHelperSingleton<Gaussian3VBlurShader, core::vector2df> +class Gaussian3VBlurShader : public ShaderHelperSingleton<Gaussian3VBlurShader, core::vector2df>, public TextureRead<Bilinear_Clamped_Filtered> { public: - GLuint TU_tex; - Gaussian3VBlurShader(); }; -class PassThroughShader : public ShaderHelperSingleton<PassThroughShader> +class PassThroughShader : public ShaderHelperSingleton<PassThroughShader>, public TextureRead<Bilinear_Filtered> { public: - GLuint TU_tex; GLuint vao; PassThroughShader(); @@ -695,87 +939,73 @@ public: LayerPassThroughShader(); }; -class LinearizeDepthShader : public ShaderHelperSingleton<LinearizeDepthShader, float, float> +class LinearizeDepthShader : public ShaderHelperSingleton<LinearizeDepthShader, float, float>, public TextureRead<Bilinear_Filtered> { public: - GLuint TU_tex; - LinearizeDepthShader(); }; -class GlowShader : public ShaderHelperSingleton<GlowShader> +class GlowShader : public ShaderHelperSingleton<GlowShader>, public TextureRead<Bilinear_Filtered> { public: - GLuint TU_tex; GLuint vao; GlowShader(); }; -class SSAOShader : public ShaderHelperSingleton<SSAOShader, float, float, float> +class SSAOShader : public ShaderHelperSingleton<SSAOShader, float, float, float>, public TextureRead<Semi_trilinear> { public: - GLuint TU_dtex; - SSAOShader(); }; -class FogShader : public ShaderHelperSingleton<FogShader, float, float, float, float, float, core::vector3df> +class FogShader : public ShaderHelperSingleton<FogShader, float, float, float, float, float, core::vector3df>, public TextureRead<Nearest_Filtered> { public: - GLuint TU_tex; - FogShader(); }; -class MotionBlurShader : public ShaderHelperSingleton<MotionBlurShader, core::matrix4, core::vector2df, float, float> +class MotionBlurShader : public ShaderHelperSingleton<MotionBlurShader, core::matrix4, core::vector2df, float, float>, public TextureRead<Bilinear_Clamped_Filtered, Nearest_Filtered> { public: - GLuint TU_cb, TU_dtex; - MotionBlurShader(); }; -class GodFadeShader : public ShaderHelperSingleton<GodFadeShader, video::SColorf> +class GodFadeShader : public ShaderHelperSingleton<GodFadeShader, video::SColorf>, public TextureRead<Bilinear_Filtered> { public: - GLuint TU_tex; GLuint vao; GodFadeShader(); }; -class GodRayShader : public ShaderHelperSingleton<GodRayShader, core::vector2df> +class GodRayShader : public ShaderHelperSingleton<GodRayShader, core::vector2df>, public TextureRead<Bilinear_Filtered> { public: - GLuint TU_tex; GLuint vao; GodRayShader(); }; -class MLAAColorEdgeDetectionSHader : public ShaderHelperSingleton<MLAAColorEdgeDetectionSHader, core::vector2df> +class MLAAColorEdgeDetectionSHader : public ShaderHelperSingleton<MLAAColorEdgeDetectionSHader, core::vector2df>, public TextureRead<Nearest_Filtered> { public: - GLuint TU_colorMapG; GLuint vao; MLAAColorEdgeDetectionSHader(); }; -class MLAABlendWeightSHader : public ShaderHelperSingleton<MLAABlendWeightSHader, core::vector2df> +class MLAABlendWeightSHader : public ShaderHelperSingleton<MLAABlendWeightSHader, core::vector2df>, public TextureRead<Bilinear_Filtered, Nearest_Filtered> { public: - GLuint TU_edgesMap, TU_areaMap; GLuint vao; MLAABlendWeightSHader(); }; -class MLAAGatherSHader : public ShaderHelperSingleton<MLAAGatherSHader, core::vector2df> +class MLAAGatherSHader : public ShaderHelperSingleton<MLAAGatherSHader, core::vector2df>, public TextureRead<Nearest_Filtered, Nearest_Filtered> { public: - GLuint TU_colorMap, TU_blendMap; GLuint vao; MLAAGatherSHader(); @@ -785,26 +1015,21 @@ public: namespace UIShader { -class TextureRectShader : public ShaderHelperSingleton<TextureRectShader, core::vector2df, core::vector2df, core::vector2df, core::vector2df> +class TextureRectShader : public ShaderHelperSingleton<TextureRectShader, core::vector2df, core::vector2df, core::vector2df, core::vector2df>, public TextureRead<Bilinear_Filtered> { public: - GLuint TU_tex; - TextureRectShader(); }; -class UniformColoredTextureRectShader : public ShaderHelperSingleton<UniformColoredTextureRectShader, core::vector2df, core::vector2df, core::vector2df, core::vector2df, video::SColor> +class UniformColoredTextureRectShader : public ShaderHelperSingleton<UniformColoredTextureRectShader, core::vector2df, core::vector2df, core::vector2df, core::vector2df, video::SColor>, public TextureRead<Bilinear_Filtered> { public: - GLuint TU_tex; - UniformColoredTextureRectShader(); }; -class ColoredTextureRectShader : public ShaderHelperSingleton<ColoredTextureRectShader, core::vector2df, core::vector2df, core::vector2df, core::vector2df> +class ColoredTextureRectShader : public ShaderHelperSingleton<ColoredTextureRectShader, core::vector2df, core::vector2df, core::vector2df, core::vector2df>, public TextureRead<Bilinear_Filtered> { public: - GLuint TU_tex; GLuint colorvbo; GLuint vao; @@ -869,6 +1094,7 @@ public: video::IShaderConstantSetCallBack * m_callbacks[ES_COUNT]; void loadShaders(); + void killShaders(); private: void check(const int num) const; diff --git a/src/graphics/shadow.cpp b/src/graphics/shadow.cpp index e092f8284..619a552fa 100644 --- a/src/graphics/shadow.cpp +++ b/src/graphics/shadow.cpp @@ -23,7 +23,9 @@ #include <IMeshSceneNode.h> #include <ISceneNode.h> -Shadow::Shadow(video::ITexture *texture, scene::ISceneNode *node, float scale = 1.0, float xOffset = 0.0, float yOffset = 0.0) +Shadow::Shadow(video::ITexture *texture, scene::ISceneNode *node, + float scale = 1.0, float x_offset = 0.0, float y_offset = 0.0, + float z_offset = 0.0) { video::SMaterial m; m.setTexture(0, texture); @@ -33,10 +35,10 @@ Shadow::Shadow(video::ITexture *texture, scene::ISceneNode *node, float scale = m_mesh = irr_driver->createQuadMesh(&m, /*create_one_quad*/true); scene::IMeshBuffer *buffer = m_mesh->getMeshBuffer(0); irr::video::S3DVertex* v=(video::S3DVertex*)buffer->getVertices(); - v[0].Pos.X = -scale+xOffset; v[0].Pos.Z = scale+yOffset; v[0].Pos.Y = 0.01f; - v[1].Pos.X = scale+xOffset; v[1].Pos.Z = scale+yOffset; v[1].Pos.Y = 0.01f; - v[2].Pos.X = scale+xOffset; v[2].Pos.Z = -scale+yOffset; v[2].Pos.Y = 0.01f; - v[3].Pos.X = -scale+xOffset; v[3].Pos.Z = -scale+yOffset; v[3].Pos.Y = 0.01f; + v[0].Pos.X = -scale+x_offset; v[0].Pos.Z = scale+z_offset; v[0].Pos.Y = 0.01f-y_offset; + v[1].Pos.X = scale+x_offset; v[1].Pos.Z = scale+z_offset; v[1].Pos.Y = 0.01f-y_offset; + v[2].Pos.X = scale+x_offset; v[2].Pos.Z = -scale+z_offset; v[2].Pos.Y = 0.01f-y_offset; + v[3].Pos.X = -scale+x_offset; v[3].Pos.Z = -scale+z_offset; v[3].Pos.Y = 0.01f-y_offset; v[0].TCoords = core::vector2df(0,0); v[1].TCoords = core::vector2df(1,0); v[2].TCoords = core::vector2df(1,1); diff --git a/src/graphics/shadow.hpp b/src/graphics/shadow.hpp index d55977bde..e234e716b 100644 --- a/src/graphics/shadow.hpp +++ b/src/graphics/shadow.hpp @@ -46,9 +46,8 @@ private: /** The scene node of the kart to which this shadow belongs. */ scene::ISceneNode *m_parent_kart_node; public: - Shadow(video::ITexture *texture, - scene::ISceneNode *node, - float scale, float xOffset, float yOffset); + Shadow(video::ITexture *texture, scene::ISceneNode *node, + float scale, float x_offset, float y_offset,float z_offset); ~Shadow(); void enableShadow(); void disableShadow(); diff --git a/src/graphics/stk_text_billboard.cpp b/src/graphics/stk_text_billboard.cpp index 1365d0ee6..c3e4e54ad 100644 --- a/src/graphics/stk_text_billboard.cpp +++ b/src/graphics/stk_text_billboard.cpp @@ -75,12 +75,12 @@ scene::IMesh* STKTextBillboard::getTextMesh(core::stringw text, gui::ScalableFon for (unsigned int i = 0; i < m_chars.size(); i++) { - core::vector3df char_pos(m_chars[i].m_destRect.UpperLeftCorner.X, - m_chars[i].m_destRect.UpperLeftCorner.Y, 0); + core::vector3df char_pos((float) m_chars[i].m_destRect.UpperLeftCorner.X, + (float) m_chars[i].m_destRect.UpperLeftCorner.Y, 0); char_pos *= scale; - core::vector3df char_pos2(m_chars[i].m_destRect.LowerRightCorner.X, - m_chars[i].m_destRect.LowerRightCorner.Y, 0); + core::vector3df char_pos2((float)m_chars[i].m_destRect.LowerRightCorner.X, + (float) m_chars[i].m_destRect.LowerRightCorner.Y, 0); char_pos2 *= scale; core::dimension2di char_size_i = m_chars[i].m_destRect.getSize(); @@ -100,8 +100,8 @@ scene::IMesh* STKTextBillboard::getTextMesh(core::stringw text, gui::ScalableFon buffer = map_itr->second; } - float tex_width = m_chars[i].m_texture->getSize().Width; - float tex_height = m_chars[i].m_texture->getSize().Height; + float tex_width = (float) m_chars[i].m_texture->getSize().Width; + float tex_height = (float)m_chars[i].m_texture->getSize().Height; video::S3DVertex vertices[] = diff --git a/src/graphics/stkanimatedmesh.cpp b/src/graphics/stkanimatedmesh.cpp index 3c4aacc04..95b0f0561 100644 --- a/src/graphics/stkanimatedmesh.cpp +++ b/src/graphics/stkanimatedmesh.cpp @@ -33,6 +33,15 @@ void STKAnimatedMesh::cleanGLMeshes() glDeleteVertexArrays(1, &(mesh.vao)); glDeleteBuffers(1, &(mesh.vertex_buffer)); glDeleteBuffers(1, &(mesh.index_buffer)); + if (mesh.instance_buffer) + glDeleteBuffers(1, &(mesh.instance_buffer)); +#ifdef Bindless_Texture_Support + for (unsigned j = 0; j < 6; j++) + { + if (mesh.TextureHandles[j] && glIsTextureHandleResidentARB(mesh.TextureHandles[j])) + glMakeTextureHandleNonResidentARB(mesh.TextureHandles[j]); + } +#endif } } @@ -45,21 +54,13 @@ void STKAnimatedMesh::setMesh(scene::IAnimatedMesh* mesh) CAnimatedMeshSceneNode::setMesh(mesh); } -void STKAnimatedMesh::render() +void STKAnimatedMesh::update() { video::IVideoDriver* driver = SceneManager->getVideoDriver(); - - bool isTransparentPass = - SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT; - - ++PassCount; - scene::IMesh* m = getMeshForCurrentFrame(); if (m) - { Box = m->getBoundingBox(); - } else { Log::error("animated mesh", "Animated Mesh returned no mesh to render."); @@ -99,11 +100,21 @@ void STKAnimatedMesh::render() { MeshMaterial MatType = MaterialTypeToMeshMaterial(type, mb->getVertexType()); MeshSolidMaterial[MatType].push_back(&mesh); + InitTextures(mesh, MatType); + } + + if (irr_driver->hasARB_base_instance()) + { + std::pair<unsigned, unsigned> p = VAOManager::getInstance()->getBase(mb); + mesh.vaoBaseVertex = p.first; + mesh.vaoOffset = p.second; + } + else + { + fillLocalBuffer(mesh, mb); + mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, mb->getVertexType()); + glBindVertexArray(0); } - std::pair<unsigned, unsigned> p = getVAOOffsetAndBase(mb); - mesh.vaoBaseVertex = p.first; - mesh.vaoOffset = p.second; - mesh.VAOType = mb->getVertexType(); } } firstTime = false; @@ -114,31 +125,47 @@ void STKAnimatedMesh::render() const video::SMaterial& material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i]; if (isObject(material.MaterialType)) { - if (irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS || irr_driver->getPhase() == TRANSPARENT_PASS) + + size_t size = mb->getVertexCount() * GLmeshes[i].Stride, offset = GLmeshes[i].vaoBaseVertex * GLmeshes[i].Stride; + void *buf; + if (irr_driver->hasBufferStorageExtension()) + { + buf = VAOManager::getInstance()->getVBOPtr(mb->getVertexType()); + buf = (char *)buf + offset; + } + else { glBindVertexArray(0); - size_t size = mb->getVertexCount() * GLmeshes[i].Stride; - glBindBuffer(GL_ARRAY_BUFFER, getVBO(mb->getVertexType())); + if (irr_driver->hasARB_base_instance()) + glBindBuffer(GL_ARRAY_BUFFER, VAOManager::getInstance()->getVBO(mb->getVertexType())); + else + glBindBuffer(GL_ARRAY_BUFFER, GLmeshes[i].vertex_buffer); GLbitfield bitfield = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT; - void * buf = glMapBufferRange(GL_ARRAY_BUFFER, GLmeshes[i].vaoBaseVertex * GLmeshes[i].Stride, size, bitfield); - memcpy(buf, mb->getVertices(), size); + buf = glMapBufferRange(GL_ARRAY_BUFFER, offset, size, bitfield); + } + memcpy(buf, mb->getVertices(), size); + if (!irr_driver->hasBufferStorageExtension()) + { glUnmapBuffer(GL_ARRAY_BUFFER); glBindBuffer(GL_ARRAY_BUFFER, 0); } } if (mb) GLmeshes[i].TextureMatrix = getMaterial(i).getTextureMatrix(0); - - video::IMaterialRenderer* rnd = driver->getMaterialRenderer(Materials[i].MaterialType); - bool transparent = (rnd && rnd->isTransparent()); - - // only render transparent buffer if this is the transparent render pass - // and solid only in solid pass - if (transparent != isTransparentPass) - continue; } - if (irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS || irr_driver->getPhase() == SHADOW_PASS) +} + +void STKAnimatedMesh::render() +{ + bool isTransparentPass = + SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT; + + ++PassCount; + + update(); + +/* if (irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS || irr_driver->getPhase() == SHADOW_PASS) { ModelViewProjectionMatrix = computeMVP(AbsoluteTransformation); core::matrix4 invmodel; @@ -158,7 +185,7 @@ void STKAnimatedMesh::render() pushVector(ListMatUnlit::getInstance(), mesh, AbsoluteTransformation, core::matrix4::EM4CONST_IDENTITY, mesh->TextureMatrix); return; - } + }*/ if (irr_driver->getPhase() == TRANSPARENT_PASS) { diff --git a/src/graphics/stkanimatedmesh.hpp b/src/graphics/stkanimatedmesh.hpp index c5c113da0..bfcd3f571 100644 --- a/src/graphics/stkanimatedmesh.hpp +++ b/src/graphics/stkanimatedmesh.hpp @@ -7,16 +7,15 @@ #include "graphics/stkmesh.hpp" #include "utils/ptr_vector.hpp" -class STKAnimatedMesh : public irr::scene::CAnimatedMeshSceneNode +class STKAnimatedMesh : public irr::scene::CAnimatedMeshSceneNode, public STKMeshCommon { protected: bool firstTime; - PtrVector<GLMesh, REF> MeshSolidMaterial[MAT_COUNT]; - PtrVector<GLMesh, REF> TransparentMesh[TM_COUNT]; std::vector<GLMesh> GLmeshes; core::matrix4 ModelViewProjectionMatrix; void cleanGLMeshes(); public: + virtual void update(); STKAnimatedMesh(irr::scene::IAnimatedMesh* mesh, irr::scene::ISceneNode* parent, irr::scene::ISceneManager* mgr, irr::s32 id, const irr::core::vector3df& position = irr::core::vector3df(0,0,0), @@ -25,6 +24,7 @@ public: virtual void render(); virtual void setMesh(irr::scene::IAnimatedMesh* mesh); + virtual bool glow() const { return false; } }; #endif // STKANIMATEDMESH_HPP diff --git a/src/graphics/stkbillboard.cpp b/src/graphics/stkbillboard.cpp index d2713f032..913727ec1 100644 --- a/src/graphics/stkbillboard.cpp +++ b/src/graphics/stkbillboard.cpp @@ -47,10 +47,12 @@ void STKBillboard::render() core::vector3df pos = getAbsolutePosition(); glBindVertexArray(billboardvao); video::ITexture *tex = Material.getTexture(0); + if (tex == NULL) + return; compressTexture(tex, true, true); GLuint texid = getTextureGLuint(tex); - setTexture(0, texid, GL_LINEAR, GL_LINEAR); glUseProgram(MeshShader::BillboardShader::getInstance()->Program); + MeshShader::BillboardShader::getInstance()->SetTextureUnits(createVector<GLuint>(texid)); MeshShader::BillboardShader::getInstance()->setUniforms(irr_driver->getViewMatrix(), irr_driver->getProjMatrix(), pos, Size); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindVertexArray(0); diff --git a/src/graphics/stkinstancedscenenode.cpp b/src/graphics/stkinstancedscenenode.cpp deleted file mode 100644 index 64c28206f..000000000 --- a/src/graphics/stkinstancedscenenode.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include "stkinstancedscenenode.hpp" -#include "graphics/irr_driver.hpp" -#include "graphics/callbacks.hpp" - -STKInstancedSceneNode::STKInstancedSceneNode(irr::scene::IMesh* mesh, ISceneNode* parent, irr::scene::ISceneManager* mgr, irr::s32 id, - const irr::core::vector3df& position, - const irr::core::vector3df& rotation, - const irr::core::vector3df& scale) : - CMeshSceneNode(mesh, parent, mgr, id, position, rotation, scale) -{ - m_ref_count = 0; - irr_driver->grabAllTextures(mesh); - - if (irr_driver->isGLSL()) - { - createGLMeshes(); - setAutomaticCulling(0); - } -} - -void STKInstancedSceneNode::cleanGL() -{ - for (u32 i = 0; i < GLmeshes.size(); ++i) - { - GLMesh mesh = GLmeshes[i]; - if (!mesh.vertex_buffer) - continue; - if (mesh.vao) - glDeleteVertexArrays(1, &(mesh.vao)); - if (mesh.vao_shadow_pass) - glDeleteVertexArrays(1, &(mesh.vao_shadow_pass)); - glDeleteBuffers(1, &(mesh.vertex_buffer)); - glDeleteBuffers(1, &(mesh.index_buffer)); - } - glDeleteBuffers(1, &instances_vbo); -} - -STKInstancedSceneNode::~STKInstancedSceneNode() -{ - irr_driver->dropAllTextures(getMesh()); - irr_driver->removeMeshFromCache(getMesh()); - - if (irr_driver->isGLSL()) - cleanGL(); -} - -void STKInstancedSceneNode::createGLMeshes() -{ - for (u32 i = 0; i<Mesh->getMeshBufferCount(); ++i) - { - scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); - GLmeshes.push_back(allocateMeshBuffer(mb)); - fillLocalBuffer(GLmeshes.back(), mb); - } - isMaterialInitialized = false; -} - -void STKInstancedSceneNode::initinstancedvaostate(GLMesh &mesh) -{ - mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, getVTXTYPEFromStride(mesh.Stride)); - glGenBuffers(1, &instances_vbo); - glBindBuffer(GL_ARRAY_BUFFER, instances_vbo); - glBufferData(GL_ARRAY_BUFFER, instance_pos.size() * sizeof(float), instance_pos.data(), GL_STATIC_DRAW); - - glEnableVertexAttribArray(7); - glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 0); - glVertexAttribDivisor(7, 1); - glEnableVertexAttribArray(8); - glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), (GLvoid*)(3 * sizeof(float))); - glVertexAttribDivisor(8, 1); - glEnableVertexAttribArray(9); - glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), (GLvoid*)(6 * sizeof(float))); - glVertexAttribDivisor(9, 1); - - mesh.vao_shadow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, getVTXTYPEFromStride(mesh.Stride)); - glBindBuffer(GL_ARRAY_BUFFER, instances_vbo); - glEnableVertexAttribArray(7); - glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), 0); - glVertexAttribDivisor(7, 4); - glEnableVertexAttribArray(8); - glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), (GLvoid*)(3 * sizeof(float))); - glVertexAttribDivisor(8, 4); - glEnableVertexAttribArray(9); - glVertexAttribPointer(9, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), (GLvoid*)(6 * sizeof(float))); - glVertexAttribDivisor(9, 4); - - glBindVertexArray(0); -} - -void STKInstancedSceneNode::setFirstTimeMaterial() -{ - if (isMaterialInitialized) - return; - for (u32 i = 0; i<Mesh->getMeshBufferCount(); ++i) - { - scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); - if (!mb) - continue; - video::E_MATERIAL_TYPE type = mb->getMaterial().MaterialType; - - GLMesh &mesh = GLmeshes[i]; - MeshMaterial MatType = MaterialTypeToMeshMaterial(type, mb->getVertexType()); - initinstancedvaostate(mesh); - MeshSolidMaterial[MatType].push_back(&mesh); - } - isMaterialInitialized = true; -} - -void STKInstancedSceneNode::addInstance(const core::vector3df &origin, const core::vector3df &orientation, const core::vector3df &scale) -{ - instance_pos.push_back(origin.X); - instance_pos.push_back(origin.Y); - instance_pos.push_back(origin.Z); - instance_pos.push_back(orientation.X); - instance_pos.push_back(orientation.Y); - instance_pos.push_back(orientation.Z); - instance_pos.push_back(scale.X); - instance_pos.push_back(scale.Y); - instance_pos.push_back(scale.Z); -} - -core::matrix4 STKInstancedSceneNode::getInstanceTransform(int id) -{ - core::matrix4 mat; - - int offset = id * 9; - mat.setTranslation(core::vector3df( - instance_pos[offset], - instance_pos[offset + 1], - instance_pos[offset + 2])); - mat.setRotationDegrees(core::vector3df( - instance_pos[offset + 3], - instance_pos[offset + 4], - instance_pos[offset + 5])); - mat.setScale(core::vector3df( - instance_pos[offset + 6], - instance_pos[offset + 7], - instance_pos[offset + 8])); - - return mat; -} - -void STKInstancedSceneNode::render() -{ - if (!irr_driver->isGLSL()) - { - CMeshSceneNode::render(); - return; - } - - setFirstTimeMaterial(); - - - for(unsigned i = 0; i < MeshSolidMaterial[MAT_DEFAULT].size(); i++) - { - GLMesh *mesh = MeshSolidMaterial[MAT_DEFAULT][i]; - ListInstancedMatDefault::getInstance()->push_back(STK::make_tuple(mesh, instance_pos.size() / 9)); - } - - for(unsigned i = 0; i < MeshSolidMaterial[MAT_ALPHA_REF].size(); i++) - { - GLMesh *mesh = MeshSolidMaterial[MAT_ALPHA_REF][i]; - ListInstancedMatAlphaRef::getInstance()->push_back(STK::make_tuple(mesh, instance_pos.size() / 9)); - } - - windDir = getWind(); - SunLightProvider * const cb = (SunLightProvider *)irr_driver->getCallback(ES_SUNLIGHT); - for(unsigned i = 0; i < MeshSolidMaterial[MAT_GRASS].size(); i++) - { - GLMesh *mesh = MeshSolidMaterial[MAT_GRASS][i]; - ListInstancedMatGrass::getInstance()->push_back(STK::make_tuple(mesh, instance_pos.size() / 9, windDir, cb->getPosition())); - } - - for(unsigned i = 0; i < MeshSolidMaterial[MAT_NORMAL_MAP].size(); i++) - { - GLMesh *mesh = MeshSolidMaterial[MAT_NORMAL_MAP][i]; - ListInstancedMatNormalMap::getInstance()->push_back(STK::make_tuple(mesh, instance_pos.size() / 9)); - } -} diff --git a/src/graphics/stkinstancedscenenode.hpp b/src/graphics/stkinstancedscenenode.hpp deleted file mode 100644 index d1063ca6d..000000000 --- a/src/graphics/stkinstancedscenenode.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef STKINSTANCEDSCENENODE_HPP -#define STKINSTANCEDSCENENODE_HPP - -#include "stkmesh.hpp" -#include "utils/leak_check.hpp" - -class ListInstancedMatDefault : public MeshList<ListInstancedMatDefault, GLMesh *, size_t> -{}; - -class ListInstancedMatAlphaRef : public MeshList<ListInstancedMatAlphaRef, GLMesh *, size_t> -{}; - -class ListInstancedMatGrass : public MeshList<ListInstancedMatGrass, GLMesh *, size_t, core::vector3df, core::vector3df> -{}; - -class ListInstancedMatNormalMap : public MeshList<ListInstancedMatNormalMap, GLMesh *, size_t> -{}; - -class STKInstancedSceneNode : public irr::scene::CMeshSceneNode -{ -protected: - int m_ref_count; - std::vector<GLMesh *> MeshSolidMaterial[MAT_COUNT]; - std::vector<GLMesh> GLmeshes; - std::vector<float> instance_pos; - core::matrix4 ModelViewProjectionMatrix, TransposeInverseModelView; - GLuint instances_vbo; - void createGLMeshes(); - bool isMaterialInitialized; - void setFirstTimeMaterial(); - void initinstancedvaostate(GLMesh &mesh); - void cleanGL(); - core::vector3df windDir; -public: - STKInstancedSceneNode(irr::scene::IMesh* mesh, ISceneNode* parent, irr::scene::ISceneManager* mgr, irr::s32 id, - const irr::core::vector3df& position = irr::core::vector3df(0, 0, 0), - const irr::core::vector3df& rotation = irr::core::vector3df(0, 0, 0), - const irr::core::vector3df& scale = irr::core::vector3df(1.0f, 1.0f, 1.0f)); - ~STKInstancedSceneNode(); - virtual void render(); - void addInstance(const core::vector3df &origin, const core::vector3df &orientation, const core::vector3df &scale); - - int getInstanceCount() const { return instance_pos.size() / 9; } - - core::matrix4 getInstanceTransform(int id); - - void instanceGrab() { m_ref_count++; } - void instanceDrop() - { - m_ref_count--; - if (m_ref_count <= 0) - { - delete this; - } - } - - LEAK_CHECK(); -}; - -#endif diff --git a/src/graphics/stkmesh.cpp b/src/graphics/stkmesh.cpp index 568479942..2746a5428 100644 --- a/src/graphics/stkmesh.cpp +++ b/src/graphics/stkmesh.cpp @@ -126,6 +126,7 @@ GLMesh allocateMeshBuffer(scene::IMeshBuffer* mb) GLMesh result = {}; if (!mb) return result; + result.mb = mb; result.IndexCount = mb->getIndexCount(); switch (mb->getIndexType()) @@ -178,6 +179,7 @@ GLMesh allocateMeshBuffer(scene::IMeshBuffer* mb) for (unsigned i = 0; i < 6; i++) result.textures[i] = mb->getMaterial().getTexture(i); result.TextureMatrix = 0; + result.VAOType = mb->getVertexType(); return result; } @@ -229,7 +231,7 @@ core::matrix4 computeMVP(const core::matrix4 &ModelMatrix) return ModelViewProjectionMatrix; } -core::vector3df getWind() +core::vector3df getWindDir() { const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; GrassShaderProvider *gsp = (GrassShaderProvider *)irr_driver->getCallback(ES_GRASS); @@ -292,4 +294,48 @@ bool isObject(video::E_MATERIAL_TYPE type) if (type == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF) return true; return false; +} + +static void +SetTexture(GLMesh &mesh, unsigned i, bool isSrgb) +{ + if (!mesh.textures[i]) + mesh.textures[i] = getUnicolorTexture(video::SColor(255, 255, 255, 255)); + compressTexture(mesh.textures[i], isSrgb); +#ifdef Bindless_Texture_Support + if (UserConfigParams::m_azdo) + { + if (!mesh.TextureHandles[i]) + mesh.TextureHandles[i] = glGetTextureSamplerHandleARB(getTextureGLuint(mesh.textures[i]), MeshShader::ObjectPass1Shader::getInstance()->SamplersId[0]); + if (!glIsTextureHandleResidentARB(mesh.TextureHandles[i])) + glMakeTextureHandleResidentARB(mesh.TextureHandles[i]); + } +#endif +} + +void InitTextures(GLMesh &mesh, MeshMaterial Mat) +{ + switch (Mat) + { + default: + case MAT_DEFAULT: + case MAT_ALPHA_REF: + case MAT_GRASS: + case MAT_SPHEREMAP: + case MAT_UNLIT: + SetTexture(mesh, 0, true); + break; + case MAT_DETAIL: + case MAT_NORMAL_MAP: + SetTexture(mesh, 0, true); + SetTexture(mesh, 1, false); + break; + case MAT_SPLATTING: + SetTexture(mesh, 0, true); + SetTexture(mesh, 1, true); + SetTexture(mesh, 2, true); + SetTexture(mesh, 3, true); + SetTexture(mesh, 4, true); + break; + } } \ No newline at end of file diff --git a/src/graphics/stkmesh.hpp b/src/graphics/stkmesh.hpp index d95933029..569331b96 100644 --- a/src/graphics/stkmesh.hpp +++ b/src/graphics/stkmesh.hpp @@ -35,9 +35,9 @@ enum TransparentMaterial struct GLMesh { GLuint vao; - GLuint vao_shadow_pass; GLuint vertex_buffer; GLuint index_buffer; + GLuint instance_buffer; video::ITexture *textures[6]; GLenum PrimitiveType; GLenum IndexType; @@ -47,6 +47,8 @@ struct GLMesh { size_t vaoBaseVertex; size_t vaoOffset; video::E_VERTEX_TYPE VAOType; + uint64_t TextureHandles[6]; + scene::IMeshBuffer *mb; }; GLMesh allocateMeshBuffer(scene::IMeshBuffer* mb); @@ -56,50 +58,132 @@ GLuint createVAO(GLuint vbo, GLuint idx, video::E_VERTEX_TYPE type); core::matrix4 computeMVP(const core::matrix4 &ModelViewProjectionMatrix); bool isObject(video::E_MATERIAL_TYPE type); -core::vector3df getWind(); +core::vector3df getWindDir(); + + +class STKMeshCommon +{ +protected: + bool m_culledForPlayerCam; + bool m_culledForShadowCam[4]; + bool m_culledForRSMCam; +public: + PtrVector<GLMesh, REF> MeshSolidMaterial[MAT_COUNT]; + PtrVector<GLMesh, REF> TransparentMesh[TM_COUNT]; + virtual void update() = 0; + virtual bool glow() const = 0; + virtual bool isImmediateDraw() const { return false; } + bool isCulledForPlayerCam() const { return m_culledForPlayerCam; } + void setCulledForPlayerCam(bool v) { m_culledForPlayerCam = v; } + bool isCulledForShadowCam(unsigned cascade) const { return m_culledForShadowCam[cascade]; } + void setCulledForShadowCam(unsigned cascade, bool v) { m_culledForShadowCam[cascade] = v; } + bool isCulledForRSMCam() const { return m_culledForRSMCam; } + void setCulledForRSMCam(bool v) { m_culledForRSMCam = v; } +}; template<typename T, typename... Args> -class MeshList : public Singleton<T>, public std::vector<STK::Tuple<Args...> > -{}; +class MeshList : public Singleton<T> +{ +public: + std::vector<STK::Tuple<Args...> > SolidPass, Shadows[4], RSM; + void clear() + { + SolidPass.clear(); + RSM.clear(); + for (unsigned i = 0; i < 4; i++) + Shadows[i].clear(); + } +}; +template<typename T> +class InstancedMeshList : public Singleton<T> +{ +public: + std::vector<GLMesh *> SolidPass, Shadows[4], RSM; + void clear() + { + SolidPass.clear(); + RSM.clear(); + for (unsigned i = 0; i < 4; i++) + Shadows[i].clear(); + } +}; + +// -----------------------------------------Mat Default---------------------------------------------------- // class ListMatDefault : public MeshList<ListMatDefault, GLMesh *, core::matrix4, core::matrix4, core::matrix4> {}; +class ListInstancedMatDefault : public InstancedMeshList<ListInstancedMatDefault> +{}; + + +// -----------------------------------------Mat Alpha Ref---------------------------------------------------- // class ListMatAlphaRef : public MeshList<ListMatAlphaRef, GLMesh *, core::matrix4, core::matrix4, core::matrix4> {}; +class ListInstancedMatAlphaRef : public InstancedMeshList<ListInstancedMatAlphaRef> +{}; + +// -----------------------------------------Mat Normap Map---------------------------------------------------- // class ListMatNormalMap : public MeshList<ListMatNormalMap, GLMesh *, core::matrix4, core::matrix4, core::matrix4> {}; +class ListInstancedMatNormalMap : public InstancedMeshList<ListInstancedMatNormalMap> +{}; + +// -----------------------------------------Mat Grass---------------------------------------------------- // class ListMatGrass : public MeshList<ListMatGrass, GLMesh *, core::matrix4, core::matrix4, core::vector3df> {}; +class ListInstancedMatGrass : public InstancedMeshList<ListInstancedMatGrass> +{}; + +// -----------------------------------------Mat Sphere Map---------------------------------------------------- // class ListMatSphereMap : public MeshList<ListMatSphereMap, GLMesh *, core::matrix4, core::matrix4, core::matrix4> {}; +class ListInstancedMatSphereMap : public InstancedMeshList<ListInstancedMatSphereMap> +{}; + +// -----------------------------------------Mat Splatting---------------------------------------------------- // class ListMatSplatting : public MeshList<ListMatSplatting, GLMesh *, core::matrix4, core::matrix4> {}; +// -----------------------------------------Mat Unlit---------------------------------------------------- // class ListMatUnlit : public MeshList<ListMatUnlit, GLMesh *, core::matrix4, core::matrix4, core::matrix4> {}; +class ListInstancedMatUnlit : public InstancedMeshList<ListInstancedMatUnlit> +{}; + +// -----------------------------------------Mat Details---------------------------------------------------- // class ListMatDetails : public MeshList<ListMatDetails, GLMesh *, core::matrix4, core::matrix4, core::matrix4> {}; - -class ListBlendTransparent : public MeshList<ListBlendTransparent, GLMesh *, core::matrix4, core::matrix4> +class ListInstancedMatDetails : public InstancedMeshList<ListInstancedMatDetails> {}; -class ListAdditiveTransparent : public MeshList<ListAdditiveTransparent, GLMesh *, core::matrix4, core::matrix4> +// Transparent +template <typename T, typename ...Args> +class MiscList : public Singleton<T>, public std::vector<STK::Tuple<Args...> > {}; -class ListBlendTransparentFog : public MeshList<ListBlendTransparentFog, GLMesh *, core::matrix4, core::matrix4, float, float, float, float, float, video::SColorf> +class ListBlendTransparent : public MiscList<ListBlendTransparent, GLMesh *, core::matrix4, core::matrix4> {}; -class ListAdditiveTransparentFog : public MeshList<ListAdditiveTransparentFog, GLMesh *, core::matrix4, core::matrix4, float, float, float, float, float, video::SColorf> +class ListAdditiveTransparent : public MiscList<ListAdditiveTransparent, GLMesh *, core::matrix4, core::matrix4> {}; -class ListDisplacement : public MeshList<ListDisplacement, GLMesh *, core::matrix4> +class ListBlendTransparentFog : public MiscList<ListBlendTransparentFog, GLMesh *, core::matrix4, core::matrix4, float, float, float, float, float, video::SColorf> +{}; + +class ListAdditiveTransparentFog : public MiscList<ListAdditiveTransparentFog, GLMesh *, core::matrix4, core::matrix4, float, float, float, float, float, video::SColorf> +{}; + +class ListDisplacement : public MiscList<ListDisplacement, GLMesh *, core::matrix4> +{}; + +class ListInstancedGlow : public Singleton<ListInstancedGlow>, public std::vector<GLMesh *> {}; // Forward pass (for transparents meshes) @@ -108,4 +192,6 @@ void drawBubble(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatr MeshMaterial MaterialTypeToMeshMaterial(video::E_MATERIAL_TYPE, video::E_VERTEX_TYPE); TransparentMaterial MaterialTypeToTransparentMaterial(video::E_MATERIAL_TYPE, f32 MaterialTypeParam); +void InitTextures(GLMesh &mesh, MeshMaterial); + #endif // STKMESH_H diff --git a/src/graphics/stkmeshscenenode.cpp b/src/graphics/stkmeshscenenode.cpp index 54db127c7..c3a08e50e 100644 --- a/src/graphics/stkmeshscenenode.cpp +++ b/src/graphics/stkmeshscenenode.cpp @@ -21,6 +21,7 @@ STKMeshSceneNode::STKMeshSceneNode(irr::scene::IMesh* mesh, ISceneNode* parent, isDisplacement = false; immediate_draw = false; update_each_frame = false; + isGlow = false; if (createGLMeshes) this->createGLMeshes(); @@ -70,35 +71,31 @@ void STKMeshSceneNode::setFirstTimeMaterial() if (rnd->isTransparent()) { TransparentMaterial TranspMat = MaterialTypeToTransparentMaterial(type, MaterialTypeParam); - if (immediate_draw) - { - fillLocalBuffer(mesh, mb); - mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, mb->getVertexType()); - glBindVertexArray(0); - } - else + if (!immediate_draw) TransparentMesh[TranspMat].push_back(&mesh); } else { assert(!isDisplacement); MeshMaterial MatType = MaterialTypeToMeshMaterial(type, mb->getVertexType()); - if (immediate_draw) + if (!immediate_draw) { - fillLocalBuffer(mesh, mb); - mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, mb->getVertexType()); - glBindVertexArray(0); + InitTextures(mesh, MatType); + MeshSolidMaterial[MatType].push_back(&mesh); } - else - MeshSolidMaterials[MatType].push_back(&mesh); } - if (!immediate_draw) + if (!immediate_draw && irr_driver->hasARB_base_instance()) { - std::pair<unsigned, unsigned> p = getVAOOffsetAndBase(mb); + std::pair<unsigned, unsigned> p = VAOManager::getInstance()->getBase(mb); mesh.vaoBaseVertex = p.first; mesh.vaoOffset = p.second; - mesh.VAOType = mb->getVertexType(); + } + else + { + fillLocalBuffer(mesh, mb); + mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, mb->getVertexType()); + glBindVertexArray(0); } } isMaterialInitialized = true; @@ -113,12 +110,23 @@ void STKMeshSceneNode::cleanGLMeshes() continue; if (mesh.vao) glDeleteVertexArrays(1, &(mesh.vao)); - glDeleteBuffers(1, &(mesh.vertex_buffer)); - glDeleteBuffers(1, &(mesh.index_buffer)); + if (mesh.vertex_buffer) + glDeleteBuffers(1, &(mesh.vertex_buffer)); + if (mesh.index_buffer) + glDeleteBuffers(1, &(mesh.index_buffer)); + if (mesh.instance_buffer) + glDeleteBuffers(1, &(mesh.instance_buffer)); +#ifdef Bindless_Texture_Support + for (unsigned j = 0; j < 6; j++) + { + if (mesh.TextureHandles[j] && glIsTextureHandleResidentARB(mesh.TextureHandles[j])) + glMakeTextureHandleNonResidentARB(mesh.TextureHandles[j]); + } +#endif } GLmeshes.clear(); for (unsigned i = 0; i < MAT_COUNT; i++) - MeshSolidMaterials[i].clearWithoutDeleting(); + MeshSolidMaterial[i].clearWithoutDeleting(); } void STKMeshSceneNode::setMesh(irr::scene::IMesh* mesh) @@ -135,14 +143,12 @@ STKMeshSceneNode::~STKMeshSceneNode() void STKMeshSceneNode::drawGlow(const GLMesh &mesh) { - ColorizeProvider * const cb = (ColorizeProvider *)irr_driver->getCallback(ES_COLORIZE); assert(mesh.VAOType == video::EVT_STANDARD); GLenum ptype = mesh.PrimitiveType; GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; - - MeshShader::ColorizeShader::getInstance()->setUniforms(AbsoluteTransformation, video::SColorf(cb->getRed(), cb->getGreen(), cb->getBlue())); + MeshShader::ColorizeShader::getInstance()->setUniforms(AbsoluteTransformation, video::SColorf(glowcolor.getRed() / 255.f, glowcolor.getGreen() / 255.f, glowcolor.getBlue() / 255.f)); glDrawElementsBaseVertex(ptype, count, itype, (GLvoid *)mesh.vaoOffset, mesh.vaoBaseVertex); } @@ -163,26 +169,8 @@ void STKMeshSceneNode::updatevbo() } } -static video::ITexture *spareWhiteTex = 0; - - -void STKMeshSceneNode::OnRegisterSceneNode() +void STKMeshSceneNode::update() { - if (isDisplacement) - SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); - else - CMeshSceneNode::OnRegisterSceneNode(); -} - -void STKMeshSceneNode::render() -{ - irr::video::IVideoDriver* driver = irr_driver->getVideoDriver(); - - if (!Mesh || !driver) - return; - - ++PassCount; - Box = Mesh->getBoundingBox(); setFirstTimeMaterial(); @@ -194,13 +182,50 @@ void STKMeshSceneNode::render() continue; GLmeshes[i].TextureMatrix = getMaterial(i).getTextureMatrix(0); } +} - if (irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS && immediate_draw) + +void STKMeshSceneNode::OnRegisterSceneNode() +{ + if (isDisplacement) + SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); + else + CMeshSceneNode::OnRegisterSceneNode(); +} + +static video::ITexture *spareWhiteTex = 0; + +void STKMeshSceneNode::render() +{ + irr::video::IVideoDriver* driver = irr_driver->getVideoDriver(); + + if (!Mesh || !driver) + return; + + ++PassCount; + + update(); + + bool isTransparent; + + for (u32 i = 0; i < Mesh->getMeshBufferCount(); ++i) + { + scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); + if (!mb) + continue; + + video::E_MATERIAL_TYPE type = mb->getMaterial().MaterialType; + video::IMaterialRenderer* rnd = driver->getMaterialRenderer(type); + + isTransparent = rnd->isTransparent(); + break; + } + + if ((irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS) && immediate_draw && !isTransparent) { core::matrix4 invmodel; AbsoluteTransformation.getInverse(invmodel); - glDisable(GL_CULL_FACE); if (update_each_frame) updatevbo(); @@ -214,6 +239,21 @@ void STKMeshSceneNode::render() GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; + if (!mesh.textures[0]) + mesh.textures[0] = getUnicolorTexture(video::SColor(255, 255, 255, 255)); + compressTexture(mesh.textures[0], true); + if (UserConfigParams::m_azdo) + { +#ifdef Bindless_Texture_Support + if (!mesh.TextureHandles[0]) + mesh.TextureHandles[0] = glGetTextureSamplerHandleARB(getTextureGLuint(mesh.textures[0]), MeshShader::TransparentFogShader::getInstance()->SamplersId[0]); + if (!glIsTextureHandleResidentARB(mesh.TextureHandles[0])) + glMakeTextureHandleResidentARB(mesh.TextureHandles[0]); + MeshShader::ObjectPass1Shader::getInstance()->SetTextureHandles(createVector<uint64_t>(mesh.TextureHandles[0])); +#endif + } + else + MeshShader::ObjectPass1Shader::getInstance()->SetTextureUnits(std::vector < GLuint > { getTextureGLuint(mesh.textures[0]) }); MeshShader::ObjectPass1Shader::getInstance()->setUniforms(AbsoluteTransformation, invmodel); assert(mesh.vao); glBindVertexArray(mesh.vao); @@ -224,53 +264,25 @@ void STKMeshSceneNode::render() return; } - if (irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS || irr_driver->getPhase() == SHADOW_PASS) + if (irr_driver->getPhase() == SOLID_LIT_PASS && immediate_draw && !isTransparent) { core::matrix4 invmodel; AbsoluteTransformation.getInverse(invmodel); - GLMesh* mesh; - for_in(mesh, MeshSolidMaterials[MAT_DEFAULT]) - pushVector(ListMatDefault::getInstance(), mesh, AbsoluteTransformation, invmodel, mesh->TextureMatrix); - - for_in(mesh, MeshSolidMaterials[MAT_ALPHA_REF]) - pushVector(ListMatAlphaRef::getInstance(), mesh, AbsoluteTransformation, invmodel, mesh->TextureMatrix); - - for_in(mesh, MeshSolidMaterials[MAT_SPHEREMAP]) - pushVector(ListMatSphereMap::getInstance(), mesh, AbsoluteTransformation, invmodel, mesh->TextureMatrix); - - for_in(mesh, MeshSolidMaterials[MAT_DETAIL]) - pushVector(ListMatDetails::getInstance(), mesh, AbsoluteTransformation, invmodel, mesh->TextureMatrix); - - windDir = getWind(); - for_in(mesh, MeshSolidMaterials[MAT_GRASS]) - pushVector(ListMatGrass::getInstance(), mesh, AbsoluteTransformation, invmodel, windDir); - - for_in(mesh, MeshSolidMaterials[MAT_UNLIT]) - pushVector(ListMatUnlit::getInstance(), mesh, AbsoluteTransformation, core::matrix4::EM4CONST_IDENTITY, mesh->TextureMatrix); - - for_in(mesh, MeshSolidMaterials[MAT_SPLATTING]) - pushVector(ListMatSplatting::getInstance(), mesh, AbsoluteTransformation, invmodel); - - for_in(mesh, MeshSolidMaterials[MAT_NORMAL_MAP]) - pushVector(ListMatNormalMap::getInstance(), mesh, AbsoluteTransformation, invmodel, core::matrix4::EM4CONST_IDENTITY); - - return; - } - - if (irr_driver->getPhase() == SOLID_LIT_PASS) - { - core::matrix4 invmodel; - AbsoluteTransformation.getInverse(invmodel); - - if (immediate_draw) + glDisable(GL_CULL_FACE); + if (!spareWhiteTex) + spareWhiteTex = getUnicolorTexture(video::SColor(255, 255, 255, 255)); + glUseProgram(MeshShader::ObjectPass2Shader::getInstance()->Program); + // Only untextured + for (unsigned i = 0; i < GLmeshes.size(); i++) { - glDisable(GL_CULL_FACE); - if (!spareWhiteTex) - spareWhiteTex = getUnicolorTexture(video::SColor(255, 255, 255, 255)); - glUseProgram(MeshShader::ObjectPass2Shader::getInstance()->Program); - // Only untextured - for (unsigned i = 0; i < GLmeshes.size(); i++) + irr_driver->IncreaseObjectCount(); + GLMesh &mesh = GLmeshes[i]; + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + if (UserConfigParams::m_azdo) { irr_driver->IncreaseObjectCount(); GLMesh &mesh = GLmeshes[i]; @@ -278,17 +290,54 @@ void STKMeshSceneNode::render() GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; - setTexture(MeshShader::ObjectPass2Shader::getInstance()->TU_Albedo, getTextureGLuint(spareWhiteTex), GL_NEAREST, GL_NEAREST, false); + if (UserConfigParams::m_azdo) + { +#ifdef Bindless_Texture_Support + GLuint64 DiffuseHandle = glGetTextureSamplerHandleARB(irr_driver->getRenderTargetTexture(RTT_DIFFUSE), MeshShader::ObjectPass2Shader::getInstance()->SamplersId[0]); + if (!glIsTextureHandleResidentARB(DiffuseHandle)) + glMakeTextureHandleResidentARB(DiffuseHandle); + + GLuint64 SpecularHandle = glGetTextureSamplerHandleARB(irr_driver->getRenderTargetTexture(RTT_SPECULAR), MeshShader::ObjectPass2Shader::getInstance()->SamplersId[1]); + if (!glIsTextureHandleResidentARB(SpecularHandle)) + glMakeTextureHandleResidentARB(SpecularHandle); + + GLuint64 SSAOHandle = glGetTextureSamplerHandleARB(irr_driver->getRenderTargetTexture(RTT_HALF1_R), MeshShader::ObjectPass2Shader::getInstance()->SamplersId[2]); + if (!glIsTextureHandleResidentARB(SSAOHandle)) + glMakeTextureHandleResidentARB(SSAOHandle); + + if (!mesh.TextureHandles[0]) + mesh.TextureHandles[0] = glGetTextureSamplerHandleARB(getTextureGLuint(spareWhiteTex), MeshShader::TransparentFogShader::getInstance()->SamplersId[0]); + if (!glIsTextureHandleResidentARB(mesh.TextureHandles[0])) + glMakeTextureHandleResidentARB(mesh.TextureHandles[0]); + MeshShader::ObjectPass2Shader::getInstance()->SetTextureHandles(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, mesh.TextureHandles[0])); +#endif + } + else + MeshShader::ObjectPass2Shader::getInstance()->SetTextureUnits(createVector<GLuint>( + irr_driver->getRenderTargetTexture(RTT_DIFFUSE), + irr_driver->getRenderTargetTexture(RTT_SPECULAR), + irr_driver->getRenderTargetTexture(RTT_HALF1_R), + getTextureGLuint(spareWhiteTex))); + MeshShader::ObjectPass2Shader::getInstance()->setUniforms(AbsoluteTransformation, mesh.TextureMatrix); assert(mesh.vao); glBindVertexArray(mesh.vao); glDrawElements(ptype, count, itype, 0); glBindVertexArray(0); } - glEnable(GL_CULL_FACE); - return; + else + MeshShader::ObjectPass2Shader::getInstance()->SetTextureUnits(createVector<GLuint>( + irr_driver->getRenderTargetTexture(RTT_DIFFUSE), + irr_driver->getRenderTargetTexture(RTT_SPECULAR), + irr_driver->getRenderTargetTexture(RTT_HALF1_R), + getTextureGLuint(mesh.textures[0]))); + MeshShader::ObjectPass2Shader::getInstance()->setUniforms(AbsoluteTransformation, mesh.TextureMatrix); + assert(mesh.vao); + glBindVertexArray(mesh.vao); + glDrawElements(ptype, count, itype, 0); + glBindVertexArray(0); } - + glEnable(GL_CULL_FACE); return; } @@ -300,12 +349,15 @@ void STKMeshSceneNode::render() scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); if (!mb) continue; - glBindVertexArray(getVAO(video::EVT_STANDARD)); + if (irr_driver->hasARB_base_instance()) + glBindVertexArray(VAOManager::getInstance()->getVAO(video::EVT_STANDARD)); + else + glBindVertexArray(GLmeshes[i].vao); drawGlow(GLmeshes[i]); } } - if (irr_driver->getPhase() == TRANSPARENT_PASS) + if (irr_driver->getPhase() == TRANSPARENT_PASS && isTransparent) { ModelViewProjectionMatrix = computeMVP(AbsoluteTransformation); @@ -340,8 +392,21 @@ void STKMeshSceneNode::render() tmpcol.getGreen() / 255.0f, tmpcol.getBlue() / 255.0f); + if (!mesh.textures[0]) + mesh.textures[0] = getUnicolorTexture(video::SColor(255, 255, 255, 255)); compressTexture(mesh.textures[0], true); - setTexture(MeshShader::TransparentFogShader::getInstance()->TU_tex, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + if (UserConfigParams::m_azdo) + { +#ifdef Bindless_Texture_Support + if (!mesh.TextureHandles[0]) + mesh.TextureHandles[0] = glGetTextureSamplerHandleARB(getTextureGLuint(mesh.textures[0]), MeshShader::TransparentFogShader::getInstance()->SamplersId[0]); + if (!glIsTextureHandleResidentARB(mesh.TextureHandles[0])) + glMakeTextureHandleResidentARB(mesh.TextureHandles[0]); + MeshShader::TransparentFogShader::getInstance()->SetTextureHandles(createVector<uint64_t>(mesh.TextureHandles[0])); +#endif + } + else + MeshShader::TransparentFogShader::getInstance()->SetTextureUnits(std::vector<GLuint>{ getTextureGLuint(mesh.textures[0]) }); MeshShader::TransparentFogShader::getInstance()->setUniforms(AbsoluteTransformation, mesh.TextureMatrix, fogmax, startH, endH, start, end, col); assert(mesh.vao); @@ -360,9 +425,21 @@ void STKMeshSceneNode::render() GLenum ptype = mesh.PrimitiveType; GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; - + if (!mesh.textures[0]) + mesh.textures[0] = getUnicolorTexture(video::SColor(255, 255, 255, 255)); compressTexture(mesh.textures[0], true); - setTexture(MeshShader::TransparentShader::getInstance()->TU_tex, getTextureGLuint(mesh.textures[0]), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + if (UserConfigParams::m_azdo) + { +#ifdef Bindless_Texture_Support + if (!mesh.TextureHandles[0]) + mesh.TextureHandles[0] = glGetTextureSamplerHandleARB(getTextureGLuint(mesh.textures[0]), MeshShader::TransparentShader::getInstance()->SamplersId[0]); + if (!glIsTextureHandleResidentARB(mesh.TextureHandles[0])) + glMakeTextureHandleResidentARB(mesh.TextureHandles[0]); + MeshShader::TransparentShader::getInstance()->SetTextureHandles(createVector<uint64_t>(mesh.TextureHandles[0])); +#endif + } + else + MeshShader::TransparentShader::getInstance()->SetTextureUnits(std::vector<GLuint>{ getTextureGLuint(mesh.textures[0]) }); MeshShader::TransparentShader::getInstance()->setUniforms(AbsoluteTransformation, mesh.TextureMatrix); assert(mesh.vao); @@ -375,47 +452,16 @@ void STKMeshSceneNode::render() } GLMesh* mesh; - - if (World::getWorld() && World::getWorld()->isFogEnabled()) - { - const Track * const track = World::getWorld()->getTrack(); - - // Todo : put everything in a ubo - const float fogmax = track->getFogMax(); - const float startH = track->getFogStartHeight(); - const float endH = track->getFogEndHeight(); - const float start = track->getFogStart(); - const float end = track->getFogEnd(); - const video::SColor tmpcol = track->getFogColor(); - - video::SColorf col(tmpcol.getRed() / 255.0f, - tmpcol.getGreen() / 255.0f, - tmpcol.getBlue() / 255.0f); - - for_in(mesh, TransparentMesh[TM_DEFAULT]) - pushVector(ListBlendTransparentFog::getInstance(), mesh, AbsoluteTransformation, mesh->TextureMatrix, - fogmax, startH, endH, start, end, col); - for_in(mesh, TransparentMesh[TM_ADDITIVE]) - pushVector(ListAdditiveTransparentFog::getInstance(), mesh, AbsoluteTransformation, mesh->TextureMatrix, - fogmax, startH, endH, start, end, col); - } - else - { - for_in(mesh, TransparentMesh[TM_DEFAULT]) - pushVector(ListBlendTransparent::getInstance(), mesh, AbsoluteTransformation, mesh->TextureMatrix); - - for_in(mesh, TransparentMesh[TM_ADDITIVE]) - pushVector(ListAdditiveTransparent::getInstance(), mesh, AbsoluteTransformation, mesh->TextureMatrix); - } - - for_in(mesh, TransparentMesh[TM_DISPLACEMENT]) - pushVector(ListDisplacement::getInstance(), mesh, AbsoluteTransformation); - if (!TransparentMesh[TM_BUBBLE].empty()) glUseProgram(MeshShader::BubbleShader::Program); - glBindVertexArray(getVAO(video::EVT_STANDARD)); + if (irr_driver->hasARB_base_instance()) + glBindVertexArray(VAOManager::getInstance()->getVAO(video::EVT_STANDARD)); for_in(mesh, TransparentMesh[TM_BUBBLE]) + { + if (irr_driver->hasARB_base_instance()) + glBindVertexArray(mesh->vao); drawBubble(*mesh, ModelViewProjectionMatrix); + } return; } } diff --git a/src/graphics/stkmeshscenenode.hpp b/src/graphics/stkmeshscenenode.hpp index d9e16283b..a8e8724ed 100644 --- a/src/graphics/stkmeshscenenode.hpp +++ b/src/graphics/stkmeshscenenode.hpp @@ -4,11 +4,9 @@ #include "stkmesh.hpp" #include "utils/ptr_vector.hpp" -class STKMeshSceneNode : public irr::scene::CMeshSceneNode +class STKMeshSceneNode : public irr::scene::CMeshSceneNode, public STKMeshCommon { protected: - PtrVector<GLMesh, REF> MeshSolidMaterials[MAT_COUNT]; - PtrVector<GLMesh, REF> TransparentMesh[TM_COUNT]; std::vector<GLMesh> GLmeshes; core::matrix4 ModelViewProjectionMatrix; core::vector3df windDir; @@ -24,7 +22,10 @@ protected: bool immediate_draw; bool update_each_frame; bool isDisplacement; + bool isGlow; + video::SColor glowcolor; public: + virtual void update(); void setReloadEachFrame(bool); STKMeshSceneNode(irr::scene::IMesh* mesh, ISceneNode* parent, irr::scene::ISceneManager* mgr, irr::s32 id, const irr::core::vector3df& position = irr::core::vector3df(0, 0, 0), @@ -35,6 +36,7 @@ public: virtual void setMesh(irr::scene::IMesh* mesh); virtual void OnRegisterSceneNode(); virtual ~STKMeshSceneNode(); + virtual bool isImmediateDraw() const { return immediate_draw; } void setIsDisplacement(bool v) { isDisplacement = v; for (u32 i = 0; i < Mesh->getMeshBufferCount(); ++i) @@ -46,6 +48,9 @@ public: mb->getMaterial().MaterialType = irr_driver->getShader(ES_DISPLACE); } } + virtual bool glow() const { return isGlow; } + void setGlowColors(const video::SColor &c) { isGlow = true; glowcolor = c; } + video::SColor getGlowColor() const { return glowcolor; } }; #endif diff --git a/src/graphics/stkscenemanager.cpp b/src/graphics/stkscenemanager.cpp new file mode 100644 index 000000000..57721bf20 --- /dev/null +++ b/src/graphics/stkscenemanager.cpp @@ -0,0 +1,710 @@ +#include "stkscenemanager.hpp" +#include "stkmesh.hpp" +#include "irr_driver.hpp" +#include <ISceneManager.h> +#include <ISceneNode.h> +#include "stkanimatedmesh.hpp" +#include "stkmeshscenenode.hpp" +#include "utils/ptr_vector.hpp" +#include <ICameraSceneNode.h> +#include <SViewFrustum.h> +#include "callbacks.hpp" +#include "utils/cpp2011.hpp" +#include <omp.h> +#include "modes/world.hpp" +#include "tracks/track.hpp" +#include "lod_node.hpp" +#include "utils/profiler.hpp" +#include <unordered_map> +#include <SViewFrustum.h> +#include <functional> + +static void +FillInstances_impl(std::vector<std::pair<GLMesh *, scene::ISceneNode *> > InstanceList, InstanceData * InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, + size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &PolyCount, std::function<bool (const scene::ISceneNode *)> cull_func) +{ + // Should never be empty + GLMesh *mesh = InstanceList.front().first; + size_t InitialOffset = InstanceBufferOffset; + + for (unsigned i = 0; i < InstanceList.size(); i++) + { + auto &Tp = InstanceList[i]; + scene::ISceneNode *node = Tp.second; + if (cull_func(node)) + continue; + InstanceData &Instance = InstanceBuffer[InstanceBufferOffset++]; + const core::matrix4 &mat = node->getAbsoluteTransformation(); + const core::vector3df &Origin = mat.getTranslation(); + const core::vector3df &Orientation = mat.getRotationDegrees(); + const core::vector3df &Scale = mat.getScale(); + Instance.Origin.X = Origin.X; + Instance.Origin.Y = Origin.Y; + Instance.Origin.Z = Origin.Z; + Instance.Orientation.X = Orientation.X; + Instance.Orientation.Y = Orientation.Y; + Instance.Orientation.Z = Orientation.Z; + Instance.Scale.X = Scale.X; + Instance.Scale.Y = Scale.Y; + Instance.Scale.Z = Scale.Z; + Instance.Texture = mesh->TextureHandles[0]; + Instance.SecondTexture = mesh->TextureHandles[1]; + } + + DrawElementsIndirectCommand &CurrentCommand = CommandBuffer[CommandBufferOffset++]; + CurrentCommand.baseVertex = mesh->vaoBaseVertex; + CurrentCommand.count = mesh->IndexCount; + CurrentCommand.firstIndex = mesh->vaoOffset / 2; + CurrentCommand.baseInstance = InitialOffset; + CurrentCommand.instanceCount = InstanceBufferOffset - InitialOffset; + + PolyCount += (InstanceBufferOffset - InitialOffset) * mesh->IndexCount / 3; +} + + +static void +FillInstancesGlow_impl(std::vector<std::pair<GLMesh *, STKMeshCommon *> > InstanceList, GlowInstanceData * InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, + size_t &InstanceBufferOffset, size_t &CommandBufferOffset, std::function<bool (const scene::ISceneNode *)> cull_func) +{ + // Should never be empty + GLMesh *mesh = InstanceList.front().first; + size_t InitialOffset = InstanceBufferOffset; + + for (unsigned i = 0; i < InstanceList.size(); i++) + { + STKMeshSceneNode *node = dynamic_cast<STKMeshSceneNode*>(InstanceList[i].second); + if (cull_func(node)) + continue; + GlowInstanceData &Instance = InstanceBuffer[InstanceBufferOffset++]; + const core::matrix4 &mat = node->getAbsoluteTransformation(); + const core::vector3df &Origin = mat.getTranslation(); + const core::vector3df &Orientation = mat.getRotationDegrees(); + const core::vector3df &Scale = mat.getScale(); + Instance.Color = node->getGlowColor().color; + Instance.Origin.X = Origin.X; + Instance.Origin.Y = Origin.Y; + Instance.Origin.Z = Origin.Z; + Instance.Orientation.X = Orientation.X; + Instance.Orientation.Y = Orientation.Y; + Instance.Orientation.Z = Orientation.Z; + Instance.Scale.X = Scale.X; + Instance.Scale.Y = Scale.Y; + Instance.Scale.Z = Scale.Z; + } + + DrawElementsIndirectCommand &CurrentCommand = CommandBuffer[CommandBufferOffset++]; + CurrentCommand.baseVertex = mesh->vaoBaseVertex; + CurrentCommand.count = mesh->IndexCount; + CurrentCommand.firstIndex = mesh->vaoOffset / 2; + CurrentCommand.baseInstance = InitialOffset; + CurrentCommand.instanceCount = InstanceBufferOffset - InitialOffset; +} + + +static +void FillInstances(const std::unordered_map<scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > &GatheredGLMesh, std::vector<GLMesh *> &InstancedList, + InstanceData *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &Polycount, + std::function<bool (const scene::ISceneNode *)> cull_func) +{ + auto It = GatheredGLMesh.begin(), E = GatheredGLMesh.end(); + for (; It != E; ++It) + { + FillInstances_impl(It->second, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, Polycount, cull_func); + if (!UserConfigParams::m_azdo) + InstancedList.push_back(It->second.front().first); + } +} + +static +void FillInstancesGrass(const std::unordered_map<scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > &GatheredGLMesh, std::vector<GLMesh *> &InstancedList, + InstanceData *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, const core::vector3df &dir, size_t &PolyCount, + std::function<bool (const scene::ISceneNode *)> cull_func) +{ + auto It = GatheredGLMesh.begin(), E = GatheredGLMesh.end(); + SunLightProvider * const cb = (SunLightProvider *)irr_driver->getCallback(ES_SUNLIGHT); + for (; It != E; ++It) + { + FillInstances_impl(It->second, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, PolyCount, cull_func); + if (!UserConfigParams::m_azdo) + InstancedList.push_back(It->second.front().first); + } +} + +static std::unordered_map <scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > MeshForSolidPass[MAT_COUNT]; +static std::unordered_map <scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > MeshForShadowPass[4][MAT_COUNT]; +static std::unordered_map <scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > MeshForRSMPass[MAT_COUNT]; +static std::unordered_map <scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, STKMeshCommon *> > > MeshForGlowPass; +static std::vector <STKMeshCommon *> DeferredUpdate; + +static core::vector3df windDir; + +// From irrlicht code +static +bool isBoxInFrontOfPlane(const core::plane3df &plane, const core::vector3df edges[8]) +{ + for (u32 j = 0; j<8; ++j) + if (plane.classifyPointRelation(edges[j]) != core::ISREL3D_FRONT) + return false; + return true; +} + +static +bool isCulled(const scene::ICameraSceneNode *cam, const scene::ISceneNode *node) +{ + if (!node->getAutomaticCulling()) + return false; + + scene::SViewFrustum frust = *cam->getViewFrustum(); + + //transform the frustum to the node's current absolute transformation + core::matrix4 invTrans(node->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE); + //invTrans.makeInverse(); + frust.transform(invTrans); + + core::vector3df edges[8]; + node->getBoundingBox().getEdges(edges); + + for (s32 i = 0; i < scene::SViewFrustum::VF_PLANE_COUNT; ++i) + if (isBoxInFrontOfPlane(frust.planes[i], edges)) + return true; + return false; +} + +static void +handleSTKCommon(scene::ISceneNode *Node, std::vector<scene::ISceneNode *> *ImmediateDraw) +{ + STKMeshCommon *node = dynamic_cast<STKMeshCommon*>(Node); + if (!node) + return; + DeferredUpdate.push_back(node); + + if (node->isImmediateDraw()) + { + ImmediateDraw->push_back(Node); + return; + } + for (unsigned Mat = 0; Mat < MAT_COUNT; ++Mat) + { + GLMesh *mesh; + if (irr_driver->hasARB_draw_indirect()) + { + for_in(mesh, node->MeshSolidMaterial[Mat]) + { + if (node->glow()) + MeshForGlowPass[mesh->mb].emplace_back(mesh, node); + + if (Mat != MAT_SPLATTING && mesh->TextureMatrix.isIdentity()) + MeshForSolidPass[Mat][mesh->mb].emplace_back(mesh, Node); + else + { + core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; + ModelMatrix.getInverse(InvModelMatrix); + switch (Mat) + { + case MAT_DEFAULT: + ListMatDefault::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_ALPHA_REF: + ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_UNLIT: + ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_SPLATTING: + ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix); + break; + } + } + } + } + else + { + core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; + ModelMatrix.getInverse(InvModelMatrix); + + for_in(mesh, node->MeshSolidMaterial[Mat]) + { + switch (Mat) + { + case MAT_DEFAULT: + ListMatDefault::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_ALPHA_REF: + ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_NORMAL_MAP: + ListMatNormalMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_DETAIL: + ListMatDetails::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_UNLIT: + ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_SPHEREMAP: + ListMatSphereMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_SPLATTING: + ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix); + break; + case MAT_GRASS: + ListMatGrass::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir); + break; + } + } + } + if (!UserConfigParams::m_shadows) + return; + for (unsigned cascade = 0; cascade < 4; ++cascade) + { + if (irr_driver->hasARB_draw_indirect()) + { + for_in(mesh, node->MeshSolidMaterial[Mat]) + MeshForShadowPass[cascade][Mat][mesh->mb].emplace_back(mesh, Node); + } + else + { + core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; + ModelMatrix.getInverse(InvModelMatrix); + + for_in(mesh, node->MeshSolidMaterial[Mat]) + { + switch (Mat) + { + case MAT_DEFAULT: + ListMatDefault::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_ALPHA_REF: + ListMatAlphaRef::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_NORMAL_MAP: + ListMatNormalMap::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_DETAIL: + ListMatDetails::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_UNLIT: + ListMatUnlit::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_SPHEREMAP: + ListMatSphereMap::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_SPLATTING: + ListMatSplatting::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix); + break; + case MAT_GRASS: + ListMatGrass::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir); + } + } + } + } + if (!UserConfigParams::m_gi) + return; + if (irr_driver->hasARB_draw_indirect()) + { + for_in(mesh, node->MeshSolidMaterial[Mat]) + if (Mat != MAT_SPLATTING) + MeshForRSMPass[Mat][mesh->mb].emplace_back(mesh, Node); + else + { + core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; + ModelMatrix.getInverse(InvModelMatrix); + ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix); + } + } + else + { + core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; + ModelMatrix.getInverse(InvModelMatrix); + + for_in(mesh, node->MeshSolidMaterial[Mat]) + { + switch (Mat) + { + case MAT_DEFAULT: + ListMatDefault::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_ALPHA_REF: + ListMatAlphaRef::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_NORMAL_MAP: + ListMatNormalMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_DETAIL: + ListMatDetails::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_UNLIT: + ListMatUnlit::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_SPHEREMAP: + ListMatSphereMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_SPLATTING: + ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix); + break; + case MAT_GRASS: + ListMatGrass::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir); + break; + } + } + } + } + // Transparent + GLMesh *mesh; + if (World::getWorld() && World::getWorld()->isFogEnabled()) + { + const Track * const track = World::getWorld()->getTrack(); + + // Todo : put everything in a ubo + const float fogmax = track->getFogMax(); + const float startH = track->getFogStartHeight(); + const float endH = track->getFogEndHeight(); + const float start = track->getFogStart(); + const float end = track->getFogEnd(); + const video::SColor tmpcol = track->getFogColor(); + + video::SColorf col(tmpcol.getRed() / 255.0f, + tmpcol.getGreen() / 255.0f, + tmpcol.getBlue() / 255.0f); + + for_in(mesh, node->TransparentMesh[TM_DEFAULT]) + pushVector(ListBlendTransparentFog::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, + fogmax, startH, endH, start, end, col); + for_in(mesh, node->TransparentMesh[TM_ADDITIVE]) + pushVector(ListAdditiveTransparentFog::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, + fogmax, startH, endH, start, end, col); + } + else + { + for_in(mesh, node->TransparentMesh[TM_DEFAULT]) + pushVector(ListBlendTransparent::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix); + for_in(mesh, node->TransparentMesh[TM_ADDITIVE]) + pushVector(ListAdditiveTransparent::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix); + } + for_in(mesh, node->TransparentMesh[TM_DISPLACEMENT]) + pushVector(ListDisplacement::getInstance(), mesh, Node->getAbsoluteTransformation()); +} + +static void +parseSceneManager(core::list<scene::ISceneNode*> List, std::vector<scene::ISceneNode *> *ImmediateDraw, + scene::ICameraSceneNode* cam) +{ + core::list<scene::ISceneNode*>::Iterator I = List.begin(), E = List.end(); + for (; I != E; ++I) + { + if (LODNode *node = dynamic_cast<LODNode *>(*I)) + node->updateVisibility(); + if (!(*I)->isVisible()) + continue; + (*I)->updateAbsolutePosition(); + + if (ParticleSystemProxy *node = dynamic_cast<ParticleSystemProxy *>(*I)) + { + if (!isCulled(cam, *I) && node->update()) + ParticlesList::getInstance()->push_back(node); + continue; + } + + handleSTKCommon(*I, ImmediateDraw); + + parseSceneManager((*I)->getChildren(), ImmediateDraw, cam); + } +} + +template<MeshMaterial Mat> static void +GenDrawCalls(unsigned cascade, std::vector<GLMesh *> &InstancedList, + InstanceData *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &PolyCount) +{ + std::function<bool(const scene::ISceneNode *)> shadowculling = [&](const scene::ISceneNode *nd) {return dynamic_cast<const STKMeshCommon*>(nd)->isCulledForShadowCam(cascade); }; + if (irr_driver->hasARB_draw_indirect()) + ShadowPassCmd::getInstance()->Offset[cascade][Mat] = CommandBufferOffset; // Store command buffer offset + FillInstances(MeshForShadowPass[cascade][Mat], InstancedList, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, PolyCount, shadowculling); + if (UserConfigParams::m_azdo) + ShadowPassCmd::getInstance()->Size[cascade][Mat] = CommandBufferOffset - ShadowPassCmd::getInstance()->Offset[cascade][Mat]; +} + +template<MeshMaterial Mat> static void +GenDrawCallsGrass(unsigned cascade, std::vector<GLMesh *> &InstancedList, +InstanceData *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, const core::vector3df &dir, size_t &PolyCount) +{ + std::function<bool(const scene::ISceneNode *)> shadowculling = [&](const scene::ISceneNode *nd) {return dynamic_cast<const STKMeshCommon*>(nd)->isCulledForShadowCam(cascade); }; + if (irr_driver->hasARB_draw_indirect()) + ShadowPassCmd::getInstance()->Offset[cascade][Mat] = CommandBufferOffset; // Store command buffer offset + FillInstancesGrass(MeshForShadowPass[cascade][Mat], InstancedList, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, dir, PolyCount, shadowculling); + if (UserConfigParams::m_azdo) + ShadowPassCmd::getInstance()->Size[cascade][Mat] = CommandBufferOffset - ShadowPassCmd::getInstance()->Offset[cascade][Mat]; +} + +void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode) +{ + windDir = getWindDir(); + ListBlendTransparent::getInstance()->clear(); + ListAdditiveTransparent::getInstance()->clear(); + ListBlendTransparentFog::getInstance()->clear(); + ListAdditiveTransparentFog::getInstance()->clear(); + ListDisplacement::getInstance()->clear(); + + ListMatDefault::getInstance()->clear(); + ListMatAlphaRef::getInstance()->clear(); + ListMatSphereMap::getInstance()->clear(); + ListMatDetails::getInstance()->clear(); + ListMatUnlit::getInstance()->clear(); + ListMatNormalMap::getInstance()->clear(); + ListMatGrass::getInstance()->clear(); + ListMatSplatting::getInstance()->clear(); + + ImmediateDrawList::getInstance()->clear(); + ParticlesList::getInstance()->clear(); + ListInstancedGlow::getInstance()->clear(); + + for (unsigned Mat = 0; Mat < MAT_COUNT; ++Mat) + { + MeshForSolidPass[Mat].clear(); + MeshForRSMPass[Mat].clear(); + for (unsigned cascade = 0; cascade < 4; ++cascade) + MeshForShadowPass[cascade][Mat].clear(); + } + MeshForGlowPass.clear(); + DeferredUpdate.clear(); + core::list<scene::ISceneNode*> List = m_scene_manager->getRootSceneNode()->getChildren(); + + parseSceneManager(List, ImmediateDrawList::getInstance(), camnode); + +#pragma omp parallel for + for (int i = 0; i < (int)DeferredUpdate.size(); i++) + { + scene::ISceneNode *node = dynamic_cast<scene::ISceneNode *>(DeferredUpdate[i]); + DeferredUpdate[i]->setCulledForPlayerCam(isCulled(camnode, node)); + DeferredUpdate[i]->setCulledForRSMCam(isCulled(m_suncam, node)); + DeferredUpdate[i]->setCulledForShadowCam(0, isCulled(m_shadow_camnodes[0], node)); + DeferredUpdate[i]->setCulledForShadowCam(1, isCulled(m_shadow_camnodes[1], node)); + DeferredUpdate[i]->setCulledForShadowCam(2, isCulled(m_shadow_camnodes[2], node)); + DeferredUpdate[i]->setCulledForShadowCam(3, isCulled(m_shadow_camnodes[3], node)); + } + + // Add a 1 s timeout + if (!m_sync) + m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + PROFILER_PUSH_CPU_MARKER("- Sync Stall", 0xFF, 0x0, 0x0); + GLenum reason = glClientWaitSync(m_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000000000); + PROFILER_POP_CPU_MARKER(); + /* switch (reason) + { + case GL_ALREADY_SIGNALED: + printf("Already Signaled\n"); + break; + case GL_TIMEOUT_EXPIRED: + printf("Timeout Expired\n"); + break; + case GL_CONDITION_SATISFIED: + printf("Condition Satisfied\n"); + break; + case GL_WAIT_FAILED: + printf("Wait Failed\n"); + break; + }*/ + for (unsigned i = 0; i < DeferredUpdate.size(); i++) + DeferredUpdate[i]->update(); + + if (!irr_driver->hasARB_draw_indirect()) + return; + + InstanceData *InstanceBuffer; + InstanceData *ShadowInstanceBuffer; + InstanceData *RSMInstanceBuffer; + GlowInstanceData *GlowInstanceBuffer; + DrawElementsIndirectCommand *CmdBuffer; + DrawElementsIndirectCommand *ShadowCmdBuffer; + DrawElementsIndirectCommand *RSMCmdBuffer; + DrawElementsIndirectCommand *GlowCmdBuffer; + + if (irr_driver->hasBufferStorageExtension()) + { + InstanceBuffer = (InstanceData*)VAOManager::getInstance()->getInstanceBufferPtr(InstanceTypeDefault); + ShadowInstanceBuffer = (InstanceData*)VAOManager::getInstance()->getInstanceBufferPtr(InstanceTypeShadow); + RSMInstanceBuffer = (InstanceData*)VAOManager::getInstance()->getInstanceBufferPtr(InstanceTypeRSM); + GlowInstanceBuffer = (GlowInstanceData*)VAOManager::getInstance()->getInstanceBufferPtr(InstanceTypeGlow); + CmdBuffer = SolidPassCmd::getInstance()->Ptr; + ShadowCmdBuffer = ShadowPassCmd::getInstance()->Ptr; + GlowCmdBuffer = GlowPassCmd::getInstance()->Ptr; + RSMCmdBuffer = RSMPassCmd::getInstance()->Ptr; + } + + ListInstancedMatDefault::getInstance()->clear(); + ListInstancedMatAlphaRef::getInstance()->clear(); + ListInstancedMatGrass::getInstance()->clear(); + ListInstancedMatNormalMap::getInstance()->clear(); + ListInstancedMatSphereMap::getInstance()->clear(); + ListInstancedMatDetails::getInstance()->clear(); + ListInstancedMatUnlit::getInstance()->clear(); + + size_t SolidPoly = 0, ShadowPoly = 0, MiscPoly = 0; + + PROFILER_PUSH_CPU_MARKER("- Draw Command upload", 0xFF, 0x0, 0xFF); + + auto playercamculling = [](const scene::ISceneNode *nd) {return dynamic_cast<const STKMeshCommon*>(nd)->isCulledForPlayerCam(); }; +#pragma omp parallel sections + { +#pragma omp section + { + size_t offset = 0, current_cmd = 0; + if (!irr_driver->hasBufferStorageExtension()) + { + glBindBuffer(GL_ARRAY_BUFFER, VAOManager::getInstance()->getInstanceBuffer(InstanceTypeDefault)); + InstanceBuffer = (InstanceData*)glMapBufferRange(GL_ARRAY_BUFFER, 0, 10000 * sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, SolidPassCmd::getInstance()->drawindirectcmd); + CmdBuffer = (DrawElementsIndirectCommand*)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + } + + + // Default Material + SolidPassCmd::getInstance()->Offset[MAT_DEFAULT] = current_cmd; + FillInstances(MeshForSolidPass[MAT_DEFAULT], ListInstancedMatDefault::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); + SolidPassCmd::getInstance()->Size[MAT_DEFAULT] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_DEFAULT]; + // Alpha Ref + SolidPassCmd::getInstance()->Offset[MAT_ALPHA_REF] = current_cmd; + FillInstances(MeshForSolidPass[MAT_ALPHA_REF], ListInstancedMatAlphaRef::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); + SolidPassCmd::getInstance()->Size[MAT_ALPHA_REF] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_ALPHA_REF]; + // Unlit + SolidPassCmd::getInstance()->Offset[MAT_UNLIT] = current_cmd; + FillInstances(MeshForSolidPass[MAT_UNLIT], ListInstancedMatUnlit::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); + SolidPassCmd::getInstance()->Size[MAT_UNLIT] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_UNLIT]; + // Spheremap + SolidPassCmd::getInstance()->Offset[MAT_SPHEREMAP] = current_cmd; + FillInstances(MeshForSolidPass[MAT_SPHEREMAP], ListInstancedMatSphereMap::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); + SolidPassCmd::getInstance()->Size[MAT_SPHEREMAP] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_SPHEREMAP]; + // Detail + SolidPassCmd::getInstance()->Offset[MAT_DETAIL] = current_cmd; + FillInstances(MeshForSolidPass[MAT_DETAIL], ListInstancedMatDetails::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); + SolidPassCmd::getInstance()->Size[MAT_DETAIL] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_DETAIL]; + // Normal Map + SolidPassCmd::getInstance()->Offset[MAT_NORMAL_MAP] = current_cmd; + FillInstances(MeshForSolidPass[MAT_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); + SolidPassCmd::getInstance()->Size[MAT_NORMAL_MAP] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_NORMAL_MAP]; + + // Grass + SolidPassCmd::getInstance()->Offset[MAT_GRASS] = current_cmd; + FillInstancesGrass(MeshForSolidPass[MAT_GRASS], ListInstancedMatGrass::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, windDir, SolidPoly, playercamculling); + SolidPassCmd::getInstance()->Size[MAT_GRASS] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_GRASS]; + + if (!irr_driver->hasBufferStorageExtension()) + { + glUnmapBuffer(GL_ARRAY_BUFFER); + glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); + } + } +#pragma omp section + { + size_t offset = 0, current_cmd = 0; + + if (!irr_driver->hasBufferStorageExtension()) + { + glBindBuffer(GL_ARRAY_BUFFER, VAOManager::getInstance()->getInstanceBuffer(InstanceTypeGlow)); + GlowInstanceBuffer = (GlowInstanceData*)glMapBufferRange(GL_ARRAY_BUFFER, 0, 10000 * sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, GlowPassCmd::getInstance()->drawindirectcmd); + GlowCmdBuffer = (DrawElementsIndirectCommand*)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + } + + // Glow + if (irr_driver->hasARB_draw_indirect()) + GlowPassCmd::getInstance()->Offset = offset; // Store command buffer offset + + auto It = MeshForGlowPass.begin(), E = MeshForGlowPass.end(); + for (; It != E; ++It) + { + FillInstancesGlow_impl(It->second, GlowInstanceBuffer, GlowCmdBuffer, offset, current_cmd, playercamculling); + if (!UserConfigParams::m_azdo) + ListInstancedGlow::getInstance()->push_back(It->second.front().first); + } + + if (UserConfigParams::m_azdo) + GlowPassCmd::getInstance()->Size = current_cmd - GlowPassCmd::getInstance()->Offset; + + if (!irr_driver->hasBufferStorageExtension()) + { + glUnmapBuffer(GL_ARRAY_BUFFER); + glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); + } + } +#pragma omp section + { + irr_driver->setPhase(SHADOW_PASS); + + size_t offset = 0, current_cmd = 0; + if (!irr_driver->hasBufferStorageExtension()) + { + glBindBuffer(GL_ARRAY_BUFFER, VAOManager::getInstance()->getInstanceBuffer(InstanceTypeShadow)); + ShadowInstanceBuffer = (InstanceData*)glMapBufferRange(GL_ARRAY_BUFFER, 0, 10000 * sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, ShadowPassCmd::getInstance()->drawindirectcmd); + ShadowCmdBuffer = (DrawElementsIndirectCommand*)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + } + + for (unsigned i = 0; i < 4; i++) + { + // Mat default + GenDrawCalls<MAT_DEFAULT>(i, ListInstancedMatDefault::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly); + // Mat AlphaRef + GenDrawCalls<MAT_ALPHA_REF>(i, ListInstancedMatAlphaRef::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly); + // Mat Unlit + GenDrawCalls<MAT_UNLIT>(i, ListInstancedMatUnlit::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly); + // Mat NormalMap + GenDrawCalls<MAT_NORMAL_MAP>(i, ListInstancedMatNormalMap::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly); + // Mat Spheremap + GenDrawCalls<MAT_SPHEREMAP>(i, ListInstancedMatSphereMap::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly); + // Mat Detail + GenDrawCalls<MAT_DETAIL>(i, ListInstancedMatDetails::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, ShadowPoly); + // Mat Grass + GenDrawCallsGrass<MAT_GRASS>(i, ListInstancedMatGrass::getInstance()->Shadows[i], ShadowInstanceBuffer, ShadowCmdBuffer, offset, current_cmd, windDir, ShadowPoly); + } + if (!irr_driver->hasBufferStorageExtension()) + { + glUnmapBuffer(GL_ARRAY_BUFFER); + glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); + } + } +#pragma omp section + { + auto rsmcamculling = [](const scene::ISceneNode *nd) {return dynamic_cast<const STKMeshCommon*>(nd)->isCulledForRSMCam(); }; + size_t offset = 0, current_cmd = 0; + if (!irr_driver->hasBufferStorageExtension()) + { + glBindBuffer(GL_ARRAY_BUFFER, VAOManager::getInstance()->getInstanceBuffer(InstanceTypeRSM)); + RSMInstanceBuffer = (InstanceData*)glMapBufferRange(GL_ARRAY_BUFFER, 0, 10000 * sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, RSMPassCmd::getInstance()->drawindirectcmd); + RSMCmdBuffer = (DrawElementsIndirectCommand*)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + } + + // Default Material + RSMPassCmd::getInstance()->Offset[MAT_DEFAULT] = current_cmd; + FillInstances(MeshForRSMPass[MAT_DEFAULT], ListInstancedMatDefault::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling); + RSMPassCmd::getInstance()->Size[MAT_DEFAULT] = current_cmd - RSMPassCmd::getInstance()->Offset[MAT_DEFAULT]; + // Alpha Ref + RSMPassCmd::getInstance()->Offset[MAT_ALPHA_REF] = current_cmd; + FillInstances(MeshForRSMPass[MAT_ALPHA_REF], ListInstancedMatAlphaRef::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling); + RSMPassCmd::getInstance()->Size[MAT_ALPHA_REF] = current_cmd - RSMPassCmd::getInstance()->Offset[MAT_ALPHA_REF]; + // Unlit + RSMPassCmd::getInstance()->Offset[MAT_UNLIT] = current_cmd; + FillInstances(MeshForRSMPass[MAT_UNLIT], ListInstancedMatUnlit::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling); + RSMPassCmd::getInstance()->Size[MAT_UNLIT] = current_cmd - RSMPassCmd::getInstance()->Offset[MAT_UNLIT]; + // Detail + RSMPassCmd::getInstance()->Offset[MAT_DETAIL] = current_cmd; + FillInstances(MeshForRSMPass[MAT_DETAIL], ListInstancedMatDetails::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling); + RSMPassCmd::getInstance()->Size[MAT_DETAIL] = current_cmd - RSMPassCmd::getInstance()->Offset[MAT_DETAIL]; + // Normal Map + RSMPassCmd::getInstance()->Offset[MAT_NORMAL_MAP] = current_cmd; + FillInstances(MeshForRSMPass[MAT_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling); + RSMPassCmd::getInstance()->Size[MAT_NORMAL_MAP] = current_cmd - RSMPassCmd::getInstance()->Offset[MAT_NORMAL_MAP]; + + if (!irr_driver->hasBufferStorageExtension()) + { + glUnmapBuffer(GL_ARRAY_BUFFER); + glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); + } + } + } + PROFILER_POP_CPU_MARKER(); + poly_count[SOLID_NORMAL_AND_DEPTH_PASS] += SolidPoly; + poly_count[SHADOW_PASS] += ShadowPoly; + + glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT); +} \ No newline at end of file diff --git a/src/graphics/stkscenemanager.hpp b/src/graphics/stkscenemanager.hpp new file mode 100644 index 000000000..998fe2a72 --- /dev/null +++ b/src/graphics/stkscenemanager.hpp @@ -0,0 +1,68 @@ +// Not really a scene manager yet but hold algorithm that +// rework scene manager output + +#ifndef HEADER_STKSCENEMANAGER_HPP +#define HEADER_STKSCENEMANAGER_HPP + +#include "utils/singleton.hpp" +#include "gl_headers.hpp" +#include "stkmesh.hpp" +#include "gpuparticles.hpp" + +template<typename T> +class CommandBuffer : public Singleton<T> +{ +public: + GLuint drawindirectcmd; + DrawElementsIndirectCommand *Ptr; + CommandBuffer() + { + glGenBuffers(1, &drawindirectcmd); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, drawindirectcmd); +#ifdef Buffer_Storage + if (irr_driver->hasBufferStorageExtension()) + { + glBufferStorage(GL_DRAW_INDIRECT_BUFFER, 10000 * sizeof(DrawElementsIndirectCommand), 0, GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT); + Ptr = (DrawElementsIndirectCommand *)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT); + } + else +#endif + { + glBufferData(GL_DRAW_INDIRECT_BUFFER, 10000 * sizeof(DrawElementsIndirectCommand), 0, GL_STREAM_DRAW); + } + } +}; + +class ImmediateDrawList : public Singleton<ImmediateDrawList>, public std::vector<scene::ISceneNode *> +{}; + +class ParticlesList : public Singleton<ParticlesList>, public std::vector<ParticleSystemProxy *> +{}; + + +class SolidPassCmd : public CommandBuffer<SolidPassCmd> +{ +public: + size_t Offset[MAT_COUNT], Size[MAT_COUNT]; +}; + +class ShadowPassCmd : public CommandBuffer<ShadowPassCmd> +{ +public: + size_t Offset[4][MAT_COUNT], Size[4][MAT_COUNT]; +}; + +class RSMPassCmd : public CommandBuffer<RSMPassCmd> +{ +public: + size_t Offset[MAT_COUNT], Size[MAT_COUNT]; +}; + +class GlowPassCmd : public CommandBuffer<GlowPassCmd> +{ +public: + size_t Offset, Size; +}; + + +#endif \ No newline at end of file diff --git a/src/graphics/rain.cpp b/src/graphics/weather.cpp similarity index 54% rename from src/graphics/rain.cpp rename to src/graphics/weather.cpp index 3c9a75bd2..2f62e4f06 100644 --- a/src/graphics/rain.cpp +++ b/src/graphics/weather.cpp @@ -18,92 +18,80 @@ #include "audio/sfx_base.hpp" #include "audio/sfx_manager.hpp" -#include "graphics/camera.hpp" -#include "graphics/glwrap.hpp" -#include "graphics/gpuparticles.hpp" -#include "graphics/irr_driver.hpp" -#include "graphics/material_manager.hpp" -#include "graphics/material.hpp" -#include "graphics/per_camera_node.hpp" -#include "graphics/rain.hpp" -#include "graphics/shaders.hpp" +#include "graphics/weather.hpp" #include "modes/world.hpp" #include "states_screens/race_gui.hpp" -#include "utils/constants.hpp" #include "utils/random_generator.hpp" -#include <ISceneManager.h> -#include <SMeshBuffer.h> +// The weather manager -using namespace video; -using namespace scene; -using namespace core; - -// The rain manager - -Rain::Rain(Camera *camera, irr::scene::ISceneNode* parent) : m_thunder_sound(0) +Weather::Weather(bool lightning, std::string sound) { - m_lightning = camera->getIndex()==0; - + m_lightning = lightning; + m_thunder_sound = NULL; + m_weather_sound = NULL; + if (m_lightning) - m_thunder_sound = sfx_manager->createSoundSource("thunder"); + { + m_thunder_sound = sfx_manager->createSoundSource("thunder"); + } - Material* m = material_manager->getMaterial("rain.png"); - assert(m != NULL); + if (sound != "") + { + m_weather_sound = sfx_manager->createSoundSource(sound); + } RandomGenerator g; m_next_lightning = (float)g.get(35); - -// RainNode *node = new RainNode(irr_driver->getSceneManager(), m->getTexture()); -// m_node = irr_driver->addPerCameraNode(node, camera->getCameraSceneNode(), parent); -// m_node->setAutomaticCulling(0); -} // Rain +} // Weather // ---------------------------------------------------------------------------- -Rain::~Rain() +Weather::~Weather() { -// m_node->drop(); // drop STK's reference -// m_node->remove(); // Then remove it from the scene graph. - - if (m_lightning && m_thunder_sound != NULL) sfx_manager->deleteSFX(m_thunder_sound); + if (m_thunder_sound != NULL) + sfx_manager->deleteSFX(m_thunder_sound); + + if (m_weather_sound != NULL) + sfx_manager->deleteSFX(m_weather_sound); } // ---------------------------------------------------------------------------- -void Rain::update(float dt) +void Weather::update(float dt) { if (m_lightning) { m_next_lightning -= dt; - + if (m_next_lightning < 0.0f) { RaceGUIBase* gui_base = World::getWorld()->getRaceGUI(); + if (gui_base != NULL) { gui_base->doLightning(); - if (m_thunder_sound) m_thunder_sound->play(); - } + if (m_thunder_sound) + { + m_thunder_sound->play(); + } + } + RandomGenerator g; m_next_lightning = 35 + (float)g.get(35); } } - } // update // ---------------------------------------------------------------------------- -void Rain::setPosition(const core::vector3df& position) +void Weather::playSound() { -// m_node->getChild()->setPosition(position); -} // setPosition - -// ---------------------------------------------------------------------------- - -void Rain::setCamera(scene::ICameraSceneNode* camera) -{ -// m_node->setCamera(camera); + if (m_weather_sound) + { + m_weather_sound->setLoop(true); + m_weather_sound->play(); + } } diff --git a/src/graphics/rain.hpp b/src/graphics/weather.hpp similarity index 66% rename from src/graphics/rain.hpp rename to src/graphics/weather.hpp index b8408c2a8..d6fb1b135 100644 --- a/src/graphics/rain.hpp +++ b/src/graphics/weather.hpp @@ -16,38 +16,25 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#ifndef HEADER_RAIN_HPP -#define HEADER_RAIN_HPP - -class Camera; -class PerCameraNode; - -#include <vector3d.h> -namespace irr -{ - namespace video { class SMaterial; class ITexture; } - namespace scene { class ICameraSceneNode; class ISceneNode; } -} -using namespace irr; +#ifndef HEADER_WEATHER_HPP +#define HEADER_WEATHER_HPP class SFXBase; -class Rain +class Weather { - PerCameraNode* m_node; - - float m_next_lightning; bool m_lightning; + float m_next_lightning; + SFXBase* m_thunder_sound; + SFXBase* m_weather_sound; public: - Rain(Camera* camera, irr::scene::ISceneNode* parent); - virtual ~Rain(); + Weather(bool lightning, std::string sound); + virtual ~Weather(); void update(float dt); - void setPosition(const irr::core::vector3df& position); - - void setCamera(scene::ICameraSceneNode* camera); + void playSound(); }; #endif diff --git a/src/guiengine/engine.hpp b/src/guiengine/engine.hpp index 5dcfce20d..9669503c7 100644 --- a/src/guiengine/engine.hpp +++ b/src/guiengine/engine.hpp @@ -170,7 +170,7 @@ namespace GUIEngine inline Skin* getSkin() { return Private::g_skin; } Screen* getScreenNamed(const char* name); - + /** \return the height of the title font in pixels */ int getTitleFontHeight(); diff --git a/src/guiengine/widgets/button_widget.cpp b/src/guiengine/widgets/button_widget.cpp index feb18af83..01016b2be 100644 --- a/src/guiengine/widgets/button_widget.cpp +++ b/src/guiengine/widgets/button_widget.cpp @@ -43,6 +43,8 @@ void ButtonWidget::add() m_id = m_element->getID(); m_element->setTabOrder(m_id); m_element->setTabGroup(false); + if (!m_is_visible) + m_element->setVisible(false); } // ----------------------------------------------------------------------------- diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.cpp b/src/guiengine/widgets/dynamic_ribbon_widget.cpp index 0a3040068..c1d2c12d2 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.cpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.cpp @@ -491,6 +491,7 @@ void DynamicRibbonWidget::clearItems() { m_items.clear(); m_animated_contents = false; + m_scroll_offset = 0; } // ----------------------------------------------------------------------------- void DynamicRibbonWidget::elementRemoved() diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index 9432335ed..cc379cd7c 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -722,16 +722,34 @@ EventPropagation RibbonWidget::transmitEvent(Widget* w, // ---------------------------------------------------------------------------- void RibbonWidget::setLabel(const unsigned int id, irr::core::stringw new_name) { - // This method should only be called AFTER a widget is added - assert(m_element != NULL); + if (m_element == NULL) + { + // before adding + m_children[id].setText(new_name); + } + else + { + // after adding + // ignore this call for ribbons without labels + if (m_labels.size() == 0) return; + + assert(id < m_labels.size()); + m_labels[id].setText(new_name.c_str()); + //m_text = new_name; + } +} // setLabel + +// ---------------------------------------------------------------------------- + +void RibbonWidget::setItemVisible(const unsigned int id, bool visible) +{ + m_children[id].setVisible(visible); // ignore this call for ribbons without labels if (m_labels.size() == 0) return; - assert(id < m_labels.size()); - m_labels[id].setText( new_name.c_str() ); - m_text = new_name; -} // setLabel + m_labels[id].setVisible(visible); +} // RibbonWidget // ---------------------------------------------------------------------------- int RibbonWidget::findItemNamed(const char* internalName) diff --git a/src/guiengine/widgets/ribbon_widget.hpp b/src/guiengine/widgets/ribbon_widget.hpp index 5746b877a..f14558250 100644 --- a/src/guiengine/widgets/ribbon_widget.hpp +++ b/src/guiengine/widgets/ribbon_widget.hpp @@ -152,6 +152,8 @@ namespace GUIEngine */ void setLabel(const unsigned int id, irr::core::stringw new_name); + void setItemVisible(const unsigned int id, bool visible); + /** Returns the ID of the item, or -1 if not found */ int findItemNamed(const char* internalName); diff --git a/src/guiengine/widgets/spinner_widget.hpp b/src/guiengine/widgets/spinner_widget.hpp index 8b3e6c326..13496afc3 100644 --- a/src/guiengine/widgets/spinner_widget.hpp +++ b/src/guiengine/widgets/spinner_widget.hpp @@ -156,18 +156,34 @@ namespace GUIEngine /** * \return the maximum value the spinner can take */ - int getMax() const { return m_max; } - /** - * \brief Sets the maximum value for a spinner. - */ - void setMax(int n) {m_max = n; } + // -------------------------------------------------------------------- + /** Returns the maximum value. */ + int getMax() const { return m_max; } + // -------------------------------------------------------------------- + /** \brief Sets the maximum value for a spinner. + * If the current value is larger than the new maximum, the current + * value is set to the new maximum. */ + void setMax(int n) + { + m_max = n; + if(getValue()>m_max) setValue(m_max); + } // setMax + // -------------------------------------------------------------------- /** * \return the minimum value the spinner can take */ int getMin() const { return m_min; } + // -------------------------------------------------------------------- + /** \brief Sets the minimum value for a spinner. + * If the current value is smaller than the new minimum, the current + * value is set to the new minimum. */ + void setMin(int n) + { + m_min = n; + if(getValue()<m_min) setValue(m_min); + } // setMin - void setMin(int n) { m_min = n; } - + // -------------------------------------------------------------------- /** Override method from base class Widget */ virtual void setActivated(); diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp index 8520caf05..cacd7b563 100644 --- a/src/io/file_manager.cpp +++ b/src/io/file_manager.cpp @@ -151,7 +151,7 @@ FileManager::FileManager() if(exe_path.size()==0 || exe_path[exe_path.size()-1]!='/') exe_path += "/"; if ( getenv ( "SUPERTUXKART_DATADIR" ) != NULL ) - root_dir = std::string(getenv("SUPERTUXKART_DATADIR"))+"/" ; + root_dir = std::string(getenv("SUPERTUXKART_DATADIR"))+"/data/" ; #ifdef __APPLE__ else if( macSetBundlePathIfRelevant( root_dir ) ) { root_dir = root_dir + "data/"; } #endif @@ -175,7 +175,7 @@ FileManager::FileManager() else { #ifdef SUPERTUXKART_DATADIR - root_dir = SUPERTUXKART_DATADIR; + root_dir = SUPERTUXKART_DATADIR"/data/"; if(root_dir.size()==0 || root_dir[root_dir.size()-1]!='/') root_dir+='/'; @@ -187,6 +187,8 @@ FileManager::FileManager() addRootDirs(root_dir); if( fileExists(root_dir+"../../stk-assets")) addRootDirs(root_dir+"../../stk-assets"); + if( fileExists(root_dir+"../../supertuxkart-assets")) + addRootDirs(root_dir+"../../supertuxkart-assets"); if ( getenv ( "SUPERTUXKART_ROOT_PATH" ) != NULL ) addRootDirs(getenv("SUPERTUXKART_ROOT_PATH")); @@ -351,6 +353,25 @@ FileManager::~FileManager() m_file_system = NULL; } // ~FileManager +// ---------------------------------------------------------------------------- +/** Returns true if the specified file exists. + */ +bool FileManager::fileExists(const std::string& path) const +{ +#ifdef DEBUG + bool exists = m_file_system->existFile(path.c_str()); + if(exists) return true; + // Now the original file was not found. Test if replacing \ with / helps: + std::string s = StringUtils::replace(path, "\\", "/"); + exists = m_file_system->existFile(s.c_str()); + if(exists) + Log::warn("FileManager", "File '%s' does not exists, but '%s' does!", + path.c_str(), s.c_str()); + return exists; +#else + return m_file_system->existFile(path.c_str()); +#endif +} // fileExists //----------------------------------------------------------------------------- /** Adds paths to the list of stk root directories. * \param roots A ":" separated string of directories to add. @@ -718,10 +739,10 @@ void FileManager::checkAndCreateConfigDir() // Try to use the APPDATA directory to store config files and highscore // lists. If not defined, used the current directory. - if(getenv("APPDATA")!=NULL) + if (getenv("APPDATA") != NULL) { m_user_config_dir = getenv("APPDATA"); - if(!checkAndCreateDirectory(m_user_config_dir)) + if (!checkAndCreateDirectory(m_user_config_dir)) { Log::error("[FileManager]", "Can't create config dir '%s" ", falling back to '.'.", m_user_config_dir.c_str()); @@ -735,7 +756,7 @@ void FileManager::checkAndCreateConfigDir() #elif defined(__APPLE__) - if (getenv("HOME")!=NULL) + if (getenv("HOME") != NULL) { m_user_config_dir = getenv("HOME"); } @@ -755,8 +776,10 @@ void FileManager::checkAndCreateConfigDir() // Remaining unix variants. Use the new standards for config directory // i.e. either XDG_CONFIG_HOME or $HOME/.config - if (getenv("XDG_CONFIG_HOME")!=NULL){ + if (getenv("XDG_CONFIG_HOME") !=NULL) + { m_user_config_dir = getenv("XDG_CONFIG_HOME"); + checkAndCreateDirectory(m_user_config_dir); } else if (!getenv("HOME")) { @@ -768,6 +791,8 @@ void FileManager::checkAndCreateConfigDir() else { m_user_config_dir = getenv("HOME"); + checkAndCreateDirectory(m_user_config_dir); + m_user_config_dir += "/.config"; if(!checkAndCreateDirectory(m_user_config_dir)) { diff --git a/src/io/file_manager.hpp b/src/io/file_manager.hpp index 3983c9e49..40be73d76 100644 --- a/src/io/file_manager.hpp +++ b/src/io/file_manager.hpp @@ -133,6 +133,7 @@ public: std::string searchMusic(const std::string& file_name) const; std::string searchTexture(const std::string& fname) const; std::string getUserConfigFile(const std::string& fname) const; + bool fileExists(const std::string& path) const; void listFiles (std::set<std::string>& result, const std::string& dir, bool make_full_path=false) const; @@ -155,14 +156,6 @@ public: m_music_search_path.push_back(path); } // pushMusicSearchPath - // ------------------------------------------------------------------------ - /** Returns true if the specified file exists. - */ - bool fileExists(const std::string& path) const - { - return m_file_system->existFile(path.c_str()); - } // fileExists - }; // FileManager extern FileManager* file_manager; diff --git a/src/karts/abstract_kart.cpp b/src/karts/abstract_kart.cpp index 3ad73b442..0171d5043 100644 --- a/src/karts/abstract_kart.cpp +++ b/src/karts/abstract_kart.cpp @@ -122,3 +122,13 @@ void AbstractKart::setKartAnimation(AbstractKartAnimation *ka) assert( (ka!=NULL) ^ (m_kart_animation!=NULL) ); m_kart_animation = ka; } // setKartAnimation + +// ---------------------------------------------------------------------------- +/** Moves the current physical transform into this kart's position. + */ +void AbstractKart::kartIsInRestNow() +{ + // Update the kart transforms with the newly computed position + // after all karts are reset + setTrans(getBody()->getWorldTransform()); +} // kartIsInRest \ No newline at end of file diff --git a/src/karts/abstract_kart.hpp b/src/karts/abstract_kart.hpp index 7e681e418..5df0e817b 100644 --- a/src/karts/abstract_kart.hpp +++ b/src/karts/abstract_kart.hpp @@ -154,6 +154,12 @@ public: /** Returns the highest point of the kart (coordinate on up axis) */ float getHighestPoint() const { return m_kart_highest_point; } // ------------------------------------------------------------------------ + /** Called after the kart comes to rest. It can be used to e.g. compute + * differences between graphical and physical chassis. Note that + * overwriting this function is possible, but this implementation must + * be called. */ + virtual void kartIsInRestNow(); + // ------------------------------------------------------------------------ /** Returns true if this kart has no wheels. */ bool isWheeless() const; // ------------------------------------------------------------------------ diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index d97a2cf7a..b84ca215c 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -607,9 +607,32 @@ void Kart::createPhysics() { int index = (x + 1) / 2 + 1 - z; // get index of wheel float f = getKartProperties()->getPhysicalWheelPosition(); - wheel_pos[index] = p*(orig_factor*(1.0f-f) + bevel_factor*f); - wheel_pos[index].setY(0); - } // if z==-1 + // f < 0 indicates to use the old physics position, i.e. + // to place the wheels outside of the chassis + if(f<0) + { + // All wheel positions are relative to the center of + // the collision shape. + wheel_pos[index].setX(x*0.5f*getKartWidth()); + float radius = getKartProperties()->getWheelRadius(); + // The y position of the wheels (i.e. the points where + // the suspension is attached to) is just at the + // bottom of the kart. That is half the kart height + // down. The wheel radius is added to the suspension + // length in the physics, so we move the connection + // point 'radius' up. That means that if the suspension + // is fully compressed (0), the wheel will just be at + // the bottom of the kart chassis and touch the ground + wheel_pos[index].setY(- 0.5f*getKartHeight() + radius); + wheel_pos[index].setZ((0.5f*getKartLength() - radius)* z); + + } + else + { + wheel_pos[index] = p*(orig_factor*(1.0f - f) + bevel_factor*f); + wheel_pos[index].setY(0); + } + } // if y==-1 } // for x } // for z } // for y @@ -669,11 +692,12 @@ void Kart::createPhysics() tuning.m_maxSuspensionForce = m_kart_properties->getMaxSuspensionForce(); + const Vec3 &cs = getKartProperties()->getGravityCenterShift(); for(unsigned int i=0; i<4; i++) { bool is_front_wheel = i<2; btWheelInfo& wheel = m_vehicle->addWheel( - wheel_pos[i], + wheel_pos[i]+cs, wheel_direction, wheel_axle, suspension_rest, wheel_radius, tuning, is_front_wheel); wheel.m_suspensionStiffness = m_kart_properties->getSuspensionStiffness(); @@ -1741,9 +1765,9 @@ void Kart::crashed(const Material *m, const Vec3 &normal) impulse.normalize(); else impulse = Vec3(0, 0, -1); // Arbitrary - // impulse depends of kart speed - impulse *= 0.2f * m_body->getLinearVelocity().length(); - impulse *= m_kart_properties->getCollisionTerrainImpulse(); + // impulse depends of kart speed - and speed can be negative + impulse *= sqrt(fabsf(getSpeed())) + * m_kart_properties->getCollisionTerrainImpulse(); m_bounce_back_time = 0.2f; m_vehicle->setTimedCentralImpulse(0.1f, impulse); } @@ -2355,7 +2379,8 @@ void Kart::loadData(RaceManager::KartType type, bool is_animated_model) m_node, m_kart_properties->getShadowScale(), m_kart_properties->getShadowXOffset(), - m_kart_properties->getShadowYOffset()); + m_kart_properties->getGraphicalYOffset(), + m_kart_properties->getShadowZOffset()); World::getWorld()->kartAdded(this, m_node); } // loadData @@ -2386,6 +2411,31 @@ void Kart::applyEngineForce(float force) } } // applyEngineForce +//----------------------------------------------------------------------------- +/** Computes the transform of the graphical kart chasses with regards to the + * physical chassis. This function is called once the kart comes to rest + * before the race starts. Based on the current physical kart position, it + * computes an (at this stage Y-only) offset by which the graphical chassis + * is moved so that it appears the way it is designed in blender. This means + * that the distance of the wheels from the chassis (i.e. suspension) appears + * as in blender when karts are in rest. + */ +void Kart::kartIsInRestNow() +{ + AbstractKart::kartIsInRestNow(); + float f = 0; + for(int i=0; i<m_vehicle->getNumWheels(); i++) + { + const btWheelInfo &wi = m_vehicle->getWheelInfo(i); + f += wi.m_chassisConnectionPointCS.getY() + - wi.m_raycastInfo.m_suspensionLength - wi.m_wheelsRadius; + } + m_graphical_y_offset = f/m_vehicle->getNumWheels() + + getKartProperties()->getGraphicalYOffset(); + + m_kart_model->setDefaultSuspension(); +} // kartIsInRestNow + //----------------------------------------------------------------------------- /** Updates the graphics model. Mainly set the graphical position to be the * same as the physics position, but uses offsets to position and rotation @@ -2486,42 +2536,15 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz, } } - // Now determine graphical chassis and wheel position depending on - // the physics result. The center of gravity of the chassis is at the - // bottom of the chassis, but the position of the graphical chassis is at - // the bottom of the wheels (i.e. in blender the kart is positioned on - // the horizonal plane through (0,0,0)). So first determine how far - // above the terrain is the center of the physics body. If the minimum - // of those values is larger than the lowest point of the chassis model - // the kart chassis would be too high (and look odd), so in this case - // move the chassis down so that the wheels (when touching the ground) - // look close enough to the chassis. - float height_above_terrain[4]; - float min_hat = 9999.9f; - for(unsigned int i=0; i<4; i++) - { - // Set the suspension length - const btWheelInfo &wi = m_vehicle->getWheelInfo(i); - height_above_terrain[i] = wi.m_raycastInfo.m_suspensionLength; - if(height_above_terrain[i] < min_hat) min_hat = height_above_terrain[i]; - } - float kart_hat = m_kart_model->getLowestPoint(); - - if(min_hat >= kart_hat) - { - for(unsigned int i=0; i<4; i++) - height_above_terrain[i] = kart_hat; - } - m_kart_model->update(dt, m_wheel_rotation_dt, getSteerPercent(), - height_above_terrain, m_speed); + m_kart_model->update(dt, m_wheel_rotation_dt, getSteerPercent(), m_speed); // If the kart is leaning, part of the kart might end up 'in' the track. // To avoid this, raise the kart enough to offset the leaning. float lean_height = tan(fabsf(m_current_lean)) * getKartWidth()*0.5f; float heading = m_skidding->getVisualSkidRotation(); - Vec3 center_shift = Vec3(0, m_skidding->getGraphicalJumpOffset() - kart_hat - + lean_height-m_kart_model->getLowestPoint(), 0); + Vec3 center_shift = Vec3(0, m_skidding->getGraphicalJumpOffset() + + lean_height +m_graphical_y_offset, 0); center_shift = getTrans().getBasis() * center_shift; Moveable::updateGraphics(dt, center_shift, diff --git a/src/karts/kart.hpp b/src/karts/kart.hpp index 52c477b9d..087c510ab 100644 --- a/src/karts/kart.hpp +++ b/src/karts/kart.hpp @@ -66,13 +66,13 @@ class Kart : public AbstractKart friend class Skidding; private: /** Handles speed increase and capping due to powerup, terrain, ... */ - MaxSpeed *m_max_speed; + MaxSpeed *m_max_speed; /** Stores information about the terrain the kart is on. */ - TerrainInfo *m_terrain_info; + TerrainInfo *m_terrain_info; /** Handles the powerup of a kart. */ - Powerup *m_powerup; + Powerup *m_powerup; /** True if kart is flying (for debug purposes only). */ bool m_flying; @@ -106,6 +106,9 @@ private: * new lap is triggered. */ Vec3 m_xyz_front; + /** Offset of the graphical kart chassis from the physical chassis. */ + float m_graphical_y_offset; + /** True if the kart is eliminated. */ bool m_eliminated; @@ -234,6 +237,7 @@ public: int position, const btTransform& init_transform); virtual ~Kart(); virtual void init(RaceManager::KartType type); + virtual void kartIsInRestNow(); virtual void updateGraphics(float dt, const Vec3& off_xyz, const btQuaternion& off_rotation); virtual void createPhysics (); diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index 90ef13a5f..fe7e85e05 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -113,8 +113,8 @@ KartModel::KartModel(bool is_master) // default value for kart suspensions. move to config file later // if we find each kart needs custom values - m_min_suspension[i] = -0.59f; - m_max_suspension[i] = 0.59f; + m_min_suspension[i] = -0.07f; + m_max_suspension[i] = 0.20f; m_dampen_suspension_amplitude[i] = 2.5f; } m_wheel_filename[0] = ""; @@ -541,6 +541,14 @@ bool KartModel::loadModels(const KartProperties &kart_properties) } } + float y_off = kart_properties.getGraphicalYOffset(); + if(y_off!=0) + { + for (unsigned int i = 0; i < 4; i++) + m_wheel_graphics_position[i].setY( + m_wheel_graphics_position[i].getY() - y_off); + } + // Load the wheel models. This can't be done early, since the default // values for the graphical position must be defined, which in turn // depend on the size of the model. @@ -634,9 +642,7 @@ void KartModel::loadWheelInfo(const XMLNode &node, */ void KartModel::reset() { - // Reset the wheels - const float suspension[4]={0,0,0,0}; - update(0.0f, 0.0f, 0.0f, suspension, 0.0f); + update(0.0f, 0.0f, 0.0f, 0.0f); // Stop any animations currently being played. setAnimation(KartModel::AF_DEFAULT); @@ -741,6 +747,16 @@ void KartModel::OnAnimationEnd(scene::IAnimatedMeshSceneNode *node) m_animated_node->setAnimationEndCallback(NULL); } // OnAnimationEnd +// ---------------------------------------------------------------------------- +void KartModel::setDefaultSuspension() +{ + for(int i=0; i<m_kart->getVehicle()->getNumWheels(); i++) + { + const btWheelInfo &wi = m_kart->getVehicle()->getWheelInfo(i); + m_default_physics_suspension[i] = wi.m_raycastInfo.m_suspensionLength; + } +} // setDefaultSuspension + // ---------------------------------------------------------------------------- /** Rotates and turns the wheels appropriately, and adjust for suspension + updates the speed-weighted objects' animations. @@ -748,30 +764,35 @@ void KartModel::OnAnimationEnd(scene::IAnimatedMeshSceneNode *node) * \param rotation_dt How far the wheels have rotated since last time. * \param steer The actual steer settings. * \param suspension Suspension height for all four wheels. - * \param speed The speed of the kart in meters/sec, used for the speed-weighted objects' animations + * \param speed The speed of the kart in meters/sec, used for the + * speed-weighted objects' animations */ -void KartModel::update(float dt, float rotation_dt, float steer, - const float height_above_terrain[4], float speed) +void KartModel::update(float dt, float rotation_dt, float steer, float speed) { core::vector3df wheel_steer(0, steer*30.0f, 0); for(unsigned int i=0; i<4; i++) { if(!m_wheel_node[i]) continue; + const btWheelInfo &wi = m_kart->getVehicle()->getWheelInfo(i); #ifdef DEBUG if(UserConfigParams::m_physics_debug && m_kart) { // Make wheels that are not touching the ground invisible - bool wheel_has_contact = - m_kart->getVehicle()->getWheelInfo(i).m_raycastInfo - .m_isInContact; - m_wheel_node[i]->setVisible(wheel_has_contact); + m_wheel_node[i]->setVisible(wi.m_raycastInfo.m_isInContact); } #endif + float rel_suspension = wi.m_raycastInfo.m_suspensionLength + - m_default_physics_suspension[i]; + // If the suspension is too compressed + if(rel_suspension< m_min_suspension[i]) + rel_suspension = m_min_suspension[i]; + else if(rel_suspension > m_max_suspension[i]) + rel_suspension = m_max_suspension[i]; + core::vector3df pos = m_wheel_graphics_position[i].toIrrVector(); - // - pos.Y = - height_above_terrain[i] + m_kart_lowest_point - + m_wheel_graphics_radius[i]; + pos.Y -= rel_suspension; + m_wheel_node[i]->setPosition(pos); // Now calculate the new rotation: (old + change) mod 360 diff --git a/src/karts/kart_model.hpp b/src/karts/kart_model.hpp index 9d2138642..733fd8aba 100644 --- a/src/karts/kart_model.hpp +++ b/src/karts/kart_model.hpp @@ -169,12 +169,16 @@ private: /** The speed weighted objects. */ SpeedWeightedObjectList m_speed_weighted_objects; - /** Minimum suspension length. If the displayed suspension is - * shorter than this, the wheel would look wrong. */ + /** Length of the physics suspension when the kart is at rest. */ + float m_default_physics_suspension[4]; + + /** Minimum suspension length (i.e. most compressed). If the displayed + * suspension is shorter than this, the wheel would look wrong. */ float m_min_suspension[4]; - /** Maximum suspension length. If the displayed suspension is - * any longer, the wheel would look too far away from the chassis. */ + /** Maximum suspension length (i.e. most extended). If the displayed + * suspension is any longer, the wheel would look too far away from the + * chassis. */ float m_max_suspension[4]; /** value used to divide the visual movement of wheels (because the actual movement @@ -227,8 +231,9 @@ public: void reset(); void loadInfo(const XMLNode &node); bool loadModels(const KartProperties &kart_properties); + void setDefaultSuspension(); void update(float dt, float rotation_dt, float steer, - const float height_abve_terrain[4], float speed); + float speed); void finishedRace(); scene::ISceneNode* attachModel(bool animatedModels, bool always_animated); diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 9882e257b..a1598c4ed 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -57,7 +57,7 @@ KartProperties::KartProperties(const std::string &filename) m_shadow_file = ""; m_shadow_scale = 1.0f; m_shadow_x_offset = 0.0f; - m_shadow_y_offset = 0.0f; + m_shadow_z_offset = 0.0f; m_groups.clear(); m_custom_sfx_id.resize(SFXManager::NUM_CUSTOMS); @@ -92,7 +92,8 @@ KartProperties::KartProperties(const std::string &filename) m_squash_duration = m_downward_impulse_factor = m_bubblegum_fade_in_time = m_bubblegum_speed_fraction = m_bubblegum_time = m_bubblegum_torque = m_jump_animation_time = - m_smooth_flying_impulse = m_physical_wheel_position = + m_smooth_flying_impulse = m_physical_wheel_position = + m_graphical_y_offset = UNDEFINED; m_engine_power.resize(RaceManager::DIFFICULTY_COUNT, UNDEFINED); @@ -272,8 +273,15 @@ void KartProperties::load(const std::string &filename, const std::string &node) m_gravity_center_shift.setZ(0); } - //FIXME: magix 0.25 factor to keep it compatible with previous tourning - m_wheel_base = fabsf( m_kart_model->getLength()-0.25f); + if(m_physical_wheel_position < 0) + m_wheel_base = fabsf(m_kart_model->getLength() ); + else + { + // The new (atm unused) physical position results in steering to be + // not sharp enough - therefore decrease the wheel base somewhat to + // approximate the behaviour of the old steering. + m_wheel_base = fabsf(m_kart_model->getLength() - 0.25f); + } // Now convert the turn radius into turn angle: for(unsigned int i=0; i<m_turn_angle_at_speed.size(); i++) @@ -315,7 +323,7 @@ void KartProperties::getAllData(const XMLNode * root) root->get("shadow-scale", &m_shadow_scale ); root->get("shadow-x-offset", &m_shadow_x_offset ); - root->get("shadow-y-offset", &m_shadow_y_offset ); + root->get("shadow-z-offset", &m_shadow_z_offset ); root->get("type", &m_kart_type ); @@ -608,6 +616,11 @@ void KartProperties::getAllData(const XMLNode * root) startup_node->get("boost", &m_startup_boost); } + if(const XMLNode *graphics_node = root->getNode("graphics")) + { + graphics_node->get("y-offset", &m_graphical_y_offset); + } + if(m_kart_model) m_kart_model->loadInfo(*root); } // getAllData @@ -728,7 +741,7 @@ void KartProperties::checkAllSet(const std::string &filename) CHECK_NEG(m_explosion_invulnerability_time, "explosion invulnerability-time"); CHECK_NEG(m_explosion_radius, "explosion radius" ); - + CHECK_NEG(m_graphical_y_offset, "graphics y-offset" ); for(unsigned int i=RaceManager::DIFFICULTY_FIRST; i<=RaceManager::DIFFICULTY_LAST; i++) { diff --git a/src/karts/kart_properties.hpp b/src/karts/kart_properties.hpp index af99a7736..759675ab9 100644 --- a/src/karts/kart_properties.hpp +++ b/src/karts/kart_properties.hpp @@ -112,7 +112,7 @@ private: * for this kart.*/ float m_shadow_x_offset; /**< X offset of the shadow plane * for this kart.*/ - float m_shadow_y_offset; /**< Y offset of the shadow plane + float m_shadow_z_offset; /**< Z offset of the shadow plane * for this kart.*/ video::ITexture *m_shadow_texture;/**< The texture with the shadow. */ video::SColor m_color; /**< Color the represents the kart in the @@ -152,7 +152,11 @@ private: /** The position of the physical wheel is a weighted average of the * two ends of the beveled shape. This determines the weight: 0 = - * a the widest end, 1 = at the narrowest front end. */ + * a the widest end, 1 = at the narrowest front end. If the value is + * < 0, the old physics settings are used which places the raycast + * wheels outside of the chassis - but result in a more stable + * physics behaviour (which is therefore atm still the default). + */ float m_physical_wheel_position; /** Time a kart is moved upwards after when it is rescued. */ @@ -200,6 +204,10 @@ private: std::string m_wheel_filename[4]; /** Radius of the graphical wheels. */ float m_wheel_graphics_radius[4]; + /** An additional Y offset added to the y position of the graphical + * chassis. Useful for karts that don't have enough space for suspension + * compression. */ + float m_graphical_y_offset; /** If the kart is supposed to have random wheel rotation at start. */ bool m_has_rand_wheels; /** Max. length of plunger rubber band. */ @@ -564,6 +572,11 @@ public: /** Returns wheel radius. */ float getWheelRadius () const {return m_wheel_radius; } + // ------------------------------------------------------------------------ + /** Return the additional Y offset added to the y position of the graphical + * chassis. Useful for karts that don't have enough space for suspension + * compression. */ + float getGraphicalYOffset() const {return m_graphical_y_offset; } // ------------------------------------------------------------------------ /** Returns parameters for the speed-weighted objects */ const SpeedWeightedObject::Properties& getSpeedWeightedObjectProperties() const @@ -827,7 +840,7 @@ public: // ------------------------------------------------------------------------ /** Returns the scale factor by which the shadow plane * had to be set. */ - float getShadowYOffset () const {return m_shadow_y_offset; } + float getShadowZOffset () const {return m_shadow_z_offset; } // ------------------------------------------------------------------------ /** Returns a pointer to the skidding properties. */ @@ -916,7 +929,9 @@ public: // ------------------------------------------------------------------------ /** Returns position of the physical wheel is a weighted average of the * two ends of the beveled shape. This determines the weight: 0 = - * a the widest end, 1 = at the narrowest, front end. */ + * a the widest end, 1 = at the narrowest, front end. If the value is <0, + * the old physics position is picked, which placed the raycast wheels + * outside of the chassis, but gives more stable physics. */ const float getPhysicalWheelPosition() const { return m_physical_wheel_position; diff --git a/src/main.cpp b/src/main.cpp index 8bc70861a..05131c01b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -854,7 +854,7 @@ int handleCmdLine() Log::warn("main", "There is no GP named '%s'.", s.c_str()); return 0; } - race_manager->setGrandPrix(gp); + race_manager->setGrandPrix(*gp); } // --gp if(CommandLine::has("--numkarts", &n) ||CommandLine::has("-k", &n)) @@ -1155,8 +1155,12 @@ void askForInternetPermission() //============================================================================= -#if defined(DEBUG) && defined(WIN32) && !defined(__CYGWIN__) -#pragma comment(linker, "/SUBSYSTEM:console") +#if defined(WIN32) && defined(_MSC_VER) + #ifdef DEBUG + #pragma comment(linker, "/SUBSYSTEM:console") + #else + #pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup") + #endif #endif // ---------------------------------------------------------------------------- @@ -1436,7 +1440,6 @@ static void cleanSuperTuxKart() Referee::cleanup(); if(ReplayPlay::get()) ReplayPlay::destroy(); if(race_manager) delete race_manager; - if(addons_manager) delete addons_manager; if(grand_prix_manager) delete grand_prix_manager; if(highscore_manager) delete highscore_manager; if(attachment_manager) delete attachment_manager; @@ -1476,6 +1479,10 @@ static void cleanSuperTuxKart() } Online::RequestManager::deallocate(); + // The addons manager might still be called from a currenty running request + // in the request manager, so it can not be deleted earlier. + if(addons_manager) delete addons_manager; + // FIXME: do we need to wait for threads there, can they be // moved further up? Online::ServersManager::deallocate(); diff --git a/src/main_loop.cpp b/src/main_loop.cpp index a24789f70..3052c9ed8 100644 --- a/src/main_loop.cpp +++ b/src/main_loop.cpp @@ -160,8 +160,6 @@ void MainLoop::run() PROFILER_PUSH_CPU_MARKER("Database polling update", 0x00, 0x7F, 0x7F); Online::RequestManager::get()->update(dt); PROFILER_POP_CPU_MARKER(); - - PROFILER_SYNC_FRAME(); } else if (!m_abort && ProfileWorld::isNoGraphics()) { @@ -174,8 +172,8 @@ void MainLoop::run() PROFILER_POP_CPU_MARKER(); } - PROFILER_SYNC_FRAME(); PROFILER_POP_CPU_MARKER(); + PROFILER_SYNC_FRAME(); } // while !m_abort } // run diff --git a/src/modes/world.cpp b/src/modes/world.cpp index a25fc6764..62c3807eb 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -122,6 +122,7 @@ World::World() : WorldStatus(), m_clear_color(255,100,101,140) m_self_destruct = false; m_schedule_tutorial = false; m_is_network_world = false; + m_weather = NULL; m_stop_music_when_dialog_open = true; @@ -197,6 +198,12 @@ void World::init() ReplayPlay::get()->Load(); powerup_manager->updateWeightsForRace(num_karts); + + if (UserConfigParams::m_weather_effects) + { + m_weather = new Weather(m_track->getWeatherLightning(), + m_track->getWeatherSound()); + } } // init //----------------------------------------------------------------------------- @@ -264,7 +271,6 @@ void World::reset() //Reset the Rubber Ball Collect Time to some negative value. powerup_manager->setBallCollectTime(-100); - } // reset //----------------------------------------------------------------------------- @@ -378,6 +384,9 @@ World::~World() // gui and this must be deleted. delete m_race_gui; } + + if (m_weather != NULL) + delete m_weather; for ( unsigned int i = 0 ; i < m_karts.size() ; i++ ) delete m_karts[i]; @@ -393,6 +402,8 @@ World::~World() music_manager->stopMusic(); m_world = NULL; + irr_driver->getSceneManager()->clear(); + #ifdef DEBUG m_magic_number = 0xDEADBEEF; #endif @@ -679,9 +690,7 @@ void World::resetAllKarts() for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++) { - // Update the kart transforms with the newly computed position - // after all karts are reset - (*i)->setTrans((*i)->getBody()->getWorldTransform()); + (*i)->kartIsInRestNow(); } // Initialise the cameras, now that the correct kart positions are set @@ -801,6 +810,7 @@ void World::updateWorld(float dt) } catch (AbortWorldUpdateException& e) { + (void)e; // avoid compiler warning return; } @@ -926,6 +936,11 @@ void World::update(float dt) { Camera::getCamera(i)->update(dt); } + + if (UserConfigParams::m_graphical_effects && m_weather) + { + m_weather->update(dt); + } projectile_manager->update(dt); diff --git a/src/modes/world.hpp b/src/modes/world.hpp index c81cfdf0e..31ff045ec 100644 --- a/src/modes/world.hpp +++ b/src/modes/world.hpp @@ -28,6 +28,7 @@ #include <vector> #include <stdexcept> +#include "graphics/weather.hpp" #include "modes/world_status.hpp" #include "race/highscores.hpp" #include "states_screens/race_gui_base.hpp" @@ -169,6 +170,10 @@ protected: /** Set when the world is online and counts network players. */ bool m_is_network_world; + + /** Used to show weather graphical effects. */ + Weather* m_weather; + virtual void onGo(); /** Returns true if the race is over. Must be defined by all modes. */ @@ -356,6 +361,9 @@ public: void setNetworkWorld(bool is_networked) { m_is_network_world = is_networked; } bool isNetworkWorld() const { return m_is_network_world; } + + /** Returns a pointer to the weather. */ + Weather* getWeather() {return m_weather;} }; // World #endif diff --git a/src/modes/world_status.cpp b/src/modes/world_status.cpp index 29775834e..c7a841f89 100644 --- a/src/modes/world_status.cpp +++ b/src/modes/world_status.cpp @@ -44,7 +44,9 @@ WorldStatus::WorldStatus() m_play_racestart_sounds = true; IrrlichtDevice *device = irr_driver->getDevice(); - if (device->getTimer()->isStopped()) device->getTimer()->start(); + + if (device->getTimer()->isStopped()) + device->getTimer()->start(); } // WorldStatus //----------------------------------------------------------------------------- @@ -56,13 +58,15 @@ void WorldStatus::reset() m_auxiliary_timer = 0.0f; // Using SETUP_PHASE will play the track into sfx first, and has no // other side effects. - m_phase = UserConfigParams::m_race_now ? RACE_PHASE : SETUP_PHASE; + m_phase = UserConfigParams::m_race_now ? RACE_PHASE : SETUP_PHASE; m_previous_phase = UNDEFINED_PHASE; // Just in case that the game is reset during the intro phase m_track_intro_sound->stop(); IrrlichtDevice *device = irr_driver->getDevice(); - if (device->getTimer()->isStopped()) device->getTimer()->start(); + + if (device->getTimer()->isStopped()) + device->getTimer()->start(); } // reset //----------------------------------------------------------------------------- @@ -74,7 +78,9 @@ WorldStatus::~WorldStatus() sfx_manager->deleteSFX(m_start_sound); sfx_manager->deleteSFX(m_track_intro_sound); IrrlichtDevice *device = irr_driver->getDevice(); - if (device->getTimer()->isStopped()) device->getTimer()->start(); + + if (device->getTimer()->isStopped()) + device->getTimer()->start(); } // ~WorldStatus //----------------------------------------------------------------------------- @@ -96,14 +102,12 @@ void WorldStatus::setClockMode(const ClockType mode, const float initial_time) void WorldStatus::enterRaceOverState() { // Don't enter race over if it's already race over - if( m_phase == DELAY_FINISH_PHASE - || m_phase == RESULT_DISPLAY_PHASE - || m_phase == FINISH_PHASE ) + if (m_phase == DELAY_FINISH_PHASE || m_phase == RESULT_DISPLAY_PHASE || + m_phase == FINISH_PHASE) return; m_phase = DELAY_FINISH_PHASE; m_auxiliary_timer = 0.0f; - } // enterRaceOverState //----------------------------------------------------------------------------- @@ -120,7 +124,7 @@ void WorldStatus::terminateRace() */ void WorldStatus::update(const float dt) { - switch(m_phase) + switch (m_phase) { // Note: setup phase must be a separate phase, since the race_manager // checks the phase when updating the camera: in the very first time @@ -130,10 +134,17 @@ void WorldStatus::update(const float dt) case SETUP_PHASE: m_auxiliary_timer = 0.0f; m_phase = TRACK_INTRO_PHASE; + if (m_play_racestart_sounds) { m_track_intro_sound->play(); } + + if (World::getWorld()->getWeather() != NULL) + { + World::getWorld()->getWeather()->playSound(); + } + return; case TRACK_INTRO_PHASE: m_auxiliary_timer += dt; @@ -141,7 +152,9 @@ void WorldStatus::update(const float dt) if (UserConfigParams::m_artist_debug_mode && race_manager->getNumberOfKarts() == 1 && race_manager->getTrackName() != "tutorial") + { m_auxiliary_timer += dt * 6; + } // Work around a bug that occurred on linux once: // the sfx_manager kept on reporting that it is playing, @@ -149,61 +162,86 @@ void WorldStatus::update(const float dt) // ... phase. Since the sound effect is about 3 seconds // long, we use the aux timer to force the next phase // after 3.5 seconds. - if(m_track_intro_sound->getStatus()==SFXManager::SFX_PLAYING - && m_auxiliary_timer<3.5f) + if (m_track_intro_sound->getStatus() == SFXManager::SFX_PLAYING && + m_auxiliary_timer < 3.5f) return; + // Wait before ready phase if sounds are disabled - if(!UserConfigParams::m_sfx && m_auxiliary_timer<3.0f) + if (!UserConfigParams::m_sfx && m_auxiliary_timer < 3.0f) return; + m_auxiliary_timer = 0.0f; - if (m_play_racestart_sounds) m_prestart_sound->play(); + + if (m_play_racestart_sounds) + m_prestart_sound->play(); + m_phase = READY_PHASE; - for(unsigned int i=0; i<World::getWorld()->getNumKarts(); i++) + + for (unsigned int i = 0; i < World::getWorld()->getNumKarts(); i++) + { World::getWorld()->getKart(i)->startEngineSFX(); + } break; case READY_PHASE: - if(m_auxiliary_timer>1.0) + if (m_auxiliary_timer > 1.0) { - if (m_play_racestart_sounds) m_prestart_sound->play(); - m_phase=SET_PHASE; + if (m_play_racestart_sounds) + { + m_prestart_sound->play(); + } + + m_phase = SET_PHASE; } + m_auxiliary_timer += dt; // In artist debug mode, when without opponents, skip the ready/set/go counter faster if (UserConfigParams::m_artist_debug_mode && race_manager->getNumberOfKarts() == 1 && race_manager->getTrackName() != "tutorial") + { m_auxiliary_timer += dt*6; + } + return; - case SET_PHASE : - if(m_auxiliary_timer>2.0) + case SET_PHASE: + if (m_auxiliary_timer > 2.0) { // set phase is over, go to the next one - m_phase=GO_PHASE; - if (m_play_racestart_sounds) m_start_sound->play(); + m_phase = GO_PHASE; + if (m_play_racestart_sounds) + { + m_start_sound->play(); + } World::getWorld()->getTrack()->startMusic(); // event onGo(); } + m_auxiliary_timer += dt; // In artist debug mode, when without opponents, skip the ready/set/go counter faster if (UserConfigParams::m_artist_debug_mode && race_manager->getNumberOfKarts() == 1 && race_manager->getTrackName() != "tutorial") + { m_auxiliary_timer += dt*6; + } + return; case GO_PHASE : if (m_auxiliary_timer>2.5f && music_manager->getCurrentMusic()) - music_manager->startMusic(music_manager->getCurrentMusic()); - - if(m_auxiliary_timer>3.0f) // how long to display the 'go' message { - m_phase=MUSIC_PHASE; + music_manager->startMusic(music_manager->getCurrentMusic()); + } + + if (m_auxiliary_timer > 3.0f) // how long to display the 'go' message + { + m_phase = MUSIC_PHASE; } m_auxiliary_timer += dt; @@ -212,31 +250,38 @@ void WorldStatus::update(const float dt) if (UserConfigParams::m_artist_debug_mode && race_manager->getNumberOfKarts() == 1 && race_manager->getTrackName() != "tutorial") + { m_auxiliary_timer += dt*6; + } + break; case MUSIC_PHASE: // how long to display the 'music' message - if(m_auxiliary_timer>stk_config->m_music_credit_time) - m_phase=RACE_PHASE; + if (m_auxiliary_timer>stk_config->m_music_credit_time) + { + m_phase = RACE_PHASE; + } + m_auxiliary_timer += dt; break; case RACE_PHASE: // Nothing to do for race phase, switch to delay finish phase // happens when break; - case DELAY_FINISH_PHASE : + case DELAY_FINISH_PHASE: { m_auxiliary_timer += dt; // Change to next phase if delay is over - if(m_auxiliary_timer > stk_config->m_delay_finish_time) + if (m_auxiliary_timer > stk_config->m_delay_finish_time) { m_phase = RESULT_DISPLAY_PHASE; terminateRace(); } + break; } - case RESULT_DISPLAY_PHASE : + case RESULT_DISPLAY_PHASE: { break; } @@ -249,7 +294,7 @@ void WorldStatus::update(const float dt) default: break; } - switch(m_clock_mode) + switch (m_clock_mode) { case CLOCK_CHRONO: m_time += dt; @@ -290,11 +335,14 @@ void WorldStatus::setTime(const float time) */ void WorldStatus::pause(Phase phase) { - assert(m_previous_phase==UNDEFINED_PHASE); + assert(m_previous_phase == UNDEFINED_PHASE); + m_previous_phase = m_phase; m_phase = phase; IrrlichtDevice *device = irr_driver->getDevice(); - if (!device->getTimer()->isStopped()) device->getTimer()->stop(); + + if (!device->getTimer()->isStopped()) + device->getTimer()->stop(); } // pause //----------------------------------------------------------------------------- @@ -307,5 +355,7 @@ void WorldStatus::unpause() // in pause to detect incorrect pause/unpause sequences. m_previous_phase = UNDEFINED_PHASE; IrrlichtDevice *device = irr_driver->getDevice(); - if (device->getTimer()->isStopped()) device->getTimer()->start(); + + if (device->getTimer()->isStopped()) + device->getTimer()->start(); } // unpause diff --git a/src/network/client_network_manager.cpp b/src/network/client_network_manager.cpp index dbd8e34b5..ee9a5abc0 100644 --- a/src/network/client_network_manager.cpp +++ b/src/network/client_network_manager.cpp @@ -117,7 +117,10 @@ ClientNetworkManager::ClientNetworkManager() ClientNetworkManager::~ClientNetworkManager() { - pthread_cancel(*m_thread_keyboard); + // On windows in release mode there is no console, and the + // thread is not created. + if(m_thread_keyboard) + pthread_cancel(*m_thread_keyboard); } void ClientNetworkManager::run() @@ -133,10 +136,17 @@ void ClientNetworkManager::run() Log::info("ClientNetworkManager", "Host initialized."); + // On windows in release mode the console is suppressed, so nothing can + // be read from std::cin. Since getline(std::cin,...) then returns + // an empty string, the waitInput thread is running all the time, consuming + // CPU. Therefore don't start the console thread in this case. +#if defined(WIN32) && defined(_MSC_VER) && !defined(DEBUG) + m_thread_keyboard = NULL; +#else // listen keyboard console input m_thread_keyboard = (pthread_t*)(malloc(sizeof(pthread_t))); pthread_create(m_thread_keyboard, NULL, waitInput, NULL); - +#endif NetworkManager::run(); Log::info("ClientNetworkManager", "Ready !"); diff --git a/src/network/protocols/get_public_address.cpp b/src/network/protocols/get_public_address.cpp index 33379e71b..8e4095065 100644 --- a/src/network/protocols/get_public_address.cpp +++ b/src/network/protocols/get_public_address.cpp @@ -28,6 +28,11 @@ #include "utils/random_generator.hpp" #include <assert.h> + +#ifdef __MINGW32__ +# define _WIN32_WINNT 0x501 +#endif + #ifdef WIN32 # include <winsock2.h> # include <ws2tcpip.h> @@ -36,6 +41,7 @@ #endif #include <sys/types.h> + int stunRand() { static bool init = false; diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index aef89c96f..e22a8fcb3 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -24,9 +24,16 @@ #include "utils/time.hpp" #include <string.h> -#ifdef WIN32 +#if defined(WIN32) && !defined(__MINGW32__) # include "Ws2tcpip.h" # define inet_ntop InetNtop + +// TODO: It's very ugly hack which allows to compile STK on windows using gcc. +// Solution would be nice seen. +#elif defined(__MINGW32__) +# include "Ws2tcpip.h" +# define inet_ntop + #else # include <arpa/inet.h> # include <errno.h> diff --git a/src/online/request.cpp b/src/online/request.cpp index 48919a159..b3d919242 100644 --- a/src/online/request.cpp +++ b/src/online/request.cpp @@ -60,9 +60,14 @@ namespace Online void Request::execute() { assert(isBusy()); + // Abort as early as possible if abort is requested + if(RequestManager::get()->getAbort()) return; prepareOperation(); + if(RequestManager::get()->getAbort()) return; operation(); + if(RequestManager::get()->getAbort()) return; setExecuted(); + if(RequestManager::get()->getAbort()) return; afterOperation(); } // execute diff --git a/src/online/request_manager.cpp b/src/online/request_manager.cpp index 7dea5ab8e..a8ab28ee5 100644 --- a/src/online/request_manager.cpp +++ b/src/online/request_manager.cpp @@ -221,7 +221,9 @@ namespace Online me->m_request_queue.unlock(); me->m_current_request->execute(); - me->addResult(me->m_current_request); + // This test is necessary in case that execute() was aborted + // (otherwise the assert in addResult will be triggered). + if (!me->getAbort()) me->addResult(me->m_current_request); me->m_request_queue.lock(); } // while handle all requests diff --git a/src/patch b/src/patch deleted file mode 100644 index 937f74c5b..000000000 --- a/src/patch +++ /dev/null @@ -1,66 +0,0 @@ -diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp -index f9d6cd9..f243d2a 100644 ---- a/src/karts/kart.cpp -+++ b/src/karts/kart.cpp -@@ -1098,7 +1098,7 @@ void Kart::update(float dt) - - // TODO: hiker said this probably will be moved to btKart or so when updating bullet engine. - // Neutralize any yaw change if the kart leaves the ground, so the kart falls more or less -- // straight after jumping, but still allowing some "boat shake" (roll and pitch). -+ // straight after jumping, but still allowing some "boat shake" (roIll and pitch). - // Otherwise many non perfect jumps end in a total roll over or a serious change of - // direction, sometimes 90 or even full U turn (real but less fun for a karting game). - // As side effect steering becames a bit less responsive (any wheel on air), but not too bad. -@@ -2023,30 +2023,6 @@ void Kart::updatePhysics(float dt) - m_max_speed->setMinSpeed(min_speed); - m_max_speed->update(dt); - -- // If the kart is flying, keep its up-axis aligned to gravity (which in -- // turn typically means the kart is parallel to the ground). This avoids -- // that the kart rotates in mid-air and lands on its side. -- if(m_vehicle->getNumWheelsOnGround()==0) -- { -- btVector3 kart_up = getTrans().getBasis().getColumn(1); // up vector -- btVector3 terrain_up = m_body->getGravity(); -- float g = World::getWorld()->getTrack()->getGravity(); -- // Normalize the gravity, g is the length of the vector -- btVector3 new_up = 0.9f * kart_up + 0.1f * terrain_up/-g; -- // Get the rotation (hpr) based on current heading. -- Vec3 rotation(getHeading(), new_up); -- btMatrix3x3 m; -- m.setEulerZYX(rotation.getX(), rotation.getY(), rotation.getZ()); -- // We can't use getXYZ() for the position here, since the position is -- // based on interpolation, while the actual center-of-mass-transform -- // is based on the actual value every 1/60 of a second (using getXYZ() -- // would result in the kart being pushed ahead a bit, making it jump -- // much further, depending on fps) -- btTransform new_trans(m, m_body->getCenterOfMassTransform().getOrigin()); -- //setTrans(new_trans); -- m_body->setCenterOfMassTransform(new_trans); -- } -- - // To avoid tunneling (which can happen on long falls), clamp the - // velocity in Y direction. Tunneling can happen if the Y velocity - // is larger than the maximum suspension travel (per frame), since then -diff --git a/src/physics/btKart.cpp b/src/physics/btKart.cpp -index bdb8f55..2aa0096 100644 ---- a/src/physics/btKart.cpp -+++ b/src/physics/btKart.cpp -@@ -387,6 +387,17 @@ void btKart::updateVehicle( btScalar step ) - if(m_wheelInfo[i].m_raycastInfo.m_isInContact) - m_num_wheels_on_ground++; - } -+ -+ // If the kart is flying, try to keep it parallel to the ground. -+ if(m_num_wheels_on_ground==0) -+ { -+ btVector3 kart_up = getChassisWorldTransform().getBasis().getColumn(1); -+ btVector3 terrain_up(0,1,0); -+ btVector3 axis = kart_up.cross(terrain_up); -+ // Times 10 gives a nicely balanced feeling. -+ m_chassisBody->applyTorqueImpulse(axis * 10); -+ } -+ - // Work around: make sure that either both wheels on one axis - // are on ground, or none of them. This avoids the problem of - // the kart suddenly getting additional angular velocity because diff --git a/src/physics/irr_debug_drawer.hpp b/src/physics/irr_debug_drawer.hpp index b384f12bd..6dc54d4ed 100644 --- a/src/physics/irr_debug_drawer.hpp +++ b/src/physics/irr_debug_drawer.hpp @@ -20,8 +20,8 @@ #define HEADER_IRR_DEBUG_DRAWER_HPP #include "btBulletDynamicsCommon.h" -#include "graphics/glwrap.hpp" +#include <SColor.h> #include "utils/vec3.hpp" #include <map> #include <vector> diff --git a/src/physics/physical_object.cpp b/src/physics/physical_object.cpp index e80a6c1cd..539f9c13d 100644 --- a/src/physics/physical_object.cpp +++ b/src/physics/physical_object.cpp @@ -25,7 +25,6 @@ using namespace irr; #include "graphics/material_manager.hpp" #include "graphics/mesh_tools.hpp" -#include "graphics/stkinstancedscenenode.hpp" #include "io/file_manager.hpp" #include "io/xml_node.hpp" #include "modes/world.hpp" @@ -242,16 +241,6 @@ void PhysicalObject::init() Log::fatal("PhysicalObject", "Unknown node type"); } } - else if (dynamic_cast<TrackObjectPresentationInstancing*>(presentation) != NULL) - { - TrackObjectPresentationInstancing* instancing = dynamic_cast<TrackObjectPresentationInstancing*>(presentation); - STKInstancedSceneNode* instancing_group = instancing->getInstancingGroup(); - if (instancing_group != NULL) - { - scene::IMesh* mesh = instancing_group->getMesh(); - MeshTools::minMax3D(mesh, &min, &max); - } - } else { Log::fatal("PhysicalObject", "Unknown node type"); diff --git a/src/race/grand_prix_data.cpp b/src/race/grand_prix_data.cpp index b4d058e15..32faafa9b 100644 --- a/src/race/grand_prix_data.cpp +++ b/src/race/grand_prix_data.cpp @@ -24,7 +24,6 @@ #include "config/player_manager.hpp" #include "io/file_manager.hpp" #include "io/utf_writer.hpp" -#include "states_screens/dialogs/random_gp_dialog.hpp" #include "tracks/track_manager.hpp" #include "tracks/track.hpp" #include "utils/string_utils.hpp" @@ -81,45 +80,56 @@ void GrandPrixData::createRandomGP(const unsigned int number_of_tracks, changeTrackNumber(number_of_tracks, track_group); changeReverse(use_reverse); -} +} // createRandomGP // ---------------------------------------------------------------------------- +/** Either adds or removes tracks to get the requested numder of tracks in + * a random GP. + * \param number_of_tracks How many tracks should be in the random list. + * \param track_group From which group to select the tracks. + */ void GrandPrixData::changeTrackNumber(const unsigned int number_of_tracks, const std::string& track_group) { // The problem with the track groups is that "all" isn't a track group // TODO: Add "all" to the track groups and rewrite this more elegant std::vector<int> track_indices; - size_t available_tracks; if (track_group == "all") { - available_tracks = track_manager->getNumberOfTracks(); + for(unsigned int i=0; i<track_manager->getNumberOfTracks(); i++) + { + const Track *track = track_manager->getTrack(i); + // Ignore no-racing tracks: + if(!track->isRaceTrack()) + continue; + + // Only add tracks that are not already picked. + if(std::find(m_tracks.begin(), m_tracks.end(), track->getIdent())== + m_tracks.end()) + track_indices.push_back(i); + } } else { track_indices = track_manager->getTracksInGroup(track_group); - available_tracks = track_indices.size(); } - assert(number_of_tracks <= available_tracks); + assert(number_of_tracks <= track_indices.size() + m_tracks.size()); // add or remove the right number of tracks if (m_tracks.size() < number_of_tracks) { while (m_tracks.size() < number_of_tracks) { - int index = (track_group == "all") ? - rand() % available_tracks : - track_indices[rand() % available_tracks]; + int index = rand() % track_indices.size(); + int track_index = track_indices[index]; - const Track *track = track_manager->getTrack(index); + const Track *track = track_manager->getTrack(track_index); std::string id = track->getIdent(); - // Avoid duplicate tracks - if (std::find(m_tracks.begin(), m_tracks.end(), id) != m_tracks.end()) - continue; m_tracks.push_back(id); m_laps.push_back(track->getDefaultNumberOfLaps()); m_reversed.push_back(false); // This will be changed later in the code + track_indices.erase(track_indices.begin()+index); } } else if (m_tracks.size() > number_of_tracks) @@ -134,7 +144,7 @@ void GrandPrixData::changeTrackNumber(const unsigned int number_of_tracks, assert(m_tracks.size() == m_laps.size() ); assert(m_laps.size() == m_reversed.size()); -} +} // changeTrackNumber // ---------------------------------------------------------------------------- /** Updates the GP data with newly decided reverse requirements. diff --git a/src/race/grand_prix_data.hpp b/src/race/grand_prix_data.hpp index ea8422e43..36530b84c 100644 --- a/src/race/grand_prix_data.hpp +++ b/src/race/grand_prix_data.hpp @@ -135,6 +135,9 @@ public: /** @return the internal indentifier of the Grand Prix (not translated) */ const std::string& getId() const { return m_id; } + // ------------------------------------------------------------------------ + /** Returns true if this GP is a random GP. */ + bool isRandomGP() const { return m_id=="random"; } // ------------------------------------------------------------------------ /** Returns the filename of the grand prix xml file. */ const std::string& getFilename() const { return m_filename; } diff --git a/src/race/grand_prix_manager.hpp b/src/race/grand_prix_manager.hpp index d4800204a..5eabbb719 100644 --- a/src/race/grand_prix_manager.hpp +++ b/src/race/grand_prix_manager.hpp @@ -45,8 +45,6 @@ private: /** Generates a new unique indentifier for a user defined grand prix */ std::string generateId(); - bool existsName(const irr::core::stringw& name) const; - public: GrandPrixManager(); ~GrandPrixManager(); @@ -54,6 +52,7 @@ public: GrandPrixData* getGrandPrix(const int i) const { return m_gp_data[i]; } GrandPrixData* getGrandPrix(const std::string& s) const; unsigned int getNumberOfGrandPrix() const { return m_gp_data.size(); } + bool existsName(const irr::core::stringw& name) const; void checkConsistency(); // Methods for the gp editor diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 2626530b4..07362e7c8 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -46,6 +46,7 @@ #include "network/protocol_manager.hpp" #include "network/network_world.hpp" #include "network/protocols/start_game_protocol.hpp" +#include "states_screens/grand_prix_cutscene.hpp" #include "states_screens/grand_prix_lose.hpp" #include "states_screens/grand_prix_win.hpp" #include "states_screens/kart_selection.hpp" @@ -678,16 +679,17 @@ void RaceManager::exitRace(bool delete_world) } } + if (delete_world) World::deleteWorld(); + delete_world = false; + + StateManager::get()->enterGameState(); + race_manager->setMinorMode(RaceManager::MINOR_MODE_CUTSCENE); + race_manager->setNumKarts(0); + race_manager->setNumPlayers(0); + race_manager->setNumLocalPlayers(0); + if (someHumanPlayerWon) { - if (delete_world) World::deleteWorld(); - delete_world = false; - - StateManager::get()->enterGameState(); - race_manager->setMinorMode(RaceManager::MINOR_MODE_CUTSCENE); - race_manager->setNumKarts(0); - race_manager->setNumPlayers(0); - race_manager->setNumLocalPlayers(0); race_manager->startSingleRace("gpwin", 999, false); GrandPrixWin* scene = GrandPrixWin::getInstance(); StateManager::get()->pushScreen(scene); @@ -695,14 +697,6 @@ void RaceManager::exitRace(bool delete_world) } else { - if (delete_world) World::deleteWorld(); - delete_world = false; - - StateManager::get()->enterGameState(); - race_manager->setMinorMode(RaceManager::MINOR_MODE_CUTSCENE); - race_manager->setNumKarts(0); - race_manager->setNumPlayers(0); - race_manager->setNumLocalPlayers(0); race_manager->startSingleRace("gplose", 999, false); GrandPrixLose* scene = GrandPrixLose::getInstance(); StateManager::get()->pushScreen(scene); @@ -713,7 +707,8 @@ void RaceManager::exitRace(bool delete_world) } else { - std::cerr << "RaceManager::exitRace() : what's going on?? no winners and no losers??\n"; + Log::error("RaceManager", "There are no winners and no losers." + "This should have never happend\n"); std::vector<std::string> karts; karts.push_back(UserConfigParams::m_default_kart); scene->setKarts(karts); @@ -767,12 +762,9 @@ void RaceManager::rerunRace() //----------------------------------------------------------------------------- -void RaceManager::startGP(const GrandPrixData* gp, bool from_overworld, +void RaceManager::startGP(const GrandPrixData &gp, bool from_overworld, bool continue_saved_gp) { - assert(gp != NULL); - //std::cout << gp->getId(); - StateManager::get()->enterGameState(); setGrandPrix(gp); setCoinTarget( 0 ); // Might still be set from a previous challenge diff --git a/src/race/race_manager.hpp b/src/race/race_manager.hpp index 379fd3ed0..1dbb9a7ee 100644 --- a/src/race/race_manager.hpp +++ b/src/race/race_manager.hpp @@ -185,12 +185,13 @@ public: case MINOR_MODE_SOCCER: return _("Soccer"); default: assert(false); return NULL; } - } + } // getNameOf // ------------------------------------------------------------------------ - static bool hasAI(const MinorRaceModeType mode) + /** Returns if the currently set minor game mode can be used by the AI. */ + bool hasAI() { - switch (mode) + switch (m_minor_mode) { case MINOR_MODE_NORMAL_RACE: return true; case MINOR_MODE_TIME_TRIAL: return true; @@ -200,7 +201,7 @@ public: case MINOR_MODE_SOCCER: return false; default: assert(false); return false; } - } + } // hasAI // ------------------------------------------------------------------------ @@ -410,9 +411,9 @@ public: void setDifficulty(Difficulty diff); // ------------------------------------------------------------------------ - void setGrandPrix(const GrandPrixData *gp) + void setGrandPrix(const GrandPrixData &gp) { - m_grand_prix = *gp; + m_grand_prix = gp; m_coin_target = 0; } // ------------------------------------------------------------------------ @@ -682,7 +683,7 @@ public: * \brief Higher-level method to start a GP without having to care about * the exact startup sequence */ - void startGP(const GrandPrixData* gp, bool from_overworld, + void startGP(const GrandPrixData &gp, bool from_overworld, bool continue_saved_gp); /** diff --git a/src/states_screens/arenas_screen.cpp b/src/states_screens/arenas_screen.cpp index f556629ac..fd4ead99e 100644 --- a/src/states_screens/arenas_screen.cpp +++ b/src/states_screens/arenas_screen.cpp @@ -25,7 +25,7 @@ #include "io/file_manager.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/arenas_screen.hpp" -#include "states_screens/dialogs/track_info_dialog.hpp" +#include "states_screens/track_info_screen.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/random_generator.hpp" @@ -163,13 +163,11 @@ void ArenasScreen::eventCallback(Widget* widget, const std::string& name, const RandomGenerator random; const int randomID = random.get(curr_group.size()); - Track* clickedTrack = track_manager->getTrack( curr_group[randomID] ); - if (clickedTrack != NULL) + Track* clicked_track = track_manager->getTrack( curr_group[randomID] ); + if (clicked_track != NULL) { - ITexture* screenshot = irr_driver->getTexture( clickedTrack->getScreenshotFile().c_str() ); - - new TrackInfoDialog(selection, clickedTrack->getIdent(), clickedTrack->getName(), - screenshot, 0.8f, 0.7f); + TrackInfoScreen::getInstance()->setTrack(clicked_track); + StateManager::get()->pushScreen(TrackInfoScreen::getInstance()); } } @@ -182,13 +180,11 @@ void ArenasScreen::eventCallback(Widget* widget, const std::string& name, const } else { - Track* clickedTrack = track_manager->getTrack(selection); - if (clickedTrack != NULL) + Track* clicked_track = track_manager->getTrack(selection); + if (clicked_track != NULL) { - ITexture* screenshot = irr_driver->getTexture( clickedTrack->getScreenshotFile().c_str() ); - - new TrackInfoDialog(selection, clickedTrack->getIdent(), clickedTrack->getName(), - screenshot, 0.8f, 0.7f); + TrackInfoScreen::getInstance()->setTrack(clicked_track); + StateManager::get()->pushScreen(TrackInfoScreen::getInstance()); } // clickedTrack != NULL } // if random_track diff --git a/src/states_screens/dialogs/addons_loading.cpp b/src/states_screens/dialogs/addons_loading.cpp index 1ebf2f3ad..a4959aafe 100644 --- a/src/states_screens/dialogs/addons_loading.cpp +++ b/src/states_screens/dialogs/addons_loading.cpp @@ -190,11 +190,12 @@ void AddonsLoading::init() } // init // ---------------------------------------------------------------------------- -void AddonsLoading::escapePressed() +bool AddonsLoading::onEscapePressed() { stopDownload(); ModalDialog::dismiss(); -} // escapePressed + return true; +} // onEscapePressed // ---------------------------------------------------------------------------- @@ -335,7 +336,6 @@ void AddonsLoading::stopDownload() // order to avoid a memory leak, we let network_http free // the request. //m_download_request->setManageMemory(true); - assert(false); m_download_request->cancel(); }; } // startDownload diff --git a/src/states_screens/dialogs/addons_loading.hpp b/src/states_screens/dialogs/addons_loading.hpp index fdb7fd5e3..27f52a431 100644 --- a/src/states_screens/dialogs/addons_loading.hpp +++ b/src/states_screens/dialogs/addons_loading.hpp @@ -23,6 +23,7 @@ #include "addons/addons_manager.hpp" #include "guiengine/widgets.hpp" #include "guiengine/modaldialog.hpp" +#include "utils/cpp2011.hpp" #include "utils/synchronised.hpp" namespace Online { class HTTPRequest; } @@ -32,7 +33,6 @@ namespace Online { class HTTPRequest; } */ class AddonsLoading : public GUIEngine::ModalDialog { - virtual void escapePressed(); private: GUIEngine::LabelWidget *m_state; GUIEngine::ProgressBarWidget *m_progress; @@ -70,6 +70,7 @@ public: * */ void onUpdate(float delta); void voteClicked(); + virtual bool onEscapePressed() OVERRIDE; }; // AddonsLoading diff --git a/src/states_screens/dialogs/confirm_resolution_dialog.cpp b/src/states_screens/dialogs/confirm_resolution_dialog.cpp index 36f00240f..c4c1896ab 100644 --- a/src/states_screens/dialogs/confirm_resolution_dialog.cpp +++ b/src/states_screens/dialogs/confirm_resolution_dialog.cpp @@ -64,6 +64,15 @@ void ConfirmResolutionDialog::onUpdate(float dt) } +// ---------------------------------------------------------------------------- + +bool ConfirmResolutionDialog::onEscapePressed() +{ + ModalDialog::dismiss(); + irr_driver->cancelResChange(); + return true; +} // escapePressed + // ------------------------------------------------------------------------------------------------------ void ConfirmResolutionDialog::updateMessage() diff --git a/src/states_screens/dialogs/confirm_resolution_dialog.hpp b/src/states_screens/dialogs/confirm_resolution_dialog.hpp index 5a03bfc72..dc3ad1605 100644 --- a/src/states_screens/dialogs/confirm_resolution_dialog.hpp +++ b/src/states_screens/dialogs/confirm_resolution_dialog.hpp @@ -20,6 +20,7 @@ #define HEADER_CONFIRM_RES_DIALOG_HPP #include "guiengine/modaldialog.hpp" +#include "utils/cpp2011.hpp" /** * \brief Dialog shown after a resolution switch sot he user may confirm if @@ -28,6 +29,7 @@ */ class ConfirmResolutionDialog : public GUIEngine::ModalDialog { +private: /** number of seconds left before resolution is considered unplayable */ float m_remaining_time; @@ -40,6 +42,7 @@ public: GUIEngine::EventPropagation processEvent(const std::string& eventSource); virtual void onUpdate(float dt); + virtual bool onEscapePressed() OVERRIDE; }; diff --git a/src/states_screens/dialogs/debug_slider.cpp b/src/states_screens/dialogs/debug_slider.cpp index 006a05c8b..38a210b51 100644 --- a/src/states_screens/dialogs/debug_slider.cpp +++ b/src/states_screens/dialogs/debug_slider.cpp @@ -39,6 +39,7 @@ DebugSliderDialog::DebugSliderDialog() : ModalDialog(0.85f, 0.25f, MODAL_DIALOG_ loadFromFile("debug_slider.stkgui"); } +#if !defined(__APPLE__) void DebugSliderDialog::setSliderHook(std::string id, unsigned min, unsigned max, std::function<int()> G, std::function<void(int)> S) { getWidget<SpinnerWidget>(id.c_str())->setValue(G()); @@ -46,6 +47,7 @@ void DebugSliderDialog::setSliderHook(std::string id, unsigned min, unsigned max getWidget<SpinnerWidget>(id.c_str())->setMax(max); Setters[id] = S; } +#endif // ------------------------------------------------------------------------------------------------------ @@ -67,12 +69,16 @@ void DebugSliderDialog::onEnterPressedInternal() GUIEngine::EventPropagation DebugSliderDialog::processEvent(const std::string& eventSource) { +#if !defined(__APPLE__) if (Setters.find(eventSource) == Setters.end()) +#endif return GUIEngine::EVENT_LET; +#if !defined(__APPLE__) int value = getWidget<SpinnerWidget>(eventSource.c_str())->getValue(); Log::info("DebugSlider", "Value for <%s> : %i", eventSource.c_str(), value); Setters[eventSource](value); return GUIEngine::EVENT_BLOCK; +#endif } // ------------------------------------------------------------------------------------------------------ diff --git a/src/states_screens/dialogs/debug_slider.hpp b/src/states_screens/dialogs/debug_slider.hpp index 5c4aaf734..8cd01acbc 100644 --- a/src/states_screens/dialogs/debug_slider.hpp +++ b/src/states_screens/dialogs/debug_slider.hpp @@ -33,14 +33,17 @@ class DebugSliderDialog : public GUIEngine::ModalDialog private: std::string m_id; +#if !defined(__APPLE__) std::map<std::string, std::function<void(int)> >Setters; +#endif public: DebugSliderDialog(); ~DebugSliderDialog(); - +#if !defined(__APPLE__) void setSliderHook(std::string id, unsigned min, unsigned max, std::function<int()> G, std::function<void(int)> S); +#endif virtual void onEnterPressedInternal() OVERRIDE; virtual void onUpdate(float dt) OVERRIDE; diff --git a/src/states_screens/dialogs/enter_gp_name_dialog.cpp b/src/states_screens/dialogs/enter_gp_name_dialog.cpp index e75c64abc..7d68bf09b 100644 --- a/src/states_screens/dialogs/enter_gp_name_dialog.cpp +++ b/src/states_screens/dialogs/enter_gp_name_dialog.cpp @@ -84,17 +84,13 @@ void EnterGPNameDialog::onEnterPressedInternal() if (name.size() > 0 && name != "Random Grand Prix") { // check for duplicate names - for (unsigned int i = 0; i < grand_prix_manager->getNumberOfGrandPrix(); i++) + if (grand_prix_manager->existsName(name)) { - const GrandPrixData* gp = grand_prix_manager->getGrandPrix(i); - if (gp->getName() == name) - { - LabelWidget* label = getWidget<LabelWidget>("title"); - assert(label != NULL); - label->setText(_("Another grand prix with this name already exists."), false); - sfx_manager->quickSound("anvil"); - return; - } + LabelWidget* label = getWidget<LabelWidget>("title"); + assert(label != NULL); + label->setText(_("Another grand prix with this name already exists."), false); + sfx_manager->quickSound("anvil"); + return; } // It's unsafe to delete from inside the event handler so we do it diff --git a/src/states_screens/dialogs/gp_info_dialog.cpp b/src/states_screens/dialogs/gp_info_dialog.cpp index 79ad221ca..dc411c69c 100644 --- a/src/states_screens/dialogs/gp_info_dialog.cpp +++ b/src/states_screens/dialogs/gp_info_dialog.cpp @@ -254,7 +254,7 @@ void GPInfoDialog::onEnterPressedInternal() ModalDialog::dismiss(); // Disable accidentally unlocking of a challenge PlayerManager::getCurrentPlayer()->setCurrentChallenge(""); - race_manager->startGP(grand_prix_manager->getGrandPrix(gp_id), false, false); + race_manager->startGP(*grand_prix_manager->getGrandPrix(gp_id), false, false); } // ---------------------------------------------------------------------------- @@ -270,8 +270,8 @@ GUIEngine::EventPropagation GPInfoDialog::processEvent(const std::string& event_ // becomes invalid! std::string save_source = event_source; ModalDialog::dismiss(); - race_manager->startGP(grand_prix_manager->getGrandPrix(gp_id), false, - (save_source == "continue")); + //race_manager->startGP(grand_prix_manager->getGrandPrix(gp_id), false, + // (save_source == "continue")); return GUIEngine::EVENT_BLOCK; } diff --git a/src/states_screens/dialogs/race_paused_dialog.cpp b/src/states_screens/dialogs/race_paused_dialog.cpp index 8da45da27..33c8adc15 100644 --- a/src/states_screens/dialogs/race_paused_dialog.cpp +++ b/src/states_screens/dialogs/race_paused_dialog.cpp @@ -103,7 +103,7 @@ void RacePausedDialog::onEnterPressedInternal() GUIEngine::EventPropagation RacePausedDialog::processEvent(const std::string& eventSource) { - GUIEngine::RibbonWidget* chocie_ribbon = + GUIEngine::RibbonWidget* choice_ribbon = getWidget<GUIEngine::RibbonWidget>("choiceribbon"); if (eventSource == "backbtn") @@ -115,7 +115,7 @@ GUIEngine::EventPropagation else if (eventSource == "choiceribbon") { const std::string& selection = - chocie_ribbon->getSelectionIDString(PLAYER_ID_GAME_MASTER); + choice_ribbon->getSelectionIDString(PLAYER_ID_GAME_MASTER); if (selection == "exit") { diff --git a/src/states_screens/dialogs/random_gp_dialog.cpp b/src/states_screens/dialogs/random_gp_dialog.cpp deleted file mode 100644 index 848d01834..000000000 --- a/src/states_screens/dialogs/random_gp_dialog.cpp +++ /dev/null @@ -1,196 +0,0 @@ -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2014 konstin -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 3 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include "guiengine/engine.hpp" -#include "guiengine/widgets/icon_button_widget.hpp" -#include "guiengine/widgets/spinner_widget.hpp" -#include "race/grand_prix_manager.hpp" -#include "race/race_manager.hpp" -#include "states_screens/dialogs/random_gp_dialog.hpp" -#include "tracks/track_manager.hpp" - -#include <IGUIEnvironment.h> -#include <IGUIStaticText.h> - -using irr::core::stringc; -using irr::core::stringw; -using irr::gui::IGUIStaticText; - -typedef GUIEngine::SpinnerWidget Spinner; - -RandomGPInfoDialog::RandomGPInfoDialog() -{ - // Defaults - loading selection from last time frrom a file would be better - m_number_of_tracks = 2; // We can assume that there are at least 2 standard tracks - m_trackgroup = "standard"; - m_use_reverse = GrandPrixData::GP_NO_REVERSE; - - doInit(); - m_curr_time = 0.0f; - - m_under_title = m_area.getHeight()/7; - m_over_body = m_area.getHeight()/7 + SPINNER_HEIGHT + 10; // 10px space - m_lower_bound = m_area.getHeight()*6/7; - - m_gp.createRandomGP(m_number_of_tracks, m_trackgroup, m_use_reverse); - - addTitle(); - addSpinners(); - addTracks(); - addScreenshot(); - addButtons(); - addRestartButton(); -} - -// ---------------------------------------------------------------------------- - -void RandomGPInfoDialog::addSpinners() -{ - const int laps_width = 150; - // "20*4" because there a 4 separators between the spinners with 20px each - int label_spinner_width = m_area.getWidth() - laps_width - 20*4; - // This scaling ensures that the spinners are smaller than the available - // area, look well and are (hopefully) big enough for their labels - if (m_area.getWidth() < 700) - label_spinner_width /= 2; - else if (m_area.getWidth() < 1500) - label_spinner_width /= 3; - else - label_spinner_width /= 4; - const int left = (m_area.getWidth() - label_spinner_width*2 - laps_width)/2; - - // Trackgroup chooser - Spinner* spinner = new Spinner(false); - spinner->m_properties[GUIEngine::PROP_ID] = "Trackgroup"; - spinner->m_properties[GUIEngine::PROP_WRAP_AROUND] = "true"; - spinner->setParent(m_irrlicht_window); - m_widgets.push_back(spinner); - spinner->add(); - spinner->move(left, m_under_title, label_spinner_width, SPINNER_HEIGHT); - // Fill it with all the track group names - spinner->addLabel("all"); - int index_standard; - const std::vector<std::string>& groups = track_manager->getAllTrackGroups(); - for (unsigned int i = 0; i < groups.size(); i++) - { - spinner->addLabel(stringw(groups[i].c_str())); - if(groups[i] == "standard") - index_standard = i+1; - } - // The value can only be set here because SpinnerWidget resets the value - // every time a label is added - spinner->setValue(index_standard); - - // Number of laps chooser - spinner = new Spinner(false); - spinner->setValue(m_number_of_tracks); - spinner->setMin(1); - spinner->setMax(track_manager->getTracksInGroup("standard").size()); - spinner->setParent(m_irrlicht_window); - spinner->m_properties[GUIEngine::PROP_ID] = "Number of tracks"; - spinner->m_properties[GUIEngine::PROP_WRAP_AROUND] = "true"; - m_widgets.push_back(spinner); - spinner->add(); - spinner->move(left + label_spinner_width + 20/2, m_under_title, laps_width, SPINNER_HEIGHT); - - // reverse choose - spinner = new Spinner(false); - spinner->setParent(m_irrlicht_window); - spinner->m_properties[GUIEngine::PROP_ID] = "reverse"; - spinner->m_properties[GUIEngine::PROP_WRAP_AROUND] = "true"; - m_widgets.push_back(spinner); - spinner->add(); - spinner->move(left + label_spinner_width + laps_width + 20/2, m_under_title, label_spinner_width, SPINNER_HEIGHT); - spinner->addLabel("no reverse"); - spinner->addLabel("all reverse"); - spinner->addLabel("mixed"); -} - -// ---------------------------------------------------------------------------- - -void RandomGPInfoDialog::addRestartButton() -{ - GUIEngine::IconButtonWidget* button = new GUIEngine::IconButtonWidget(); - button->setImage("gui/restart.png"); - button->setParent(m_irrlicht_window); - button->m_properties[GUIEngine::PROP_ID] = "reload"; - m_widgets.push_back(button); - button->add(); - button->move(m_area.getWidth() - 20 - 32, 20, 32, 32); -} - -// ---------------------------------------------------------------------------- - -GUIEngine::EventPropagation RandomGPInfoDialog::processEvent( - const std::string& eventSource) -{ - if (eventSource == "start") - { - // Save GP data, since dismiss will delete this object. - GrandPrixData gp = m_gp; - ModalDialog::dismiss(); - race_manager->startGP(&gp, false, false); - return GUIEngine::EVENT_BLOCK; - } - else if (eventSource == "Number of tracks") - { - // The old gp can be reused because there's only track deletion/adding - m_number_of_tracks = getWidget<Spinner>("Number of tracks")->getValue(); - m_gp.changeTrackNumber(m_number_of_tracks, m_trackgroup); - addTracks(); - } - else if (eventSource == "Trackgroup") - { - Spinner* t = getWidget<Spinner>("Trackgroup"); - Spinner* s = getWidget<Spinner>("Number of tracks"); - - m_trackgroup = stringc(t->getStringValue()).c_str(); - - // Update the maximum for the number of tracks since it's depending on - // the current track. The current value in the Number-of-tracks-spinner - // has to be updated, since otherwise the displayed (and used) value - // can be bigger than the maximum. (Might be a TODO to fix this) - unsigned int max = (m_trackgroup == "all") ? - track_manager->getNumberOfTracks() : - track_manager->getTracksInGroup(m_trackgroup).size(); - m_number_of_tracks = std::min(max, m_number_of_tracks); - s->setMax(max); - if (s->getValue() > (signed)max) - s->setValue(max); - - // Create a new (i.e. with new tracks) random gp, since the old - // tracks might not all belong to the newly selected group. - m_gp.createRandomGP(m_number_of_tracks, m_trackgroup, m_use_reverse, - /*new_tracks*/true); - addTracks(); - } - else if (eventSource == "reverse") - { - Spinner* r = getWidget<Spinner>("reverse"); - m_use_reverse = static_cast<GrandPrixData::GPReverseType>(r->getValue()); - m_gp.changeReverse(m_use_reverse); - } - else if (eventSource == "reload") - { - m_gp.createRandomGP(m_number_of_tracks, m_trackgroup, m_use_reverse, - /*new_tracks*/true); - addTracks(); - } - - return GUIEngine::EVENT_LET; -} - diff --git a/src/states_screens/dialogs/random_gp_dialog.hpp b/src/states_screens/dialogs/random_gp_dialog.hpp deleted file mode 100644 index 35a058825..000000000 --- a/src/states_screens/dialogs/random_gp_dialog.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2014 konstin -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 3 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef HEADER_RANDOM_GP_INFO_DIALOG_HPP -#define HEADER_RANDOM_GP_INFO_DIALOG_HPP - -#include "states_screens/dialogs/gp_info_dialog.hpp" - -#include <string> - -class RandomGPInfoDialog : public GPInfoDialog -{ -private: - /** How many tracks to pick. */ - unsigned int m_number_of_tracks; - - /** Name of the track group from which to pick tracks. */ - std::string m_trackgroup; - - /** How reverse settings should be determined. */ - GrandPrixData::GPReverseType m_use_reverse; - -public: - static const int SPINNER_HEIGHT = 40; - - RandomGPInfoDialog(); - - /** Adds a SpinnerWidgets to choose the track groups, one to choose the - * number of tracks and one to choose if the tracks should be raced in - * reverse. The Spinners are centered. */ - void addSpinners(); - void addRestartButton(); - - GUIEngine::EventPropagation processEvent(const std::string& eventSource); -}; - -#endif diff --git a/src/states_screens/easter_egg_screen.cpp b/src/states_screens/easter_egg_screen.cpp index 474615e32..bf0790cde 100644 --- a/src/states_screens/easter_egg_screen.cpp +++ b/src/states_screens/easter_egg_screen.cpp @@ -26,7 +26,7 @@ #include "guiengine/widgets/icon_button_widget.hpp" #include "io/file_manager.hpp" #include "states_screens/state_manager.hpp" -#include "states_screens/dialogs/track_info_dialog.hpp" +#include "states_screens/track_info_screen.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/translation.hpp" @@ -80,19 +80,13 @@ void EasterEggScreen::eventCallback(Widget* widget, const std::string& name, con std::string track = m_random_track_list.front(); m_random_track_list.pop_front(); m_random_track_list.push_back(track); - Track* clickedTrack = track_manager->getTrack( track ); + Track* clicked_track = track_manager->getTrack( track ); - if (clickedTrack != NULL) + if (clicked_track != NULL) { - ITexture* screenshot = - irr_driver->getTexture( clickedTrack->getScreenshotFile(), - "While loading screenshot for track '%s':", - clickedTrack->getFilename() ); - - new TrackInfoDialog(selection, clickedTrack->getIdent(), - translations->fribidize(clickedTrack->getName()), - screenshot, 0.8f, 0.7f); + TrackInfoScreen::getInstance()->setTrack(clicked_track); + StateManager::get()->pushScreen(TrackInfoScreen::getInstance()); } } @@ -100,22 +94,13 @@ void EasterEggScreen::eventCallback(Widget* widget, const std::string& name, con { unlock_manager->playLockSound(); } - else if (selection == RibbonWidget::NO_ITEM_ID) + else if (selection != RibbonWidget::NO_ITEM_ID) { - } - else - { - Track* clickedTrack = track_manager->getTrack(selection); - if (clickedTrack != NULL) + Track* clicked_track = track_manager->getTrack(selection); + if (clicked_track != NULL) { - ITexture* screenshot = - irr_driver->getTexture( clickedTrack->getScreenshotFile(), - "While loading screenshot for track '%s'", - clickedTrack->getFilename()); - - new TrackInfoDialog(selection, clickedTrack->getIdent(), - translations->fribidize(clickedTrack->getName()), - screenshot, 0.8f, 0.7f); + TrackInfoScreen::getInstance()->setTrack(clicked_track); + StateManager::get()->pushScreen(TrackInfoScreen::getInstance()); } } } diff --git a/src/states_screens/edit_gp_screen.cpp b/src/states_screens/edit_gp_screen.cpp index 8ce3a6490..a9a3b66d4 100644 --- a/src/states_screens/edit_gp_screen.cpp +++ b/src/states_screens/edit_gp_screen.cpp @@ -103,20 +103,17 @@ void EditGPScreen::eventCallback(GUIEngine::Widget* widget, const std::string& n setModified(true); } } - else if (m_action == "add" || m_action == "edit") + else if (m_action == "edit") { - if (m_action == "edit") - { - edit(); - } - else - { - EditTrackScreen* edit = EditTrackScreen::getInstance(); - assert(edit != NULL); - //By default, 3 laps and no reversing - edit->setSelection(NULL, 3, false); - StateManager::get()->pushScreen(edit); - } + edit(); + } + else if (m_action == "add") + { + EditTrackScreen* edit = EditTrackScreen::getInstance(); + assert(edit != NULL); + //By default, 3 laps and no reversing + edit->setSelection(NULL, 3, false); + StateManager::get()->pushScreen(edit); } else if (m_action == "remove") { diff --git a/src/states_screens/edit_track_screen.cpp b/src/states_screens/edit_track_screen.cpp index a01bfc7c4..c3b68fe29 100644 --- a/src/states_screens/edit_track_screen.cpp +++ b/src/states_screens/edit_track_screen.cpp @@ -234,6 +234,8 @@ void EditTrackScreen::selectTrack(const std::string& id) tracks->setSelection("", PLAYER_ID_GAME_MASTER, true); selected_track->setText(_("Select a track"), true); + // We can't set a better default for number of laps. On the other + // hand, if a track is selected, the number of laps will be updated. laps->setValue(3); reverse->setVisible(true); diff --git a/src/states_screens/feature_unlocked.cpp b/src/states_screens/feature_unlocked.cpp index 32510f341..3f24204ee 100644 --- a/src/states_screens/feature_unlocked.cpp +++ b/src/states_screens/feature_unlocked.cpp @@ -297,8 +297,7 @@ void FeatureUnlockedCutScene::init() m_unlocked_stuff[n].m_root_gift_node = kart_model->attachModel(true, false); m_unlocked_stuff[n].m_scale = 5.0f; kart_model->setAnimation(KartModel::AF_DEFAULT); - float susp[4]={0,0,0,0}; - kart_model->update(0.0f, 0.0f, 0.0f, susp, 0.0f); + kart_model->update(0.0f, 0.0f, 0.0f, 0.0f); #ifdef DEBUG m_unlocked_stuff[n].m_root_gift_node->setName("unlocked kart"); diff --git a/src/states_screens/gp_info_screen.cpp b/src/states_screens/gp_info_screen.cpp new file mode 100644 index 000000000..5efdee60c --- /dev/null +++ b/src/states_screens/gp_info_screen.cpp @@ -0,0 +1,364 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2014 Marianne Gagnon +// 2014 Joerg Henrichs, konstin +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "states_screens/gp_info_screen.hpp" + +#include "audio/sfx_manager.hpp" +#include "challenges/unlock_manager.hpp" +#include "config/player_manager.hpp" +#include "config/saved_grand_prix.hpp" +#include "graphics/irr_driver.hpp" +#include "guiengine/engine.hpp" +#include "guiengine/screen.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/list_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "guiengine/widgets/spinner_widget.hpp" +#include "io/file_manager.hpp" +#include "race/grand_prix_manager.hpp" +#include "race/grand_prix_data.hpp" +#include "race/race_manager.hpp" +#include "states_screens/state_manager.hpp" +#include "states_screens/tracks_screen.hpp" +#include "tracks/track.hpp" +#include "tracks/track_manager.hpp" +#include "utils/translation.hpp" + +#include <IGUIEnvironment.h> +#include <IGUIStaticText.h> + +#include <algorithm> + +using irr::gui::IGUIStaticText; +using namespace GUIEngine; + +DEFINE_SCREEN_SINGLETON( GPInfoScreen ); + +/** Constructor, initialised some variables which might be used before + * loadedFromFile is called. + */ +GPInfoScreen::GPInfoScreen() : Screen("gp_info.stkgui") +{ + m_curr_time = 0.0f; + // Necessary to test if loadedFroMFile() was executed (in setGP) + m_reverse_spinner = NULL; + m_screenshot_widget = NULL; +} // GPInfoScreen + +// ---------------------------------------------------------------------------- +/** Called when the stkgui file is read. It stores the pointer to various + * widgets and adds the right names for reverse mode. + */ +void GPInfoScreen::loadedFromFile() +{ + // The group spinner is filled in init every time the screen is shown + // (since the groups can change if addons are added/deleted). + m_group_spinner = getWidget<SpinnerWidget>("group-spinner"); + m_reverse_spinner = getWidget<SpinnerWidget>("reverse-spinner"); + m_reverse_spinner->addLabel(_("No")); + m_reverse_spinner->addLabel(_("Yes")); + m_reverse_spinner->addLabel(_("Random")); + m_reverse_spinner->setValue(0); + + m_num_tracks_spinner = getWidget<SpinnerWidget>("track-spinner"); + // Only init the number of tracks here, this way the previously selected + // number of tracks will be the default. + m_num_tracks_spinner->setValue(1); + int number_of_tracks = m_num_tracks_spinner->getValue(); +} // loadedFromFile + +// ---------------------------------------------------------------------------- +/** Sets the GP to be displayed. If the identifier is 'random', no gp info + * will be loaded. + */ +void GPInfoScreen::setGP(const std::string &gp_ident) +{ + if(gp_ident!="random") + m_gp = *grand_prix_manager->getGrandPrix(gp_ident); + else + { + // Doesn't matter what kind of GP we create, it just gets the + // right id ("random"). + m_gp.createRandomGP(1, "standard", + m_reverse_spinner ? getReverse() + : GrandPrixData::GP_NO_REVERSE); + } +} // setGP + +// ---------------------------------------------------------------------------- +/** Converts the currently selected reverse status into a value of type +* GPReverseType . +*/ +GrandPrixData::GPReverseType GPInfoScreen::getReverse() const +{ + switch (m_reverse_spinner->getValue()) + { + case 0: return GrandPrixData::GP_NO_REVERSE; break; + case 1: return GrandPrixData::GP_ALL_REVERSE; break; + case 2: return GrandPrixData::GP_RANDOM_REVERSE; break; + default: assert(false); + } // switch + // Avoid compiler warning + return GrandPrixData::GP_NO_REVERSE; +} // getReverse +// ---------------------------------------------------------------------------- +void GPInfoScreen::beforeAddingWidget() +{ + bool random = m_gp.isRandomGP(); + if (!random) + { + // Check if there is a saved GP: + SavedGrandPrix* saved_gp = SavedGrandPrix::getSavedGP( + StateManager::get()->getActivePlayerProfile(0)->getUniqueID(), + m_gp.getId(), + race_manager->getDifficulty(), + race_manager->getNumberOfKarts(), + race_manager->getNumLocalPlayers()); + + RibbonWidget* ribbonButtons = getWidget<RibbonWidget>("buttons"); + int id_continue_button = ribbonButtons->findItemNamed("continue"); + ribbonButtons->setItemVisible(id_continue_button, saved_gp != NULL); + ribbonButtons->setLabel(id_continue_button, _("Continue saved GP")); + } + else + { + RibbonWidget* ribbonButtons = getWidget<RibbonWidget>("buttons"); + int id_continue_button = ribbonButtons->findItemNamed("continue"); + ribbonButtons->setItemVisible(id_continue_button, true); + ribbonButtons->setLabel(id_continue_button, _("Reload")); + } +} + +// ---------------------------------------------------------------------------- +/** Called before the screen is shown. It adds the screenshot icon, and + * initialises all widgets depending on GP mode (random or not), if a saved + * GP is available etc. + */ +void GPInfoScreen::init() +{ + Screen::init(); + m_curr_time = 0.0f; + + bool random = m_gp.isRandomGP(); + + SpinnerWidget *reverse_spinner = getWidget<SpinnerWidget>("reverse-spinner"); + getWidget<LabelWidget >("track-text" )->setVisible(random); + m_num_tracks_spinner->setVisible(random); + getWidget<LabelWidget >("group-text" )->setVisible(random); + m_group_spinner->setVisible(random); + + + if(random) + { + RibbonWidget *rb = getWidget<RibbonWidget>("buttons"); + rb->setLabel(1,_(L"Reload") ); + getWidget<LabelWidget>("name")->setText(_("Random Grand Prix"), false); + std::string restart = file_manager->getAsset(FileManager::GUI, "restart.png"); + + // We have to recreate the group spinner, but a new group might have + // been added or deleted since the last time this screen was shown. + m_group_spinner->clearLabels(); + m_group_spinner->addLabel("all"); + int index_standard; + const std::vector<std::string>& groups = track_manager->getAllTrackGroups(); + for (unsigned int i = 0; i < groups.size(); i++) + { + m_group_spinner->addLabel(stringw(groups[i].c_str())); + if (groups[i] == "standard") + index_standard = i + 1; + } + // Try to keep a previously selected group value + if(m_group_spinner->getValue() >= (int)groups.size()) + { + m_group_spinner->setValue(index_standard); + m_group_name = "standard"; + } + else + m_group_name = stringc(m_group_spinner->getStringValue().c_str()).c_str(); + + // If there are more tracks selected atm as in the group (which can + // happen if the group has been changed since last time this screen + // was shown), adjust it: + int max_num_tracks = m_group_name=="all" + ? track_manager->getNumberOfRaceTracks() + : track_manager->getTracksInGroup(m_group_name).size(); + m_num_tracks_spinner->setMax(max_num_tracks); + if(m_num_tracks_spinner->getValue() > max_num_tracks) + { + m_num_tracks_spinner->setValue(max_num_tracks); + } + + // Now create the random GP: + m_gp.createRandomGP(m_num_tracks_spinner->getValue(), + m_group_name, getReverse(), true); + } + else + { + getWidget<LabelWidget>("name")->setText(m_gp.getName(), false); + m_gp.checkConsistency(); + } + + addTracks(); + addScreenshot(); +} // init + +// ---------------------------------------------------------------------------- +/** Updates the list of tracks shown. + */ +void GPInfoScreen::addTracks() +{ + const std::vector<std::string> tracks = m_gp.getTrackNames(); + + ListWidget *list = getWidget<ListWidget>("tracks"); + list->clear(); + for (unsigned int i = 0; i < tracks.size(); i++) + { + const Track *track = track_manager->getTrack(tracks[i]); + std::string s = StringUtils::toString(i); + list->addItem(s, translations->fribidize(track->getName())); + } +} // addTracks + +// ---------------------------------------------------------------------------- +/** Creates a screenshot widget in the placeholder of the GUI. + */ +void GPInfoScreen::addScreenshot() +{ + Widget* screenshot_div = getWidget("screenshot_div"); + + if(!m_screenshot_widget) + { + m_screenshot_widget = new IconButtonWidget( + IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, + false, false, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + m_widgets.push_back(m_screenshot_widget); + } + // images are saved squared, but must be stretched to 4:3 + m_screenshot_widget->setCustomAspectRatio(4.0f / 3.0f); + m_screenshot_widget->m_x = screenshot_div->m_x; + m_screenshot_widget->m_y = screenshot_div->m_y; + m_screenshot_widget->m_w = screenshot_div->m_w; + m_screenshot_widget->m_h = screenshot_div->m_h; + + + // Temporary icon, will replace it just after + // (but it will be shown if the given icon is not found) + m_screenshot_widget->m_properties[PROP_ICON] = "gui/main_help.png"; + m_screenshot_widget->add(); + + const Track *track = track_manager->getTrack(m_gp.getTrackId(0)); + video::ITexture* screenshot = irr_driver->getTexture(track->getScreenshotFile(), + "While loading screenshot for track '%s':", + track->getFilename() ); + if (screenshot != NULL) + m_screenshot_widget->setImage(screenshot); +} // addScreenShot + +// ---------------------------------------------------------------------------- +/** Handle user input. + */ +void GPInfoScreen::eventCallback(Widget *, const std::string &name, + const int player_id) +{ + if(name=="buttons") + { + const std::string &button = getWidget<RibbonWidget>("buttons") + ->getSelectionIDString(PLAYER_ID_GAME_MASTER); + + // The continue button becomes a 'reload' button in random GP: + if(button=="continue" && m_gp.isRandomGP()) + { + // Create a new GP: + m_gp.createRandomGP(m_num_tracks_spinner->getValue(), + m_group_name, getReverse(), + /*new tracks*/ true ); + addTracks(); + } + else if (button == "start" || button=="continue") + { + // Normal GP: start/continue a saved GP + int n = getWidget<SpinnerWidget>("ai-spinner")->getValue(); + + race_manager->setNumKarts(race_manager->getNumLocalPlayers() + n); + race_manager->startGP(m_gp, false, (name == "continue")); + } + } // name=="buttons" + else if (name=="group-spinner") + { + m_group_name = stringc(m_group_spinner->getStringValue()).c_str(); + + // Update the maximum for the number of tracks since it's depending on + // the current track. The current value in the Number-of-tracks-spinner + // has to be updated, since otherwise the displayed (and used) value + // can be bigger than the maximum. (Might be a TODO to fix this) + int max_num_tracks = m_group_name=="all" + ? track_manager->getNumberOfRaceTracks() + : track_manager->getTracksInGroup(m_group_name).size(); + m_num_tracks_spinner->setMax(max_num_tracks); + int number_of_tracks = std::min(max_num_tracks, + m_num_tracks_spinner->getValue()); + if (m_num_tracks_spinner->getValue() > max_num_tracks) + m_num_tracks_spinner->setValue(max_num_tracks); + // Create a new (i.e. with new tracks) random gp, since the old + // tracks might not all belong to the newly selected group. + + m_gp.createRandomGP(m_num_tracks_spinner->getValue(), m_group_name, + getReverse(), /*new_tracks*/true); + addTracks(); + } + else if (name=="track-spinner") + { + m_gp.changeTrackNumber(m_num_tracks_spinner->getValue(), m_group_name); + addTracks(); + } + else if (name=="reverse-spinner") + { + m_gp.changeReverse(getReverse()); + } + else if(name=="back") + { + StateManager::get()->escapePressed(); + } + +} // eventCallback + +// ---------------------------------------------------------------------------- +/** Called every update. Used to cycle the screenshots. + * \param dt Time step size. + */ +void GPInfoScreen::onUpdate(float dt) +{ + if (dt == 0) + return; // if nothing changed, return right now + + m_curr_time += dt; + int frame_after = (int)(m_curr_time / 1.5f); + + const std::vector<std::string> tracks = m_gp.getTrackNames(); + if (frame_after >= (int)tracks.size()) + { + frame_after = 0; + m_curr_time = 0; + } + + Track* track = track_manager->getTrack(tracks[frame_after]); + std::string file = track->getScreenshotFile(); + m_screenshot_widget->setImage(file, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + m_screenshot_widget->m_properties[PROP_ICON] = file; +} // onUpdate \ No newline at end of file diff --git a/src/states_screens/gp_info_screen.hpp b/src/states_screens/gp_info_screen.hpp new file mode 100644 index 000000000..8e72b89b2 --- /dev/null +++ b/src/states_screens/gp_info_screen.hpp @@ -0,0 +1,88 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2014 Marianne Gagnon +// 2014 Joerg Henrichs +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifndef HEADER_GP_INFO_SCREEN_HPP +#define HEADER_GP_INFO_SCREEN_HPP + +#include "guiengine/screen.hpp" +#include "race/grand_prix_data.hpp" + +class GrandPrixData; + +namespace GUIEngine +{ + class IconButtonWidget; + class SpinnerWidget; +} + +/** + * \brief Dialog that shows information about a specific grand prix + * \ingroup states_screens + */ +class GPInfoScreen : public GUIEngine::Screen, + public GUIEngine::ScreenSingleton<GPInfoScreen> +{ +private: + /** Spinner for the different track groups. */ + GUIEngine::SpinnerWidget *m_group_spinner; + + /** Spinner for reverse mode. */ + GUIEngine::SpinnerWidget *m_reverse_spinner; + + /** Spinner for number of tracks (in case of random GP). */ + GUIEngine::SpinnerWidget *m_num_tracks_spinner; + + /** The currently selected group name. */ + std::string m_group_name; + +protected: // Necessary for RandomGPInfoScreen + GUIEngine::IconButtonWidget* m_screenshot_widget; + float m_curr_time; + + /** The grand prix data. */ + GrandPrixData m_gp; + + /** \brief display all the tracks according to the current gp + * For a normal gp info dialog, it just creates a label for every track. + * But with a random gp info dialog, it tries to reuse as many + * labels as possible by just changing their text. */ + void addTracks(); + void addScreenshot(); + void updateRandomGP(); + GrandPrixData::GPReverseType getReverse() const; + +public: + GPInfoScreen(); + /** Places the focus back on the selected GP, in the case that the dialog + * was cancelled and we're returning to the track selection screen */ + virtual ~GPInfoScreen() {} + + void onEnterPressedInternal(); + virtual void eventCallback(GUIEngine::Widget *, const std::string &name, + const int player_id); + virtual void loadedFromFile() OVERRIDE; + virtual void init() OVERRIDE; + virtual void beforeAddingWidget() OVERRIDE; + + virtual void onUpdate(float dt); + + void setGP(const std::string &gp_ident); +}; // GPInfoScreen + +#endif diff --git a/src/states_screens/grand_prix_cutscene.cpp b/src/states_screens/grand_prix_cutscene.cpp new file mode 100644 index 000000000..850852aec --- /dev/null +++ b/src/states_screens/grand_prix_cutscene.cpp @@ -0,0 +1,91 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2014 konstin +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "guiengine/scalable_font.hpp" +#include "guiengine/widgets/button_widget.hpp" +#include "modes/cutscene_world.hpp" +#include "race/grand_prix_data.hpp" +#include "race/grand_prix_manager.hpp" +#include "race/race_manager.hpp" +#include "states_screens/grand_prix_cutscene.hpp" +#include "tracks/track_manager.hpp" + +#include <string> +#include <vector> + +typedef GUIEngine::ButtonWidget Button; + +/** A Button to save the GP if it was a random GP */ +void GrandPrixCutscene::saveGPButton() +{ + if (race_manager->getGrandPrix().getId() != "random") + getWidget<Button>("save")->setVisible(false); +} // saveGPButton + +// ---------------------------------------------------------------------------- + +/** \brief Creates a new GP with the same content as the current and saves it + * The GP that the race_manager provides can't be used because we need some + * functions and settings that the GP manager only gives us through + * createNewGP(). */ +void GrandPrixCutscene::onNewGPWithName(const irr::core::stringw& name) +{ + // create a new GP with the correct filename and a unique id + GrandPrixData* gp = grand_prix_manager->createNewGP(name); + const GrandPrixData current_gp = race_manager->getGrandPrix(); + std::vector<std::string> tracks = current_gp.getTrackNames(); + std::vector<int> laps = current_gp.getLaps(); + std::vector<bool> reverse = current_gp.getReverse(); + for (unsigned int i = 0; i < laps.size(); i++) + gp->addTrack(track_manager->getTrack(tracks[i]), laps[i], reverse[i]); + gp->writeToFile(); + + // Avoid double-save which can have bad side-effects + getWidget<Button>("save")->setVisible(false); +} // onNewGPWithName + +// ---------------------------------------------------------------------------- + +void GrandPrixCutscene::eventCallback(GUIEngine::Widget* widget, + const std::string& name, + const int playerID) +{ + if (name == "continue") + { + ((CutsceneWorld*)World::getWorld())->abortCutscene(); + } + else if (name == "save") + { + new EnterGPNameDialog(this, 0.5f, 0.4f); + } +} // eventCallback + +// ---------------------------------------------------------------------------- + +bool GrandPrixCutscene::onEscapePressed() +{ + ((CutsceneWorld*)World::getWorld())->abortCutscene(); + return false; +} // onEscapePressed + +// ---------------------------------------------------------------------------- + +void GrandPrixCutscene::tearDown() +{ + Screen::tearDown(); +} // tearDown + diff --git a/src/states_screens/grand_prix_cutscene.hpp b/src/states_screens/grand_prix_cutscene.hpp new file mode 100644 index 000000000..d85834b7b --- /dev/null +++ b/src/states_screens/grand_prix_cutscene.hpp @@ -0,0 +1,48 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2014 konstin +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_GRAND_PRIX_CUTSCENE_HPP +#define HEADER_GRAND_PRIX_CUTSCENE_HPP + +#include "guiengine/screen.hpp" +#include "guiengine/widgets/button_widget.hpp" +#include "race/race_manager.hpp" +#include "states_screens/dialogs/enter_gp_name_dialog.hpp" + +#include <string> + +class GrandPrixCutscene: public GUIEngine::CutsceneScreen, + public EnterGPNameDialog::INewGPListener +{ + friend class GUIEngine::ScreenSingleton<GrandPrixCutscene>; +public: + GrandPrixCutscene(const char * filename) : CutsceneScreen(filename) {} +protected: + void saveGPButton(); + + /** implement callback from INewGPListener */ + void onNewGPWithName(const irr::core::stringw& name); + + // implement callbacks from parent class GUIEngine::Screen + void eventCallback(GUIEngine::Widget* widget, + const std::string& name, + const int playerID) OVERRIDE; + bool onEscapePressed() OVERRIDE; + void tearDown() OVERRIDE; +}; + +#endif diff --git a/src/states_screens/grand_prix_editor_screen.cpp b/src/states_screens/grand_prix_editor_screen.cpp index 784408889..1552835c1 100644 --- a/src/states_screens/grand_prix_editor_screen.cpp +++ b/src/states_screens/grand_prix_editor_screen.cpp @@ -29,7 +29,6 @@ #include "states_screens/edit_gp_screen.hpp" #include "states_screens/dialogs/enter_gp_name_dialog.hpp" #include "states_screens/dialogs/gp_info_dialog.hpp" -#include "states_screens/dialogs/track_info_dialog.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/translation.hpp" @@ -205,6 +204,9 @@ void GrandPrixEditorScreen::loadGPList() // Reset GP list everytime (accounts for locking changes, etc.) gplist_widget->clearItems(); + // ensures that no GP and no track is NULL + grand_prix_manager->checkConsistency(); + // Build GP list for (unsigned int i = 0; i < grand_prix_manager->getNumberOfGrandPrix(); i++) { @@ -215,23 +217,7 @@ void GrandPrixEditorScreen::loadGPList() for (unsigned int t=0; t<tracks.size(); t++) { Track* track = track_manager->getTrack(tracks[t]); - if (track == NULL) - { - Log::warn("GrandPrixEditor", - "Grand Prix '%s' refers to track '%s', which does not exist\n", - gp->getId().c_str(), tracks[t].c_str()); - } - else - { - sshot_files.push_back(track->getScreenshotFile()); - } - } - if (sshot_files.size() == 0) - { - Log::warn("GrandPrixEditor", - "Grand Prix '%s' does not contain any valid track\n", - gp->getId().c_str()); - sshot_files.push_back("gui/main_help.png"); + sshot_files.push_back(track->getScreenshotFile()); } gplist_widget->addAnimatedItem(translations->fribidize(gp->getName()), gp->getId(), diff --git a/src/states_screens/grand_prix_editor_screen.hpp b/src/states_screens/grand_prix_editor_screen.hpp index 4d763846b..318acf0c0 100644 --- a/src/states_screens/grand_prix_editor_screen.hpp +++ b/src/states_screens/grand_prix_editor_screen.hpp @@ -18,8 +18,8 @@ #ifndef HEADER_GRAND_PRIX_EDITOR_SCREEN_HPP #define HEADER_GRAND_PRIX_EDITOR_SCREEN_HPP -#include "dialogs/enter_gp_name_dialog.hpp" #include "guiengine/screen.hpp" +#include "states_screens/dialogs/enter_gp_name_dialog.hpp" #include "states_screens/dialogs/message_dialog.hpp" diff --git a/src/states_screens/grand_prix_lose.cpp b/src/states_screens/grand_prix_lose.cpp index 27673542b..be86e77e9 100644 --- a/src/states_screens/grand_prix_lose.cpp +++ b/src/states_screens/grand_prix_lose.cpp @@ -26,6 +26,7 @@ #include "graphics/irr_driver.hpp" #include "guiengine/engine.hpp" #include "guiengine/scalable_font.hpp" +#include "guiengine/widgets/button_widget.hpp" #include "guiengine/widgets/label_widget.hpp" #include "io/file_manager.hpp" #include "items/item_manager.hpp" @@ -34,6 +35,7 @@ #include "modes/cutscene_world.hpp" #include "modes/overworld.hpp" #include "modes/world.hpp" +#include "race/race_manager.hpp" #include "states_screens/feature_unlocked.hpp" #include "states_screens/main_menu_screen.hpp" #include "states_screens/state_manager.hpp" @@ -47,7 +49,6 @@ #include <ICameraSceneNode.h> #include <ILightSceneNode.h> #include <IMeshSceneNode.h> -//#include <iostream> using namespace irr::core; using namespace irr::gui; @@ -82,42 +83,20 @@ DEFINE_SCREEN_SINGLETON( GrandPrixLose ); // ------------------------------------------------------------------------------------- -GrandPrixLose::GrandPrixLose() : CutsceneScreen("grand_prix_lose.stkgui") -{ -} // GrandPrixLose - -// ------------------------------------------------------------------------------------- - void GrandPrixLose::onCutsceneEnd() { - TrackObjectManager* tobjman = World::getWorld()->getTrack()->getTrackObjectManager(); - if (m_kart_node[0] != NULL) - m_kart_node[0]->getPresentation<TrackObjectPresentationSceneNode>()->getNode()->remove(); - if (m_kart_node[1] != NULL) - m_kart_node[1]->getPresentation<TrackObjectPresentationSceneNode>()->getNode()->remove(); - if (m_kart_node[2] != NULL) - m_kart_node[2]->getPresentation<TrackObjectPresentationSceneNode>()->getNode()->remove(); - if (m_kart_node[3] != NULL) - m_kart_node[3]->getPresentation<TrackObjectPresentationSceneNode>()->getNode()->remove(); + for (int i = 0; i < 4; i++) + { + if (m_kart_node[i] != NULL) + m_kart_node[i]->getPresentation<TrackObjectPresentationSceneNode>()->getNode()->remove(); + m_kart_node[i] = NULL; + } for (unsigned int i = 0; i<m_all_kart_models.size(); i++) delete m_all_kart_models[i]; m_all_kart_models.clear(); - - m_kart_node[0] = NULL; - m_kart_node[1] = NULL; - m_kart_node[2] = NULL; - m_kart_node[3] = NULL; -} - -// ------------------------------------------------------------------------------------- - -bool GrandPrixLose::onEscapePressed() -{ - ((CutsceneWorld*)World::getWorld())->abortCutscene(); - return false; -} +} // onCutsceneEnd // ------------------------------------------------------------------------------------- @@ -142,19 +121,14 @@ void GrandPrixLose::init() World::getWorld()->setPhase(WorldStatus::RACE_PHASE); + saveGPButton(); + m_phase = 1; m_global_time = 0.0f; } // init // ------------------------------------------------------------------------------------- -void GrandPrixLose::tearDown() -{ - Screen::tearDown(); -} // tearDown - -// ------------------------------------------------------------------------------------- - void GrandPrixLose::onUpdate(float dt) { m_global_time += dt; @@ -177,7 +151,7 @@ void GrandPrixLose::onUpdate(float dt) } } } - + // ---- title const int w = irr_driver->getFrameSize().Width; const int h = irr_driver->getFrameSize().Height; @@ -194,27 +168,13 @@ void GrandPrixLose::onUpdate(float dt) // ------------------------------------------------------------------------------------- -void GrandPrixLose::eventCallback(GUIEngine::Widget* widget, - const std::string& name, - const int playerID) -{ - if (name == "continue") - { - ((CutsceneWorld*)World::getWorld())->abortCutscene(); - } -} // eventCallback - -// ------------------------------------------------------------------------------------- - void GrandPrixLose::setKarts(std::vector<std::string> ident_arg) { TrackObjectManager* tobjman = World::getWorld()->getTrack()->getTrackObjectManager(); assert(ident_arg.size() > 0); if ((int)ident_arg.size() > MAX_KART_COUNT) - { ident_arg.resize(MAX_KART_COUNT); - } // (there is at least one kart so kart node 0 is sure to be set) m_kart_node[1] = NULL; @@ -252,7 +212,8 @@ void GrandPrixLose::setKarts(std::vector<std::string> ident_arg) } else { - Log::warn("GrandPrixLose", "Could not find a kart named '%s'.", ident_arg[n].c_str()); + Log::warn("GrandPrixLose", "A kart named '%s' could not be found\n", + ident_arg[n].c_str()); m_kart_node[n] = NULL; } // if kart != NULL } diff --git a/src/states_screens/grand_prix_lose.hpp b/src/states_screens/grand_prix_lose.hpp index bf30dfc70..a1cd0d6a4 100644 --- a/src/states_screens/grand_prix_lose.hpp +++ b/src/states_screens/grand_prix_lose.hpp @@ -21,6 +21,7 @@ #include "guiengine/screen.hpp" #include "karts/kart_model.hpp" +#include "states_screens/grand_prix_cutscene.hpp" #include <vector> #include <string> @@ -33,11 +34,13 @@ class TrackObject; * \brief Screen shown at the end of a Grand Prix * \ingroup states_screens */ -class GrandPrixLose : public GUIEngine::CutsceneScreen, public GUIEngine::ScreenSingleton<GrandPrixLose> +class GrandPrixLose : + public GrandPrixCutscene, + public GUIEngine::ScreenSingleton<GrandPrixLose> { friend class GUIEngine::ScreenSingleton<GrandPrixLose>; - GrandPrixLose(); + GrandPrixLose(): GrandPrixCutscene("grand_prix_lose.stkgui") {}; /** Global evolution of time */ float m_global_time; @@ -52,27 +55,11 @@ class GrandPrixLose : public GUIEngine::CutsceneScreen, public GUIEngine::Screen float m_kart_x, m_kart_y, m_kart_z; public: - - virtual void onCutsceneEnd() OVERRIDE; - - virtual bool onEscapePressed() OVERRIDE; - - /** \brief implement callback from parent class GUIEngine::Screen */ - virtual void loadedFromFile() OVERRIDE; - - /** \brief implement optional callback from parent class GUIEngine::Screen */ - void onUpdate(float dt) OVERRIDE; - - /** \brief implement callback from parent class GUIEngine::Screen */ + // implement callbacks from parent class GUIEngine::Screen void init() OVERRIDE; - - /** \brief implement callback from parent class GUIEngine::Screen */ - void tearDown() OVERRIDE; - - /** \brief implement callback from parent class GUIEngine::Screen */ - void eventCallback(GUIEngine::Widget* widget, const std::string& name, - const int playerID) OVERRIDE; - + void loadedFromFile() OVERRIDE; + void onCutsceneEnd() OVERRIDE; + void onUpdate(float dt) OVERRIDE; /** \brief set which karts lost this GP */ void setKarts(std::vector<std::string> ident); }; diff --git a/src/states_screens/grand_prix_win.cpp b/src/states_screens/grand_prix_win.cpp index 97a0b835f..92e15dd6f 100644 --- a/src/states_screens/grand_prix_win.cpp +++ b/src/states_screens/grand_prix_win.cpp @@ -28,6 +28,7 @@ #include "graphics/irr_driver.hpp" #include "guiengine/engine.hpp" #include "guiengine/scalable_font.hpp" +#include "guiengine/widgets/button_widget.hpp" #include "guiengine/widgets/label_widget.hpp" #include "io/file_manager.hpp" #include "items/item_manager.hpp" @@ -35,6 +36,7 @@ #include "karts/kart_properties_manager.hpp" #include "modes/cutscene_world.hpp" #include "modes/world.hpp" +#include "race/race_manager.hpp" #include "states_screens/feature_unlocked.hpp" #include "states_screens/state_manager.hpp" #include "tracks/track.hpp" @@ -66,26 +68,17 @@ DEFINE_SCREEN_SINGLETON( GrandPrixWin ); // ------------------------------------------------------------------------------------- -GrandPrixWin::GrandPrixWin() : CutsceneScreen("grand_prix_win.stkgui") +GrandPrixWin::GrandPrixWin() : GrandPrixCutscene("grand_prix_win.stkgui") { - m_kart_node[0] = NULL; - m_kart_node[1] = NULL; - m_kart_node[2] = NULL; - - m_podium_steps[0] = NULL; - m_podium_steps[1] = NULL; - m_podium_steps[2] = NULL; - + for (int i = 0; i < 3; i++) + { + m_kart_node[i] = NULL; + m_podium_steps[i] = NULL; + } } // GrandPrixWin // ------------------------------------------------------------------------------------- -GrandPrixWin::~GrandPrixWin() -{ -} - -// ------------------------------------------------------------------------------------- - void GrandPrixWin::onCutsceneEnd() { for (unsigned int i = 0; i<m_all_kart_models.size(); i++) @@ -99,31 +92,17 @@ void GrandPrixWin::onCutsceneEnd() m_unlocked_label = NULL; } - TrackObjectManager* tobjman = World::getWorld()->getTrack()->getTrackObjectManager(); - if (m_kart_node[0] != NULL) - m_kart_node[0]->getPresentation<TrackObjectPresentationSceneNode>()->getNode()->remove(); - if (m_kart_node[1] != NULL) - m_kart_node[1]->getPresentation<TrackObjectPresentationSceneNode>()->getNode()->remove(); - if (m_kart_node[2] != NULL) - m_kart_node[2]->getPresentation<TrackObjectPresentationSceneNode>()->getNode()->remove(); - - m_kart_node[0] = NULL; - m_kart_node[1] = NULL; - m_kart_node[2] = NULL; - - m_podium_steps[0] = NULL; - m_podium_steps[1] = NULL; - m_podium_steps[2] = NULL; + for (int i = 0; i < 3; i++) + { + if (m_kart_node[i] != NULL) + m_kart_node[i]->getPresentation<TrackObjectPresentationSceneNode>()->getNode()->remove(); + m_kart_node[i] = NULL; + m_podium_steps[i] = NULL; + } } // ------------------------------------------------------------------------------------- -void GrandPrixWin::loadedFromFile() -{ -} // loadedFromFile - -// ------------------------------------------------------------------------------------- - void GrandPrixWin::init() { std::vector<std::string> parts; @@ -136,6 +115,7 @@ void GrandPrixWin::init() World::getWorld()->setPhase(WorldStatus::RACE_PHASE); + saveGPButton(); if (PlayerManager::getCurrentPlayer()->getRecentlyCompletedChallenges().size() > 0) { const core::dimension2d<u32>& frame_size = GUIEngine::getDriver()->getCurrentRenderTargetSize(); @@ -195,21 +175,6 @@ void GrandPrixWin::init() // ------------------------------------------------------------------------------------- -bool GrandPrixWin::onEscapePressed() -{ - ((CutsceneWorld*)World::getWorld())->abortCutscene(); - return false; -} - -// ------------------------------------------------------------------------------------- - -void GrandPrixWin::tearDown() -{ - Screen::tearDown(); -} // tearDown - -// ------------------------------------------------------------------------------------- - void GrandPrixWin::onUpdate(float dt) { m_global_time += dt; @@ -228,17 +193,11 @@ void GrandPrixWin::onUpdate(float dt) if (fabsf(m_kart_z[k] - KARTS_DEST_Z) > dt) { if (m_kart_z[k] < KARTS_DEST_Z - dt) - { m_kart_z[k] += dt; - } else if (m_kart_z[k] > KARTS_DEST_Z + dt) - { m_kart_z[k] -= dt; - } else - { m_kart_z[k] = KARTS_DEST_Z; - } karts_not_yet_done++; } @@ -250,9 +209,7 @@ void GrandPrixWin::onUpdate(float dt) } // end for if (karts_not_yet_done == 0) - { m_phase = 2; - } } // ---- Karts Rotate @@ -281,7 +238,8 @@ void GrandPrixWin::onUpdate(float dt) } } // end for - if (karts_not_yet_done == 0) m_phase = 3; + if (karts_not_yet_done == 0) + m_phase = 3; } // ---- Podium Rises @@ -308,7 +266,6 @@ void GrandPrixWin::onUpdate(float dt) } } } // end for - } @@ -325,17 +282,6 @@ void GrandPrixWin::onUpdate(float dt) true/* center h */, true /* center v */ ); } // onUpdate -// ------------------------------------------------------------------------------------- - -void GrandPrixWin::eventCallback(GUIEngine::Widget* widget, - const std::string& name, - const int playerID) -{ - if (name == "continue") - { - ((CutsceneWorld*)World::getWorld())->abortCutscene(); - } -} // eventCallback // ------------------------------------------------------------------------------------- @@ -385,17 +331,11 @@ void GrandPrixWin::setKarts(const std::string idents_arg[3]) if (meshPresentation != NULL) { if (meshPresentation->getModelFile() == "gpwin_podium1.b3d") - { m_podium_steps[0] = currObj; - } else if (meshPresentation->getModelFile() == "gpwin_podium2.b3d") - { m_podium_steps[1] = currObj; - } else if (meshPresentation->getModelFile() == "gpwin_podium3.b3d") - { m_podium_steps[2] = currObj; - } } } diff --git a/src/states_screens/grand_prix_win.hpp b/src/states_screens/grand_prix_win.hpp index a702f134d..06e999d12 100644 --- a/src/states_screens/grand_prix_win.hpp +++ b/src/states_screens/grand_prix_win.hpp @@ -22,6 +22,7 @@ #include "audio/sfx_base.hpp" #include "guiengine/screen.hpp" #include "karts/kart_model.hpp" +#include "states_screens/grand_prix_cutscene.hpp" namespace irr { namespace scene { class ISceneNode; class ICameraSceneNode; class ILightSceneNode; class IMeshSceneNode; } } namespace GUIEngine { class LabelWidget; } @@ -32,13 +33,15 @@ class TrackObject; * \brief Screen shown at the end of a Grand Prix * \ingroup states_screens */ -class GrandPrixWin : public GUIEngine::CutsceneScreen, public GUIEngine::ScreenSingleton<GrandPrixWin> +class GrandPrixWin : + public GrandPrixCutscene, + public GUIEngine::ScreenSingleton<GrandPrixWin> { friend class GUIEngine::ScreenSingleton<GrandPrixWin>; GrandPrixWin(); - virtual ~GrandPrixWin(); + virtual ~GrandPrixWin() {}; /** Global evolution of time */ double m_global_time; @@ -47,41 +50,22 @@ class GrandPrixWin : public GUIEngine::CutsceneScreen, public GUIEngine::ScreenS TrackObject* m_kart_node[3]; - //irr::scene::IMeshSceneNode* m_podium_step[3]; - //irr::scene::ISceneNode* m_kart_node[3]; - /** A copy of the kart model for each kart used. */ std::vector<KartModel*> m_all_kart_models; GUIEngine::LabelWidget* m_unlocked_label; int m_phase; - + float m_kart_x[3], m_kart_y[3], m_kart_z[3]; - //float m_podium_x[3], m_podium_z[3]; float m_kart_rotation[3]; public: - - virtual void onCutsceneEnd() OVERRIDE; - - virtual bool onEscapePressed() OVERRIDE; - - /** \brief implement callback from parent class GUIEngine::Screen */ - virtual void loadedFromFile() OVERRIDE; - - /** \brief implement optional callback from parent class GUIEngine::Screen */ - void onUpdate(float dt) OVERRIDE; - - /** \brief implement callback from parent class GUIEngine::Screen */ + // implement callbacks from parent class GUIEngine::Screen void init() OVERRIDE; - - /** \brief implement callback from parent class GUIEngine::Screen */ - void tearDown() OVERRIDE; - - /** \brief implement callback from parent class GUIEngine::Screen */ - void eventCallback(GUIEngine::Widget* widget, const std::string& name, - const int playerID) OVERRIDE; + void loadedFromFile() OVERRIDE {}; + void onCutsceneEnd() OVERRIDE; + void onUpdate(float dt) OVERRIDE; /** \pre must be called after pushing the screen, but before onUpdate had the chance to be invoked */ void setKarts(const std::string idents[3]); diff --git a/src/states_screens/race_setup_screen.cpp b/src/states_screens/race_setup_screen.cpp index 9e4a415ae..1553c6d42 100644 --- a/src/states_screens/race_setup_screen.cpp +++ b/src/states_screens/race_setup_screen.cpp @@ -142,12 +142,6 @@ void RaceSetupScreen::eventCallback(Widget* widget, const std::string& name, con unlock_manager->playLockSound(); } } - else if (name == "aikartamount") - { - SpinnerWidget* w = dynamic_cast<SpinnerWidget*>(widget); - race_manager->setNumKarts( race_manager->getNumLocalPlayers() + w->getValue() ); - UserConfigParams::m_num_karts = race_manager->getNumLocalPlayers() + w->getValue(); - } else if (name == "back") { StateManager::get()->escapePressed(); @@ -209,16 +203,6 @@ void RaceSetupScreen::onGameModeChanged() RaceManager::MinorRaceModeType gamemode = RaceManager::getModeIDFromInternalName(gamemode_str); - // deactivate the AI karts count widget for modes for which we have no AI - SpinnerWidget* kartamount = getWidget<SpinnerWidget>("aikartamount"); - if (!RaceManager::hasAI(gamemode)) - { - kartamount->setDeactivated(); - } - else - { - kartamount->setActivated(); - } } // onGameModeChanged // ----------------------------------------------------------------------------- @@ -240,17 +224,6 @@ void RaceSetupScreen::init() w->setSelection( UserConfigParams::m_difficulty, PLAYER_ID_GAME_MASTER ); } - SpinnerWidget* kartamount = getWidget<SpinnerWidget>("aikartamount"); - kartamount->setActivated(); - - // Avoid negative numbers (which can happen if e.g. the number of karts - // in a previous race was lower than the number of players now. - int num_ai = UserConfigParams::m_num_karts-race_manager->getNumLocalPlayers(); - if(num_ai<0) num_ai = 0; - kartamount->setValue(num_ai); - kartamount->setMax(stk_config->m_max_karts - race_manager->getNumLocalPlayers() ); - race_manager->setNumKarts(num_ai + race_manager->getNumLocalPlayers()); - DynamicRibbonWidget* w2 = getWidget<DynamicRibbonWidget>("gamemode"); assert( w2 != NULL ); w2->clearItems(); diff --git a/src/states_screens/register_screen.cpp b/src/states_screens/register_screen.cpp index 067cfcf3b..8fad53ed4 100644 --- a/src/states_screens/register_screen.cpp +++ b/src/states_screens/register_screen.cpp @@ -224,7 +224,7 @@ void RegisterScreen::doRegister() } else if (username.size() < 3 || username.size() > 30) { - m_info_widget->setText(_("Username has to be between 4 and 30 characters long!"), false); + m_info_widget->setText(_("Online username has to be between 3 and 30 characters long!"), false); } else if (password.size() < 8 || password.size() > 30) { diff --git a/src/states_screens/dialogs/track_info_dialog.cpp b/src/states_screens/track_info_screen.cpp similarity index 52% rename from src/states_screens/dialogs/track_info_dialog.cpp rename to src/states_screens/track_info_screen.cpp index e7d7025f2..0e8914283 100644 --- a/src/states_screens/dialogs/track_info_dialog.cpp +++ b/src/states_screens/track_info_screen.cpp @@ -1,5 +1,6 @@ // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2009-2013 Marianne Gagnon +// Copyright (C) 2009-2014 Marianne Gagnon +// 2014 Joerg Henrichs // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -15,7 +16,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include "states_screens/dialogs/track_info_dialog.hpp" +#include "states_screens/track_info_screen.hpp" #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" @@ -24,8 +25,10 @@ #include "guiengine/engine.hpp" #include "guiengine/screen.hpp" #include "guiengine/widgets/button_widget.hpp" +#include "guiengine/widgets/check_box_widget.hpp" #include "guiengine/widgets/icon_button_widget.hpp" #include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" #include "guiengine/widgets/spinner_widget.hpp" #include "io/file_manager.hpp" #include "karts/kart_properties.hpp" @@ -49,80 +52,121 @@ using namespace irr::video; using namespace irr::core; using namespace GUIEngine; -// ------------------------------------------------------------------------------------------------------ +DEFINE_SCREEN_SINGLETON( TrackInfoScreen ); -TrackInfoDialog::TrackInfoDialog(const std::string& ribbonItem, const std::string& trackIdent, - const irr::core::stringw& trackName, ITexture* screenshot, - const float w, const float h) : ModalDialog(w, h) +// ---------------------------------------------------------------------------- +/** Constructor, which loads the corresponding track_info.stkgui file. */ +TrackInfoScreen::TrackInfoScreen() + : Screen("track_info.stkgui") { - loadFromFile("track_info_dialog.stkgui"); + m_screenshot = NULL; +} // TrackInfoScreen +// ---------------------------------------------------------------------------- +/* Saves some often used pointers. */ +void TrackInfoScreen::loadedFromFile() +{ + m_lap_spinner = getWidget<SpinnerWidget>("lap-spinner"); + m_ai_kart_spinner = getWidget<SpinnerWidget>("ai-spinner"); + m_reverse = getWidget<CheckBoxWidget>("reverse"); +} // loadedFromFile + +// ---------------------------------------------------------------------------- +void TrackInfoScreen::setTrack(Track *track) +{ + m_track = track; +} // setTrack + +// ---------------------------------------------------------------------------- +/** Initialised the display. The previous screen has to setup m_track before + * pushing this screen using TrackInfoScreen::getInstance()->setTrack(). + */ +void TrackInfoScreen::init() +{ const bool has_laps = race_manager->modeHasLaps(); const bool has_highscores = race_manager->modeHasHighscores(); - m_track_ident = trackIdent; - m_ribbon_item = ribbonItem; - - getWidget<LabelWidget>("name")->setText(trackName.c_str(), false); - - Track* track = track_manager->getTrack(trackIdent); - //I18N: when showing who is the author of track '%s' (place %s where the name of the author should appear) - getWidget<LabelWidget>("author")->setText( _("Track by %s", track->getDesigner().c_str()), false ); + getWidget<LabelWidget>("name")->setText(m_track->getName(), false); + //I18N: when showing who is the author of track '%s' + //I18N: (place %s where the name of the author should appear) + getWidget<LabelWidget>("author")->setText( _("Track by %s", m_track->getDesigner()), + false ); // ---- Track screenshot Widget* screenshot_div = getWidget("screenshot_div"); - IconButtonWidget* screenshotWidget = new IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, - false /* tab stop */, false /* focusable */); - // images are saved squared, but must be stretched to 4: - screenshotWidget->setCustomAspectRatio(4.0f / 3.0f); + if(!m_screenshot) + { + m_screenshot = + new IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, + false /* tab stop */, false /* focusable */); + m_screenshot->setCustomAspectRatio(4.0f / 3.0f); - screenshotWidget->m_x = screenshot_div->m_x; - screenshotWidget->m_y = screenshot_div->m_y; - screenshotWidget->m_w = screenshot_div->m_w; - screenshotWidget->m_h = screenshot_div->m_h; + m_screenshot->m_x = screenshot_div->m_x; + m_screenshot->m_y = screenshot_div->m_y; + m_screenshot->m_w = screenshot_div->m_w; + m_screenshot->m_h = screenshot_div->m_h; + m_screenshot->add(); + m_widgets.push_back(m_screenshot); + } + // images are saved squared, but must be stretched to 4: // temporary icon, will replace it just after (but it will be shown if the given icon is not found) - screenshotWidget->m_properties[PROP_ICON] = "gui/main_help.png"; - screenshotWidget->setParent(m_irrlicht_window); - screenshotWidget->add(); + m_screenshot->m_properties[PROP_ICON] = "gui/main_help.png"; + ITexture* screenshot = irr_driver->getTexture(m_track->getScreenshotFile(), + "While loading screenshot for track '%s':", + m_track->getFilename() ); if (screenshot != NULL) - screenshotWidget->setImage(screenshot); - m_widgets.push_back(screenshotWidget); + m_screenshot->setImage(screenshot); - - // ---- Lap count m_spinner + // Lap count m_lap_spinner + // ----------------------- + m_lap_spinner->setVisible(has_laps); + getWidget<LabelWidget>("lap-text")->setVisible(has_laps); if (has_laps) { - m_spinner = getWidget<SpinnerWidget>("lapcountspinner"); if (UserConfigParams::m_artist_debug_mode) - m_spinner->setMin(0); - - m_spinner->setValue(track->getActualNumberOfLap()); - race_manager->setNumLaps(m_spinner->getValue()); + m_lap_spinner->setMin(0); + m_lap_spinner->setValue(m_track->getActualNumberOfLap()); + race_manager->setNumLaps(m_lap_spinner->getValue()); } - else + + // Number of AIs + // ------------- + const bool has_AI = race_manager->hasAI(); + m_ai_kart_spinner->setVisible(has_AI); + getWidget<LabelWidget>("ai-text")->setVisible(has_AI); + if (has_AI) { - getWidget<SpinnerWidget>("lapcountspinner")->setVisible(false); - m_spinner = NULL; - } + m_ai_kart_spinner->setActivated(); + // Avoid negative numbers (which can happen if e.g. the number of karts + // in a previous race was lower than the number of players now. + int num_ai = UserConfigParams::m_num_karts - race_manager->getNumLocalPlayers(); + if (num_ai < 0) num_ai = 0; + m_ai_kart_spinner->setValue(num_ai); + race_manager->setNumKarts(num_ai + race_manager->getNumLocalPlayers()); + m_ai_kart_spinner->setMax(stk_config->m_max_karts - race_manager->getNumLocalPlayers()); + // A ftl reace needs at least three karts to make any sense + if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER) + { + m_ai_kart_spinner->setMin(3-race_manager->getNumLocalPlayers()); + } + else + m_ai_kart_spinner->setMin(0); + + } // has_AI // Reverse track - const bool reverse_available = track->reverseAvailable() && + // ------------- + const bool reverse_available = m_track->reverseAvailable() && race_manager->getMinorMode() != RaceManager::MINOR_MODE_EASTER_EGG; + m_reverse->setVisible(reverse_available); + getWidget<LabelWidget>("reverse-text")->setVisible(reverse_available); if (reverse_available) { - m_checkbox = getWidget<CheckBoxWidget>("reverse"); - m_checkbox->setState(race_manager->getReverseTrack()); - } - else - { - getWidget<CheckBoxWidget>("reverse")->setVisible(false); - getWidget<LabelWidget>("reverse-text")->setVisible(false); - m_checkbox = NULL; - race_manager->setReverseTrack(false); + m_reverse->setState(race_manager->getReverseTrack()); } // ---- High Scores @@ -150,27 +194,17 @@ TrackInfoDialog::TrackInfoDialog(const std::string& ribbonItem, const std::strin getWidget<LabelWidget>("highscore3")->setVisible(false); } - getWidget<ButtonWidget>("start")->setFocusForPlayer( PLAYER_ID_GAME_MASTER ); +} // init -} // TrackInfoDialog +// ---------------------------------------------------------------------------- -// ------------------------------------------------------------------------------------------------------ - -TrackInfoDialog::~TrackInfoDialog() +TrackInfoScreen::~TrackInfoScreen() { - // Place focus back on selected track, in case the dialog was cancelled and we're back to - // the track selection screen after - GUIEngine::Screen* curr_screen = GUIEngine::getCurrentScreen(); - if (curr_screen->getName() == "tracks.stkgui") - { - ((TracksScreen*)curr_screen)->setFocusOnTrack(m_ribbon_item); - } +} // ~TrackInfoScreen -} // ~TrackInfoDialog +// ---------------------------------------------------------------------------- -// ------------------------------------------------------------------------------------------------------ - -void TrackInfoDialog::updateHighScores() +void TrackInfoScreen::updateHighScores() { std::string game_mode_ident = RaceManager::getIdentOf( race_manager->getMinorMode() ); const Highscores::HighscoreType type = "HST_" + game_mode_ident; @@ -179,7 +213,7 @@ void TrackInfoDialog::updateHighScores() highscore_manager->getHighscores(type, race_manager->getNumberOfKarts(), race_manager->getDifficulty(), - m_track_ident, + m_track->getIdent(), race_manager->getNumLaps(), race_manager->getReverseTrack() ); const int amount = highscores->getNumberEntries(); @@ -226,43 +260,46 @@ void TrackInfoDialog::updateHighScores() } } // updateHighScores -// ------------------------------------------------------------------------------------------------------ +// ---------------------------------------------------------------------------- -void TrackInfoDialog::onEnterPressedInternal() +void TrackInfoScreen::onEnterPressedInternal() { // Create a copy of member variables we still need, since they will // not be accessible after dismiss: - const int num_laps = (m_spinner == NULL ? -1 : m_spinner->getValue()); - const bool reverse_track = m_checkbox == NULL ? false - : m_checkbox->getState(); - track_manager->getTrack(m_track_ident)->setActualNumberOfLaps(num_laps); + const int num_laps = race_manager->modeHasLaps() ? m_lap_spinner->getValue() + : -1; + const bool reverse_track = m_reverse == NULL ? false + : m_reverse->getState(); + m_track->setActualNumberOfLaps(num_laps); race_manager->setReverseTrack(reverse_track); - std::string track_ident = m_track_ident; + // Disable accidentally unlocking of a challenge PlayerManager::getCurrentPlayer()->setCurrentChallenge(""); - ModalDialog::dismiss(); - race_manager->startSingleRace(track_ident, num_laps, false); + race_manager->startSingleRace(m_track->getIdent(), num_laps, false); } // onEnterPressedInternal -// ------------------------------------------------------------------------------------------------------ - -GUIEngine::EventPropagation TrackInfoDialog::processEvent(const std::string& eventSource) +// ---------------------------------------------------------------------------- +void TrackInfoScreen::eventCallback(Widget* widget, const std::string& name, + const int playerID) { - if (eventSource == "start" ) + if (name == "buttons") { - onEnterPressedInternal(); - return GUIEngine::EVENT_BLOCK; + const std::string &button = getWidget<GUIEngine::RibbonWidget>("buttons") + ->getSelectionIDString(PLAYER_ID_GAME_MASTER); + if(button=="start") + onEnterPressedInternal(); + else if(button=="back") + StateManager::get()->escapePressed(); } - else if (eventSource == "closePopup") + else if (name == "back") { - ModalDialog::dismiss(); - return GUIEngine::EVENT_BLOCK; + StateManager::get()->escapePressed(); } - else if (eventSource == "reverse") + else if (name == "reverse") { - race_manager->setReverseTrack(m_checkbox->getState()); + race_manager->setReverseTrack(m_reverse->getState()); // Makes sure the highscores get swapped when clicking the 'reverse' // checkbox. if (race_manager->modeHasHighscores()) @@ -270,16 +307,21 @@ GUIEngine::EventPropagation TrackInfoDialog::processEvent(const std::string& eve updateHighScores(); } } - else if (eventSource == "lapcountspinner") + else if (name == "lap-spinner") { - assert(m_spinner != NULL); - const int num_laps = m_spinner->getValue(); + assert(race_manager->modeHasLaps()); + const int num_laps = m_lap_spinner->getValue(); race_manager->setNumLaps(num_laps); UserConfigParams::m_num_laps = num_laps; updateHighScores(); } + else if (name=="ai-spinner") + { + SpinnerWidget* w = dynamic_cast<SpinnerWidget*>(widget); + const int num_ai = m_ai_kart_spinner->getValue(); + race_manager->setNumKarts( race_manager->getNumLocalPlayers() + num_ai ); + UserConfigParams::m_num_karts = race_manager->getNumLocalPlayers() + num_ai; + } +} // eventCallback - return GUIEngine::EVENT_LET; -} // processEvent - -// ------------------------------------------------------------------------------------------------------ +// ---------------------------------------------------------------------------- diff --git a/src/states_screens/dialogs/track_info_dialog.hpp b/src/states_screens/track_info_screen.hpp similarity index 50% rename from src/states_screens/dialogs/track_info_dialog.hpp rename to src/states_screens/track_info_screen.hpp index 3367ac5c2..00387bc60 100644 --- a/src/states_screens/dialogs/track_info_dialog.hpp +++ b/src/states_screens/track_info_screen.hpp @@ -1,5 +1,6 @@ // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2009-2013 Marianne Gagnon +// Copyright (C) 2009-2014 Marianne Gagnon +// 2014 Joerg Henrichs // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -16,55 +17,65 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#ifndef HEADER_TRACKINFO_DIALOG_HPP -#define HEADER_TRACKINFO_DIALOG_HPP +#ifndef HEADER_TRACK_INFO_SCREEN_HPP +#define HEADER_TRACK_INFO_SCREEN_HPP -#include "guiengine/modaldialog.hpp" -#include "guiengine/widgets/check_box_widget.hpp" - -static const int HIGHSCORE_COUNT = 3; +#include "guiengine/screen.hpp" namespace GUIEngine { - class SpinnerWidget; + class CheckBoxWidget; class IconButtonWidget; class LabelWidget; + class SpinnerWidget; + class Widget; } +class Track; /** * \brief Dialog that shows the information about a given track * \ingroup states_screens */ -class TrackInfoDialog : public GUIEngine::ModalDialog +class TrackInfoScreen : public GUIEngine::Screen, + public GUIEngine::ScreenSingleton<TrackInfoScreen> { - std::string m_track_ident; - std::string m_ribbon_item; - + static const int HIGHSCORE_COUNT = 3; + + /** A pointer to the track of which the info is shown. */ + Track *m_track; + // When there is no need to tab through / click on images/labels, we can add directly // irrlicht labels (more complicated uses require the use of our widget set) - GUIEngine::SpinnerWidget* m_spinner; - GUIEngine::CheckBoxWidget* m_checkbox; + /** Spinner for number of laps. */ + GUIEngine::SpinnerWidget* m_lap_spinner; + + /** Spinner for number of AI karts. */ + GUIEngine::SpinnerWidget* m_ai_kart_spinner; + + /** Screenshot widget. */ + GUIEngine::IconButtonWidget *m_screenshot; + + /** Check box for reverse mode. */ + GUIEngine::CheckBoxWidget* m_reverse; + + /** The icons for the highscore list. */ GUIEngine::IconButtonWidget* m_kart_icons[HIGHSCORE_COUNT]; + + /** The actual highscore text values shown. */ GUIEngine::LabelWidget* m_highscore_entries[HIGHSCORE_COUNT]; void updateHighScores(); public: - /** - * \brief Creates a track info modal dialog with given percentage of screen width and height - * \param ribbonItem identifier name of the ribbon item that was clicked in the track selection - * screen to get there (often will be 'trackIdent' but may also be the random item) - * \param trackIdent identifier name of the track to show information about - * \param trackName human-readable, possibly translated, name of the track to show information about - * \param screenshot screenshot of the track to show information about - */ - TrackInfoDialog(const std::string& ribbonItem, const std::string& trackIdent, - const irr::core::stringw& trackName, irr::video::ITexture* screenshot, - const float percentWidth, const float percentHeight); - virtual ~TrackInfoDialog(); + TrackInfoScreen(); + virtual ~TrackInfoScreen(); + virtual void init(); + virtual void loadedFromFile(); + virtual void eventCallback(GUIEngine::Widget *,const std::string &name , + const int player_id); void onEnterPressedInternal(); - GUIEngine::EventPropagation processEvent(const std::string& eventSource); + void setTrack(Track *track); }; #endif diff --git a/src/states_screens/tracks_screen.cpp b/src/states_screens/tracks_screen.cpp index 94f715553..62e94f6df 100644 --- a/src/states_screens/tracks_screen.cpp +++ b/src/states_screens/tracks_screen.cpp @@ -28,9 +28,8 @@ #include "race/grand_prix_data.hpp" #include "race/grand_prix_manager.hpp" #include "states_screens/state_manager.hpp" -#include "states_screens/dialogs/gp_info_dialog.hpp" -#include "states_screens/dialogs/random_gp_dialog.hpp" -#include "states_screens/dialogs/track_info_dialog.hpp" +#include "states_screens/track_info_screen.hpp" +#include "states_screens/gp_info_screen.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/translation.hpp" @@ -81,14 +80,8 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name, if (clicked_track) { - ITexture* screenshot = - irr_driver->getTexture(clicked_track->getScreenshotFile(), - "While loading screenshot for track '%s':", - clicked_track->getFilename() ); - - new TrackInfoDialog(selection, clicked_track->getIdent(), - translations->fribidize(clicked_track->getName()), - screenshot, 0.8f, 0.7f); + TrackInfoScreen::getInstance()->setTrack(clicked_track); + StateManager::get()->pushScreen(TrackInfoScreen::getInstance()); } // if clicked_track } // selection=="random_track" @@ -104,14 +97,8 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name, Track* clicked_track = track_manager->getTrack(selection); if (clicked_track) { - ITexture* screenshot = - irr_driver->getTexture(clicked_track->getScreenshotFile(), - "While loading screenshot for track '%s'", - clicked_track->getFilename()); - - new TrackInfoDialog(selection, clicked_track->getIdent(), - translations->fribidize(clicked_track->getName()), - screenshot, 0.8f, 0.7f); + TrackInfoScreen::getInstance()->setTrack(clicked_track); + StateManager::get()->pushScreen(TrackInfoScreen::getInstance()); } } } // name=="tracks" @@ -127,10 +114,10 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name, } else { - if (selection == "Random Grand Prix") - new RandomGPInfoDialog(); - else - new GPInfoDialog(selection); + GPInfoScreen *gpis = GPInfoScreen::getInstance(); + gpis->setGP( selection == "Random Grand Prix" ? "random" + : selection); + StateManager::get()->pushScreen(gpis); } } else if (name == "trackgroups") diff --git a/src/tracks/check_manager.cpp b/src/tracks/check_manager.cpp index 7ece0621e..1281fd1cb 100644 --- a/src/tracks/check_manager.cpp +++ b/src/tracks/check_manager.cpp @@ -150,6 +150,7 @@ unsigned int CheckManager::getLapLineIndex() const } Log::fatal("CheckManager", "Error, no kind of lap line for track found, aborting."); + return -1; } // getLapLineIndex // ---------------------------------------------------------------------------- diff --git a/src/tracks/model_definition_loader.cpp b/src/tracks/model_definition_loader.cpp index 0e0303ced..98159e961 100644 --- a/src/tracks/model_definition_loader.cpp +++ b/src/tracks/model_definition_loader.cpp @@ -22,7 +22,6 @@ using namespace irr; #include "graphics/irr_driver.hpp" #include "graphics/lod_node.hpp" #include "graphics/mesh_tools.hpp" -#include "graphics/stkinstancedscenenode.hpp" #include "io/xml_node.hpp" #include "tracks/track.hpp" @@ -111,35 +110,6 @@ LODNode* ModelDefinitionLoader::instanciateAsLOD(const XMLNode* node, scene::ISc // ---------------------------------------------------------------------------- -STKInstancedSceneNode* ModelDefinitionLoader::instanciate(const irr::core::vector3df& position, - const irr::core::vector3df& rotation, - const irr::core::vector3df scale, - const std::string& name) -{ - if (m_instancing_nodes.find(name) == m_instancing_nodes.end()) - { - if (m_lod_groups.find(name) == m_lod_groups.end()) - { - Log::warn("Instancing", "Cannot find instancing model <%s>", name.c_str()); - return NULL; - } - - scene::IMesh* mesh = irr_driver->getMesh(m_lod_groups[name][0].m_model_file); - mesh = MeshTools::createMeshWithTangents(mesh, &MeshTools::isNormalMap); - irr_driver->setAllMaterialFlags(mesh); - - m_instancing_nodes[name] = new STKInstancedSceneNode(mesh, - irr_driver->getSceneManager()->getRootSceneNode(), irr_driver->getSceneManager(), -1); - m_track->addNode(m_instancing_nodes[name]); - } - - m_instancing_nodes[name]->addInstance(position, rotation, scale); - m_instancing_nodes[name]->instanceGrab(); - return m_instancing_nodes[name]; -} - -// ---------------------------------------------------------------------------- - void ModelDefinitionLoader::clear() { m_lod_groups.clear(); diff --git a/src/tracks/model_definition_loader.hpp b/src/tracks/model_definition_loader.hpp index 3c750348d..b3bf75694 100644 --- a/src/tracks/model_definition_loader.hpp +++ b/src/tracks/model_definition_loader.hpp @@ -83,10 +83,6 @@ public: void addModelDefinition(const XMLNode* xml); LODNode* instanciateAsLOD(const XMLNode* xml_node, scene::ISceneNode* parent); - STKInstancedSceneNode* instanciate(const core::vector3df& position, - const irr::core::vector3df& rotation, - const irr::core::vector3df scale, - const std::string& name); void clear(); diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 6c46d2eff..5b3b255a2 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -37,7 +37,6 @@ #include "graphics/particle_emitter.hpp" #include "graphics/particle_kind.hpp" #include "graphics/particle_kind_manager.hpp" -#include "graphics/stkinstancedscenenode.hpp" #include "graphics/stk_text_billboard.hpp" #include "guiengine/scalable_font.hpp" #include "io/file_manager.hpp" @@ -132,7 +131,10 @@ Track::Track(const std::string &filename) m_sky_particles = NULL; m_sky_dx = 0.05f; m_sky_dy = 0.0f; - m_weather_type = WEATHER_NONE; + m_godrays_opacity = 1.0f; + m_godrays_color = video::SColor(255, 255, 255, 255); + m_weather_lightning = false; + m_weather_sound = ""; m_cache_track = UserConfigParams::m_cache_overworld && m_ident=="overworld"; m_minimap_x_scale = 1.0f; @@ -272,7 +274,7 @@ void Track::cleanup() { QuadGraph::destroy(); ItemManager::destroy(); - resetVAO(); + VAOManager::kill(); ParticleKindManager::get()->cleanUpTrackSpecificGfx(); // Clear reminder of transformed textures @@ -427,7 +429,6 @@ void Track::cleanup() } #endif } // if verbose - } // cleanup //----------------------------------------------------------------------------- @@ -442,6 +443,9 @@ void Track::loadTrackInfo() m_fog_height_end = 100.0f; m_gravity = 9.80665f; m_smooth_normals = false; + m_godrays = false; + m_godrays_opacity = 1.0f; + m_godrays_color = video::SColor(255, 255, 255, 255); /* ARGB */ m_fog_color = video::SColor(255, 77, 179, 230); m_default_ambient_color = video::SColor(255, 120, 120, 120); @@ -484,7 +488,6 @@ void Track::loadTrackInfo() root->get("bloom-threshold", &m_bloom_threshold); root->get("lens-flare", &m_lensflare); root->get("shadows", &m_shadows); - root->get("god-rays", &m_godrays); root->get("displacement-speed", &m_displacement_speed); root->get("caustics-speed", &m_caustics_speed); root->get("color-level-in", &m_color_inlevel); @@ -740,24 +743,10 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) node->updateAbsolutePosition(); std::vector<core::matrix4> matrices; - - STKInstancedSceneNode* instancing_node = dynamic_cast<STKInstancedSceneNode*>(node); - if (instancing_node != NULL) - { - int count = instancing_node->getInstanceCount(); - for (int i = 0; i < count; i++) - { - matrices.push_back(instancing_node->getInstanceTransform(i)); - } - } - else - { - matrices.push_back(node->getAbsoluteTransformation()); - } + matrices.push_back(node->getAbsoluteTransformation()); const core::vector3df &pos = node->getAbsolutePosition(); - scene::IMesh *mesh; // In case of readonly materials we have to get the material from // the mesh, otherwise from the node. This is esp. important for @@ -1061,20 +1050,6 @@ bool Track::loadMainTrack(const XMLNode &root) } } - // Load instancing models (for the moment they are loaded the same way as LOD to simplify implementation) - const XMLNode *instancing_xml_node = root.getNode("instancing"); - if (instancing_xml_node != NULL) - { - for (unsigned int i = 0; i < instancing_xml_node->getNumNodes(); i++) - { - const XMLNode* lod_group_xml = instancing_xml_node->getNode(i); - for (unsigned int j = 0; j < lod_group_xml->getNumNodes(); j++) - { - lodLoader.addModelDefinition(lod_group_xml->getNode(j)); - } - } - } - for (unsigned int i=0; i<track_node->getNumNodes(); i++) { const XMLNode *n=track_node->getNode(i); @@ -1734,6 +1709,14 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) node->get("fog-end-height", &m_fog_height_end); } + if (const XMLNode *node = root->getNode("lightshaft")) + { + m_godrays = true; + node->get("opacity", &m_godrays_opacity); + node->get("color", &m_godrays_color); + node->get("xyz", &m_godrays_position); + } + loadMainTrack(*root); unsigned int main_track_count = m_all_nodes.size(); @@ -1753,20 +1736,6 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) } } - // Load instancing models (for the moment they are loaded the same way as LOD to simplify implementation) - const XMLNode *instancing_xml_node = root->getNode("instancing"); - if (instancing_xml_node != NULL) - { - for (unsigned int i = 0; i < instancing_xml_node->getNumNodes(); i++) - { - const XMLNode* lod_group_xml = instancing_xml_node->getNode(i); - for (unsigned int j = 0; j < lod_group_xml->getNumNodes(); j++) - { - model_def_loader.addModelDefinition(lod_group_xml->getNode(j)); - } - } - } - std::map<std::string, XMLNode*> library_nodes; loadObjects(root, path, model_def_loader, true, NULL, library_nodes); @@ -2007,20 +1976,6 @@ void Track::loadObjects(const XMLNode* root, const std::string& path, ModelDefin } } } - - // Load instancing definitions - const XMLNode *instancing_xml_node = libroot->getNode("instancing"); - if (instancing_xml_node != NULL) - { - for (unsigned int i = 0; i < instancing_xml_node->getNumNodes(); i++) - { - const XMLNode* instancing_group_xml = instancing_xml_node->getNode(i); - for (unsigned int j = 0; j < instancing_group_xml->getNumNodes(); j++) - { - model_def_loader.addModelDefinition(instancing_group_xml->getNode(j)); - } - } - } } else { @@ -2029,11 +1984,15 @@ void Track::loadObjects(const XMLNode* root, const std::string& path, ModelDefin } scene::ISceneNode* parent = irr_driver->getSceneManager()->addEmptySceneNode(); +#ifdef DEBUG + parent->setName(("libnode_" + name).c_str()); +#endif parent->setPosition(xyz); parent->setRotation(hpr); parent->setScale(scale); parent->updateAbsolutePosition(); loadObjects(libroot, lib_path, model_def_loader, create_lod_definitions, parent, library_nodes); + //m_all_nodes.push_back(parent); } else if (name == "water") { @@ -2095,27 +2054,16 @@ void Track::loadObjects(const XMLNode* root, const std::string& path, ModelDefin else if (name == "weather") { std::string weather_particles; - std::string weather_type; + node->get("particles", &weather_particles); - node->get("type", &weather_type); + node->get("lightning", &m_weather_lightning); + node->get("sound", &m_weather_sound); if (weather_particles.size() > 0) { m_sky_particles = ParticleKindManager::get()->getParticles(weather_particles); } - else if (weather_type.size() > 0) - { - if (weather_type == "rain") - { - m_weather_type = WEATHER_RAIN; - } - else - { - Log::error("track", "Unknown weather type : '%s'", - weather_type.c_str()); - } - } else { Log::error("track", "Bad weather node found - ignored.\n"); @@ -2132,7 +2080,7 @@ void Track::loadObjects(const XMLNode* root, const std::string& path, ModelDefin } else if (name == "instancing") { - // handled above + // TODO: eventually remove, this is now automatic } else if (name == "subtitles") { diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp index cd442b62c..1bdf040fb 100644 --- a/src/tracks/track.hpp +++ b/src/tracks/track.hpp @@ -67,12 +67,6 @@ namespace Scripting const int HEIGHT_MAP_RESOLUTION = 256; -enum WeatherType -{ - WEATHER_NONE, - WEATHER_RAIN -}; - struct OverworldForceField { core::vector3df m_position; @@ -317,7 +311,8 @@ private: ParticleKind* m_sky_particles; /** Use a special built-in wheather */ - WeatherType m_weather_type; + bool m_weather_lightning; + std::string m_weather_sound; /** A simple class to keep information about a track mode. */ class TrackMode @@ -390,7 +385,12 @@ private: float m_bloom_threshold; bool m_lensflare; + bool m_godrays; + core::vector3df m_godrays_position; + float m_godrays_opacity; + video::SColor m_godrays_color; + bool m_shadows; float m_displacement_speed; @@ -408,6 +408,7 @@ private: /** The number of laps the track will be raced in a random GP. * m_actual_number_of_laps is initialised with this value.*/ int m_default_number_of_laps; + /** The number of laps that is predefined in a track info dialog. */ int m_actual_number_of_laps; @@ -426,7 +427,7 @@ private: public: - bool reverseAvailable() { return m_reverse_available; } + bool reverseAvailable() const { return m_reverse_available; } void handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml); static const float NOHIT; @@ -470,8 +471,16 @@ public: /** Returns true if this track has an arena mode. */ bool isArena() const { return m_is_arena; } // ------------------------------------------------------------------------ + /** Returns true if this track is a racing track. This means it is not an + * internal track (like cut scenes), arena, or soccer field. */ + bool isRaceTrack() const + { + return !m_internal && !m_is_arena && !m_is_soccer; + } // isRaceTrack + // ------------------------------------------------------------------------ /** Returns true if this track has easter eggs. */ bool hasEasterEggs() const { return m_has_easter_eggs; } + // ------------------------------------------------------------------------ bool isSoccer () const { return m_is_soccer; } // ------------------------------------------------------------------------ void loadTrackModel (World* parent, @@ -568,7 +577,9 @@ public: unsigned int getNumberOfStartPositions() const { return m_start_transforms.size(); } // ------------------------------------------------------------------------ - WeatherType getWeatherType () const { return m_weather_type; } + bool getWeatherLightning() {return m_weather_lightning;} + // ------------------------------------------------------------------------ + std::string getWeatherSound() {return m_weather_sound;} // ------------------------------------------------------------------------ ParticleKind* getSkyParticles () { return m_sky_particles; } // ------------------------------------------------------------------------ @@ -620,6 +631,9 @@ public: bool hasLensFlare() const { return m_lensflare; } bool hasGodRays() const { return m_godrays; } + core::vector3df getGodRaysPosition() const { return m_godrays_position; } + float getGodRaysOpacity() const { return m_godrays_opacity; } + video::SColor getGodRaysColor() const { return m_godrays_color; } bool hasShadows() const { return m_shadows; } void addNode(scene::ISceneNode* node) { m_all_nodes.push_back(node); } diff --git a/src/tracks/track_manager.cpp b/src/tracks/track_manager.cpp index b2092b13e..94c9a5637 100644 --- a/src/tracks/track_manager.cpp +++ b/src/tracks/track_manager.cpp @@ -57,6 +57,19 @@ void TrackManager::addTrackSearchDir(const std::string &dir) m_track_search_path.push_back(dir); } // addTrackDir +//----------------------------------------------------------------------------- +/** Returns the number of racing tracks. Those are tracks that are not + * internal (like cut scenes), arenas, or soccer fields. + */ +int TrackManager::getNumberOfRaceTracks() const +{ + int n=0; + for(unsigned int i=0; i<m_tracks.size(); i++) + if(m_tracks[i]->isRaceTrack()) + n++; + return n; +} // getNumberOfRaceTracks + //----------------------------------------------------------------------------- /** Get TrackData by the track identifier. * \param ident Identifier = basename of the directory the track is in. diff --git a/src/tracks/track_manager.hpp b/src/tracks/track_manager.hpp index 3faf53921..7d2b86ed1 100644 --- a/src/tracks/track_manager.hpp +++ b/src/tracks/track_manager.hpp @@ -53,9 +53,6 @@ private: /** List of all soccer arena groups. */ Group2Indices m_soccer_arena_groups; - /** List of all groups (for both normal tracks and arenas) */ - //std::vector<std::string> m_all_group_names; - /** List of the names of all groups containing tracks */ std::vector<std::string> m_track_group_names; @@ -85,6 +82,7 @@ public: void removeTrack(const std::string &ident); bool loadTrack(const std::string& dirname); void removeAllCachedData(); + int getNumberOfRaceTracks() const; Track* getTrack(const std::string& ident) const; // ------------------------------------------------------------------------ /** Sets a list of track as being unavailable (e.g. in network mode the diff --git a/src/tracks/track_object.cpp b/src/tracks/track_object.cpp index e5566bdd2..7ddc7fe85 100644 --- a/src/tracks/track_object.cpp +++ b/src/tracks/track_object.cpp @@ -105,9 +105,6 @@ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent, bool lod_instance = false; xml_node.get("lod_instance", &lod_instance); - bool instancing = false; - xml_node.get("instancing", &instancing); - m_soccer_ball = false; xml_node.get("soccer_ball", &m_soccer_ball); @@ -163,14 +160,7 @@ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent, { scene::ISceneNode *glownode = NULL; - if (instancing) - { - m_type = "lod"; - TrackObjectPresentationInstancing* instancing_node = - new TrackObjectPresentationInstancing(xml_node, parent, model_def_loader); - m_presentation = instancing_node; - } - else if (lod_instance) + if (lod_instance) { m_type = "lod"; TrackObjectPresentationLOD* lod_node = diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index 9d4f5950d..0e568fd64 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -28,7 +28,6 @@ #include "graphics/particle_emitter.hpp" #include "graphics/particle_kind_manager.hpp" #include "graphics/stkmeshscenenode.hpp" -#include "graphics/stkinstancedscenenode.hpp" #include "io/file_manager.hpp" #include "io/xml_node.hpp" #include "input/device_manager.hpp" @@ -169,59 +168,6 @@ TrackObjectPresentationLOD::~TrackObjectPresentationLOD() // ---------------------------------------------------------------------------- -TrackObjectPresentationInstancing::TrackObjectPresentationInstancing(const XMLNode& xml_node, - scene::ISceneNode* parent, - ModelDefinitionLoader& model_def_loader) : TrackObjectPresentationSceneNode(xml_node) -{ - m_instancing_group = NULL; - m_fallback_scene_node = NULL; - - std::string instancing_model; - xml_node.get("instancing_model", &instancing_model); - - m_node = irr_driver->getSceneManager()->addEmptySceneNode(parent); - m_node->setPosition(m_init_xyz); - m_node->setRotation(m_init_hpr); - m_node->setScale(m_init_scale); - m_node->updateAbsolutePosition(); - if (irr_driver->isGLSL()) - { - m_instancing_group = model_def_loader.instanciate(m_node->getAbsolutePosition(), - m_node->getAbsoluteTransformation().getRotationDegrees(), m_node->getAbsoluteTransformation().getScale(), - instancing_model); - } - else - { - scene::IMesh* mesh = model_def_loader.getFirstMeshFor(instancing_model); - scene::IMeshSceneNode* node = irr_driver->addMesh(mesh, m_node); - node->grab(); - irr_driver->grabAllTextures(mesh); - mesh->grab(); - World::getWorld()->getTrack()->addNode(node); - - m_fallback_scene_node = node; - } -} - -TrackObjectPresentationInstancing::~TrackObjectPresentationInstancing() -{ - if (m_instancing_group != NULL) - m_instancing_group->instanceDrop(); - - if (m_fallback_scene_node != NULL) - { - scene::IMesh* mesh = m_fallback_scene_node->getMesh(); - irr_driver->dropAllTextures(mesh); - mesh->drop(); - if (mesh->getReferenceCount() == 1) - irr_driver->removeMeshFromCache(mesh); - - m_fallback_scene_node->drop(); - } -} - -// ---------------------------------------------------------------------------- - TrackObjectPresentationMesh::TrackObjectPresentationMesh(const XMLNode& xml_node, bool enabled, scene::ISceneNode* parent) : TrackObjectPresentationSceneNode(xml_node) diff --git a/src/tracks/track_object_presentation.hpp b/src/tracks/track_object_presentation.hpp index 161c88646..ad427d52c 100644 --- a/src/tracks/track_object_presentation.hpp +++ b/src/tracks/track_object_presentation.hpp @@ -171,20 +171,6 @@ public: virtual ~TrackObjectPresentationLOD(); }; -class TrackObjectPresentationInstancing : public TrackObjectPresentationSceneNode -{ - STKInstancedSceneNode* m_instancing_group; - scene::IMeshSceneNode* m_fallback_scene_node; -public: - - TrackObjectPresentationInstancing(const XMLNode& xml_node, - scene::ISceneNode* parent, - ModelDefinitionLoader& model_def_loader); - virtual ~TrackObjectPresentationInstancing(); - - STKInstancedSceneNode* getInstancingGroup() { return m_instancing_group; } -}; - /** * \ingroup tracks * A track object representation that consists of a mesh scene node. diff --git a/src/utils/cpp2011.hpp b/src/utils/cpp2011.hpp index d1d5a2d79..2cf0a2f88 100644 --- a/src/utils/cpp2011.hpp +++ b/src/utils/cpp2011.hpp @@ -27,4 +27,28 @@ void pushVector(std::vector<T> *vec, Args ...args) vec->emplace_back(args...); #endif } + +struct Util +{ + template <typename T> + static void populate(std::vector<T> &v) + { } + + template <typename T, typename...Args> + static void populate(std::vector<T> &v, T t, Args... args) + { + v.push_back(t); + populate<T>(v, args...); + } +}; + + +template<typename T, typename...Args> +static std::vector<T> createVector(Args...args) +{ + std::vector<T> result = std::vector<T>(); + Util::template populate<T>(result, args...); + return result; +} + #endif \ No newline at end of file diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index 57a74ec8e..a6bfc6fcc 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -34,6 +34,7 @@ #include "utils/profiler.hpp" #include <IGUIEnvironment.h> #include <IGUIContextMenu.h> + using namespace irr; using namespace gui; @@ -436,34 +437,36 @@ bool onEvent(const SEvent &event) } else if (cmdID == DEBUG_VISUAL_VALUES) { +#if !defined(__APPLE__) DebugSliderDialog *dsd = new DebugSliderDialog(); - dsd->setSliderHook( "red_slider", 0, 255, [](){ return irr_driver->getAmbientLight().r * 255.; }, + dsd->setSliderHook( "red_slider", 0, 255, [](){ return irr_driver->getAmbientLight().r * 255.f; }, [](int v){ video::SColorf ambient = irr_driver->getAmbientLight(); - ambient.setColorComponentValue(0, v / 255.); + ambient.setColorComponentValue(0, v / 255.f); irr_driver->setAmbientLight(ambient); } ); - dsd->setSliderHook("green_slider", 0, 255, [](){ return irr_driver->getAmbientLight().g * 255.; }, + dsd->setSliderHook("green_slider", 0, 255, [](){ return irr_driver->getAmbientLight().g * 255.f; }, [](int v){ video::SColorf ambient = irr_driver->getAmbientLight(); - ambient.setColorComponentValue(1, v / 255.); + ambient.setColorComponentValue(1, v / 255.f); irr_driver->setAmbientLight(ambient); } ); - dsd->setSliderHook("blue_slider", 0, 255, [](){ return irr_driver->getAmbientLight().b * 255.; }, + dsd->setSliderHook("blue_slider", 0, 255, [](){ return irr_driver->getAmbientLight().b * 255.f; }, [](int v){ video::SColorf ambient = irr_driver->getAmbientLight(); - ambient.setColorComponentValue(2, v / 255.); + ambient.setColorComponentValue(2, v / 255.f); irr_driver->setAmbientLight(ambient); } ); - dsd->setSliderHook("ssao_radius", 0, 100, [](){ return irr_driver->getSSAORadius() * 10; }, - [](int v){irr_driver->setSSAORadius(v / 10.); } + dsd->setSliderHook("ssao_radius", 0, 100, [](){ return irr_driver->getSSAORadius() * 10.f; }, + [](int v){irr_driver->setSSAORadius(v / 10.f); } ); - dsd->setSliderHook("ssao_k", 0, 100, [](){ return irr_driver->getSSAOK() * 10; }, - [](int v){irr_driver->setSSAOK(v / 10.); } + dsd->setSliderHook("ssao_k", 0, 100, [](){ return irr_driver->getSSAOK() * 10.f; }, + [](int v){irr_driver->setSSAOK(v / 10.f); } ); - dsd->setSliderHook("ssao_sigma", 0, 100, [](){ return irr_driver->getSSAOSigma() * 10; }, - [](int v){irr_driver->setSSAOSigma(v / 10.); } + dsd->setSliderHook("ssao_sigma", 0, 100, [](){ return irr_driver->getSSAOSigma() * 10.f; }, + [](int v){irr_driver->setSSAOSigma(v / 10.f); } ); +#endif } } diff --git a/src/utils/profiler.cpp b/src/utils/profiler.cpp index 11eb7ba63..6df0432dd 100644 --- a/src/utils/profiler.cpp +++ b/src/utils/profiler.cpp @@ -33,6 +33,7 @@ static const char* GPU_Phase[Q_LAST] = { "Solid Pass 1", "Shadows", + "RSM", "RH", "GI", "Env Map", @@ -255,6 +256,7 @@ void Profiler::synchronizeFrame() /// Draw the markers void Profiler::draw() { + PROFILER_PUSH_CPU_MARKER("ProfilerDraw", 0xFF, 0xFF, 0x00); video::IVideoDriver* driver = irr_driver->getVideoDriver(); std::stack<Marker> hovered_markers; @@ -263,7 +265,7 @@ void Profiler::draw() // Force to show the pointer irr_driver->showPointer(); - int read_id = (m_freeze_state == FROZEN ? !m_write_id : m_write_id); + int read_id = !m_write_id; // Compute some values for drawing (unit: pixels, but we keep floats for reducing errors accumulation) core::dimension2d<u32> screen_size = driver->getScreenSize(); @@ -293,7 +295,7 @@ void Profiler::draw() else end = std::max(end, m.end); } } - + const double duration = end - start; const double factor = profiler_width / duration; @@ -351,33 +353,36 @@ void Profiler::draw() m_first_capture_sweep = false; } } - + + // GPU profiler QueryPerf hovered_gpu_marker = Q_LAST; long hovered_gpu_marker_elapsed = 0; + int gpu_y = int(y_offset + nb_thread_infos*line_height + line_height/2); + float total = 0; + unsigned int gpu_timers[Q_LAST]; + for (unsigned i = 0; i < Q_LAST; i++) + { + gpu_timers[i] = irr_driver->getGPUTimer(i).elapsedTimeus(); + total += gpu_timers[i]; + } + + static video::SColor colors[] = { + video::SColor(255, 255, 0, 0), + video::SColor(255, 0, 255, 0), + video::SColor(255, 0, 0, 255), + video::SColor(255, 255, 255, 0), + video::SColor(255, 255, 0, 255), + video::SColor(255, 0, 255, 255) + }; + if (hovered_markers.size() == 0) { - int gpu_y = int(y_offset + nb_thread_infos*line_height + line_height/2); - float total = 0; - for (unsigned i = 0; i < Q_LAST; i++) - { - total += irr_driver->getGPUTimer(i).elapsedTimeus(); - } - - static video::SColor colors[] = { - video::SColor(255, 255, 0, 0), - video::SColor(255, 0, 255, 0), - video::SColor(255, 0, 0, 255), - video::SColor(255, 255, 255, 0), - video::SColor(255, 255, 0, 255), - video::SColor(255, 0, 255, 255) - }; - float curr_val = 0; for (unsigned i = 0; i < Q_LAST; i++) { //Log::info("GPU Perf", "Phase %d : %d us\n", i, irr_driver->getGPUTimer(i).elapsedTimeus()); - float elapsed = float(irr_driver->getGPUTimer(i).elapsedTimeus()); + float elapsed = float(gpu_timers[i]); core::rect<s32> pos((s32)(x_offset + (curr_val / total)*profiler_width), (s32)(y_offset + gpu_y), (s32)(x_offset + ((curr_val + elapsed) / total)*profiler_width), @@ -389,7 +394,7 @@ void Profiler::draw() if (pos.isPointInside(mouse_pos)) { hovered_gpu_marker = (QueryPerf)i; - hovered_gpu_marker_elapsed = irr_driver->getGPUTimer(i).elapsedTimeus(); + hovered_gpu_marker_elapsed = gpu_timers[i]; } if (m_capture_report) @@ -421,7 +426,7 @@ void Profiler::draw() // Draw the hovered markers' names gui::ScalableFont* font = GUIEngine::getFont(); - if(font) + if (font) { core::stringw text; while(!hovered_markers.empty()) @@ -449,6 +454,8 @@ void Profiler::draw() { font->draw("Capturing profiler report...", MARKERS_NAMES_POS, video::SColor(0xFF, 0x00, 0x90, 0x00)); } + + PROFILER_POP_CPU_MARKER(); } //----------------------------------------------------------------------------- diff --git a/src/utils/vs.hpp b/src/utils/vs.hpp index ffc47ba16..017f07400 100644 --- a/src/utils/vs.hpp +++ b/src/utils/vs.hpp @@ -11,3 +11,7 @@ # define round(x) (floorf(x + 0.5)) #endif +#ifdef __MINGW32__ + #include <cmath> + using std::isnan; +#endif diff --git a/src/windows_installer/icon_rc.template b/src/windows_installer/icon_rc.template new file mode 100644 index 000000000..d9cc5fd32 --- /dev/null +++ b/src/windows_installer/icon_rc.template @@ -0,0 +1 @@ +100 ICON "@PROJECT_SOURCE_DIR@/src/windows_installer/icon.ico"