mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 08:15:59 -10:00
Add Vulkan rendering backend, with HDR10 output and raytraced shadows (#7554)
* Shadow overhaul round 2: PCSS, dynamic cascades, cockpit/instanced shadows Squashed snapshot of lafiel/shadow_overhaul_2's continuation work (d3922aa87..010f9d2d9), which has no separate upstream PR of its own. * Add Vulkan rendering backend Squashed snapshot of the Vulkan backend as vendored into this branch (ce2d1e85f..6ce539463, authored by Mara van der Laan with build/CI fixes by Taylor Richards). This work has its own upstream PR #7553 (notimaginative:vulkan-pr-new) and is not otherwise original to true-hdr. * Add true HDR output, RT shadows, and PCSS shadows for Vulkan Squashed snapshot of true-hdr's own integration work: true HDR framebuffer output, wiring the shadow overhaul into the Vulkan backend (raytraced + cascaded shadow maps), logging refactors, log filter UI, and CI/build fixes. * refactor: update Vulkan logging calls to use `nprintf` for scoped logging * fix: correct shadow cascade count in Vulkan logging calls * fix: fall back to PATH-resolved ccache when CCACHE_PATH is stale CI hardcodes /usr/local/bin/ccache, but macOS runners on Apple Silicon hosts install Homebrew (and ccache) under /opt/homebrew instead, causing all four Mac configs to fail with "No such file or directory". * Fix vulkan texture readback to correctly handle transparent pipelines * Put the pixel swizzles into a util file * OOB safety check * Fix fog handling * Fix MSAA in Vulkan * fix: enable SMAA for vulkan * adapt the post-processing AA shaders to hdr * fix clang-tidy warnings: concatenate nested namespaces, static methods pixel_swizzle.{h,cpp}: collapse `namespace graphics { namespace util {` into `namespace graphics::util {` (modernize-concat-nested-namespaces). VulkanState.h/VulkanDraw.h: getClearColor()/setClearColor() only touch gr_screen and other globals, no instance state, so make them static (readability-convert-member-functions-to-static) and drop the top-level const on getClearColor()'s return type (readability-const-return-type). * fix clang-tidy warning * Extend raytraced shadows to all directional lights RT shadows previously only shadowed the first directional light in the scene, even though multi-sun missions push more than one directional light into the engine. The TLAS raytraced shadows query against is already light-agnostic, so this extends both the deferred lighting pass and the forward MODEL shader to shadow every directional light (capped by a new Max Raytraced Shadow Lights option, configurable via the in-game Options menu or the Lab's Scene rendering options). Cascaded shadow maps are untouched: they're built for a single light only, so the deferred pass still limits itself to one shadowed directional light whenever CSM (not raytracing) is the active method. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_016DA6JHJ3twz2oHGQcZ1Udc * refactor: improve shader flag handling and render target finalization in Vulkan backend - Consolidate shader flag setup logic in VulkanPostProcessingLighting to simplify configuration. - Fix dead field usage in VulkanDraw by ensuring correct image view selection for environment maps. - Add mip chain regeneration in VulkanRenderer::endRenderTarget to ensure correct mip levels for cubemaps. * fix: ensure correct mip chain initialization in cubemap rendering - Add mip chain generation to VulkanDraw for cubemaps with multiple mip levels. - Fix potential issue with uninitialized mip levels above level 0 in deferred-f.sdr sampling paths. * fix: don't crash on startup when environment locale is unavailable std::locale("") pulls in the process's environment locale categories (LC_CTYPE, LC_MONETARY, LC_PAPER, etc.), and throws std::runtime_error if any of them names a locale not installed on the host (e.g. mismatched regional-format overrides). Since SCP_default_locale is constructed during static initialization, before main() and before any of our own exception handling exists, an uncaught throw here aborted the whole process before the game even started. Fall back to the classic "C" locale instead, which is sufficient since this locale is only ever used for ASCII case-folding (SCP_toupper/tolower/isdigit). Co-Authored-By: Claude Sonnet 5 <[email protected]> * `feat: add raytraced shadows for local lights and optimize TLAS management` * Make the Commandline authoritative for -res and -vulkan / -opengl * address BMagnu's comments on the original PR * update prebuilt version hash to 62c89ef6 * refactor: standardize graphics API handling and document Vulkan limitations in qtFRED - Updated `AboutDialogModel.cpp` to use `GraphicsAPI` enum for better clarity. - Ensured qtFRED falls back to OpenGL when Vulkan is requested. - Added detailed documentation in `qtfred/README.md` regarding Vulkan backend limitations and requirements. * chore: include cmdline library in main and mission management modules * docs: add known issue for blank render viewport under Wayland in README.md * fix CI issues * chore: add `GR_DEBUG_SCOPE` markers across Vulkan post-processing and rendering paths for improved debugging * feat: improve Vulkan HDR pipeline with separate encode paths for SDR and HDR10 - Added an HDR10-specific output encode pass in `VulkanRenderer` and `VulkanPostProcessor` that applies PQ/BT.2020 transfer. - Introduced an optimized SDR fallback path with direct blit support for devices that can skip shader draws. - Updated `m_sceneLdrCompressed` to provide [0,1]-clamped proxies for HDR edge detection. - Refactored `copyImageToImage` and added `blitImageToImage` to allow format conversions and optimized transfers. - Replaced `hdr_mode` with explicit HDR10 flags and data structures for clearer state handling. * refactor: encapsulate SMAA processing and refactor VulkanPostProcessor - Moved SMAA-specific logic into `VulkanSMAA` class for better separation of concerns. - Simplified `initSMAA`, `shutdownSMAA`, and `executeSMAA` logic by leveraging `VulkanLDR` and `PostProcessContext` abstractions. - Improved initialization and cleanup code with clearer resource lifecycle management. - Updated debug markers and messages to reference `VulkanSMAA`. - Enhanced flexibility of fullscreen triangle rendering API with additional parameters (`sampleCount`, `bindGlobalSet`). * Update Vulkan porting credits in AboutDialogModel * fix CI issues again * fix: correct Y-flip in viewport setup for Vulkan light volumes - Adjusted viewport height to negative value to account for G-buffer render pass's negative Y-axis convention. - Ensured proper alignment of point and tube light volumes with actual light positions. * feat: add user-adjustable gamma correction to SDR and HDR10 output paths - Added gamma correction to HDR10 path, applying user settings before PQ/BT.2020 encode. - Replaced the SDR blit-only path with an encode pass that applies gamma correction, ensuring consistent behavior across devices. - Refactored VulkanPostProcessor and associated shaders to support gamma slider adjustments for both SDR and HDR output. * fix: ensure proper uniform and cull mode setup for Vulkan sphere rendering - Added uniform buffer setup and default material uniforms in `vulkan_draw_sphere`. - Disabled face culling in material definition for sphere rendering to align behavior with OpenGL. * Ensure memory flushes after UBO updates and add explicit pipeline barrier for MoltenVK compatibility. * fix: add clear pass for SMAA edge detection to prevent persistent artifacts * feat: add Vulkan debug-utils messenger, opt-in sync validation, frame diagnostics Groundwork for the renderer-review fix series (.agents/plans/ vulkan-renderer-review-fixes.md, Phase 0): - Register a VK_EXT_debug_utils messenger (preferred) instead of only the deprecated VK_EXT_debug_report callback, which is kept as a fallback for loaders without debug-utils. The messenger config is also chained into instance creation so vkCreateInstance-time messages are captured. Validation errors/warnings now go to the main log via mprintf. - New -gr_sync_validation cmdline flag (implies -gr_debug): chains VkValidationFeaturesEXT with synchronization validation into instance creation when VK_LAYER_KHRONOS_validation is available. This is the regression net for the synchronization fixes in the following commits. - Frame stats now report descriptor sets/writes allocated per frame and the total pipeline count (descriptor-manager counters; DescriptorWriter::flush moved out-of-line to report into the manager). Co-Authored-By: Claude Fable 5 <[email protected]> * refactor: unify Vulkan render-pass begins, clamp in-pass clears, add per-frame UBO ring Phase 1 of the renderer-review fix series: shared helpers that the correctness fixes build on. - New VulkanRenderer::beginTrackedRenderPass(PassBeginDesc): every render-pass begin on the frame command buffer now records vkCmdBeginRenderPass and updates the state tracker (pass, color attachment count, sample count, render area, viewport) in one place. Converted: setupFrame, beginSceneRendering (both branches), resumeSceneRendering, endSceneRendering, beginRenderTarget (viewport kept for gr_set_viewport), resumeSwapChainPass, plus new resumeScenePassAfterCopy() shared by copyEffectTexture/copySceneDepthForParticles and rebeginSwapChainPassAfterReadback() shared by both readbackFramebuffer exits (~200 lines of duplicated begin/clear/viewport blocks removed). - The state tracker records the active render area; all four vkCmdClearAttachments sites clamp their rects against it and skip empty results. Previously gr_screen-sized clear rects could exceed a smaller off-screen render target's render area, which is invalid API usage. - New PerFrameUboRing utility (VulkanPerFrameUbo.h/.cpp): a persistently mapped uniform buffer with one slot region per frame in flight and a self-flushing alloc(). Used by the next commit to fix the cross-frame UBO races. Deliberate behavior deltas (all safe-direction): the helper always sets colorAttachmentCount/sampleCount (some sites previously inherited stale values), and resumeSwapChainPass/resumeSceneRendering now also reset the standard flipped viewport instead of leaving the previous one. Co-Authored-By: Claude Fable 5 <[email protected]> * fix: eliminate Vulkan cross-frame UBO/buffer races, make gr_sync honest Phase 2 of the renderer-review fix series: with two frames in flight, several host-visible resources were rewritten by the CPU while the previous frame's GPU work could still be reading them. - The post-processing scratch UBO is now a PerFrameUboRing (per-frame-in- flight slot regions, persistently mapped, self-flushing alloc). All the per-pass map/unmap/cursor bookkeeping in bloom/LDR/fog/SMAA is deleted; the cursor resets exactly once per frame via the new VulkanPostProcessor::beginFrame() hook in setupFrame. This also fixes two latent bugs: (a) fog consumed scratch slots mid-scene and bloom's later same-frame cursor reset overwrote them before submission whenever fog+bloom were both active; (b) volumetric_fog_data (288 bytes) overflowed the 256-byte slots - the memcpy spilled into the neighboring slot and the shader's bound range ended before the aspect/fov/noise fields. Slots are now 512 bytes (static_assert at the fog call site) and the per-frame budget is 32 slots. - The dedicated tonemap, output-encode, and MSAA-resolve UBOs (each a single instance rewritten per frame, i.e. racy; the MSAA one also never flushed) are deleted entirely - those passes build their structs on the stack and allocate from the scratch ring. - Static-buffer rewrites orphan instead of racing: getVkBuffer() stamps a last-used frame number, and a full-content updateBufferData() on a Static buffer used within the last MAX_FRAMES_IN_FLIGHT frames defers the old VkBuffer to the deletion queue and writes a fresh one. Offset writes (GPU-heap appends to fresh regions) and PersistentMapping buffers (the engine holds their mapped pointer and syncs via gr_sync) are exempt. - gr_sync_wait now honors its contract: VulkanRenderFrame::waitForFinish takes a timeout and reports expiry without consuming the fence; VulkanRenderer::waitForFrame returns false for fences taken during the still-recording frame (previously it waited on a stale or idle slot and reported success) and resolves the frame->slot mapping correctly. This makes UniformBufferManager's segment-fence throttling actually protective on Vulkan for the first time. Co-Authored-By: Claude Fable 5 <[email protected]> * Refactor framebuffer and target lifecycle: centralized creation/resizing logic, improved resource management across Vulkan post-processing subsystems. * Improve Vulkan cross-frame sync with explicit access masks and validation updates - Unified Vulkan validation flag handling in setup, separating engine debug output from synchronization validation. - Specified access masks and stage flags to address cross-frame WRITE_AFTER_WRITE vulnerabilities, notably in G-buffer, post-processing, and MSAA resolve paths. - Adjusted subpass dependencies and image layout transitions to prevent read-after-write and write-after-write hazards, detected using `-gr_sync_validation`. - Fixed uniform buffer and barrier transitions to ensure proper ordering in render passes across frames. * Refactor Vulkan render-pass dependencies and sync stages for clarity and future testing - Clarified dependency logic for cross-pass and cross-frame synchronization, ensuring explicit stage and access flag comments match observed behavior. - Adjusted subpass dependencies to decouple render-pass compatibility definitions from dependency assumptions. - Highlighted MoltenVK-specific issues and retained workarounds with notes for re-testing on macOS hardware. - Updated synchronization barriers and validation notes to address historical inconsistencies across platforms. * Remove transfer queue support; consolidate all operations into the graphics queue - Removed transfer queue handling, simplifying buffer and queue logic to use the graphics queue for all transfer operations. - Updated buffer sharing modes and removed related code paths and parameters for transfer queue families. - Introduced exclusive buffer access, noting async transfer and queue ownership transfers are future work. - Limited enabled device features to only those actively used by the renderer, reducing unnecessary feature requests (e.g., robustBufferAccess). * Refactor frame advancement and descriptor management in VulkanRenderer - Removed `endFrame()` from `VulkanDescriptorManager`, replacing it with `setCurrentFrame(frameIndex)` for explicit frame synchronization. - Centralized frame index advancement within `VulkanRenderer` to ensure consistency across components. - Invalidated cached descriptor set bindings at render-pass boundaries to handle raw recorder staleness correctly. - Optimized pipeline descriptor rebind logic by removing redundant clears during pipeline changes. * Refactor `PipelineConfig::hash` and Global descriptor set management for improved hashing and memoization efficiency - Replaced inefficient shift-based hashing in `PipelineConfig::hash` with a robust `hashCombine` strategy to minimize bucket collisions. - Introduced `maskBits` helper to streamline bitmask creation for boolean fields. - Implemented memoization for Global (Set 0) descriptor sets, reducing redundant rebuilds across frames and improving performance. - Added dirty state tracking (`m_globalSetDirty`) and invalidation logic for Global set updates following relevant input changes (e.g., TLAS or UBO modifications). * Refactor Vulkan post-processing output logic: extracted shared `encodeToSwapChainPass` method to streamline HDR and SDR output paths. * Optimize Vulkan descriptor set management with per-frame memoization - Added memoization for Material (Set 1) and PerDraw (Set 2) descriptor sets to reuse cached sets across frames if inputs remain unchanged. - Implemented precise input tracking for Material and PerDraw descriptor sets to detect and rebuild only when necessary. - Reduced redundant Vulkan descriptor allocations and writes, improving performance on repeated or batched draw calls. * Fix Vulkan access masks for G-buffer and scene pass transitions - Added `eColorAttachmentRead` to access masks in multiple barriers to ensure proper synchronization for load operations (e.g., `loadOp=eLoad`) across render passes. - Prevented `READ_AFTER_WRITE` synchronization validation issues in deferred and multi-pass rendering scenarios. - Updated comments to clarify the reasoning behind the access mask changes and load dependencies. * Refactor Vulkan resource management and indexed draw logic - Consolidated destruction queue methods in `VulkanDeletionQueue` using a shared `queueHandle` template to reduce redundancy. - Introduced `ModelDrawParams` structure and `computeModelDrawParams` function to unify indexed draw parameters for models and shadows. - Simplified draw logic by eliminating repeated calculation of indexed draw parameters and improving code reuse. * Add `releaseAnimationSlotRef` for ref-count handling of shared animation texture arrays - Introduced `releaseAnimationSlotRef` to manage reference counting for shared animation texture-array slots, preventing premature destruction of shared resources. - Updated `flushTextures` and related methods to integrate `releaseAnimationSlotRef` for shared slot cleanup. - Refactored staging buffer creation into `createStagingBuffer` for 3D texture uploads and shared path consistency. - Enhanced texture upload logic with improved tracking and logging for re-upload cases, aiding preloading gap analysis. - Added instrumentation for on-demand mid-frame texture uploads in `FrameStats`. * Refactor Vulkan resource and texture management, extend debug logging - Updated smart pointer usage for consistency across Vulkan resource managers (`std::make_unique`). - Removed redundant `cubeImageView` member and related cleanup logic; unified sampling view management. - Added per-instance debug log counters (avoiding static state) for Vulkan texture uploads and bindings, improving visibility during initialization and run-time. - Optimized `VulkanRenderer` property/feature getters by caching physical device properties and features during device creation. - Improved memory region flushing logic for out-of-date offsets, aligning with Vulkan Memory Allocator behavior. - Refactored render pass state tracking to reapply dynamic state reliably after mid-frame render passes. - Enhanced validation and error handling for mismatched update texture formats. * fix CI build warning * Fix on-demand YUV texture locking and set alpha uniform for movie rendering in Vulkan - Corrected bitmap lock type from `BMP_TEX_OTHER` to `BMP_AABITMAP` for YUV textures during on-demand loading. - Updated movie rendering to bind alpha from the `MovieData` UBO (set 2, binding 4) for Vulkan, aligning behavior with OpenGL implementation. * revert inadvertent changes introduced by a squash commit * address ci issues * remove wip stuff from code comments that make no sense to people who aren't me * Remove unused LD_LIBRARY_PATH export and fix shader shadow map sampling. * Refactor batched rendering uniform setup in Vulkan - Removed unused fields from `genericData` uniform block, simplifying shader definitions. - Updated Vulkan material uniform handling to align with OpenGL's batched rendering logic. - Introduced `batched_data` struct for streamlined UBO updates, improving maintainability and clarity. * Add `-hdr` command-line option for HDR nits configuration - Introduced `-hdr` parameter to set paper white and peak luminance in nits, overriding in-game HDR settings. - Added input validation with error feedback for incorrect format. * Remove unused `MODEL_SDR_FLAG_SHADOW_MAP` macro from shader flags * clean up unrelated changes * Invalidate Vulkan state tracker bindings after external command buffer modifications - Added `invalidateExternalBindings()` to `VulkanStateTracker` to handle stale pipelines, descriptors, and dynamic states caused by external Vulkan commands (e.g., ImGui renders mid-pass). - Updated ImGui rendering flow to call `invalidateExternalBindings()` post-draw, ensuring consistent pipeline state for subsequent engine renders. - Adjusted image usage flags to account for `eTransferSrc` in texture readbacks. - Fixed barrier `dstAccessMask` and pipeline stage flags to ensure proper synchronization for image transitions. * Add a few more generically useful lines to the log * Simplify Qt deployment logic and improve handling for system-installed Qt on Linux * add cmdline headers to make qtFred compile * use VK_KHR_synchronization2 for sync and barrier purposes * Simplify and clean up Qt deployment logic in CMake for qtfred * update get_bitmap_from_texture to match the new API * Enhance `-hdr` command-line option to force HDR output and support optional nits configuration with improved input validation and overrides. * Improve Vulkan robustness, add device feature checks, and refine memory/logging. - Added depth clamping support gated by device feature checks, with fallback where unsupported. - Improved deferred lighting UBO overflow handling with user-accessible warnings and buffer size adjustments. - Enhanced Vulkan logging for validation, allocation, and debugging: - Automatic logging for descriptor pool exhaustion/fragmentation. - Vertex format and resource destruction checks. - Notifications for generic layout transitions and volumetric texture uploads. - Consolidated shader logic to ensure Vulkan and OpenGL parity. * Remove HDR10 encode shader and consolidate gamma correction logic for SDR and HDR10. Replace `Verify` assertions with `Assert` * Add braces to conditional in object lighting logic for clarity * Refine Vulkan memory allocation checks with `Verification` for improved error handling and messaging. * Refine VulkanBuffer resize logic to preserve contents with CPU-side copy and add safeguards for non-coherent memory scenarios. * Add detailed comments explaining descriptor array capacity constants in VulkanDescriptorManager * Gate shadow support on depth clamp feature availability and clarify its necessity with improved comments. --------- Co-authored-by: BMagnu <[email protected]> Co-authored-by: Mara van der Laan <[email protected]> Co-authored-by: Claude <[email protected]>
This commit is contained in:
228 files changed
+48749
-2973
No files matched your search
+1
-1
@@ -134,7 +134,7 @@ OPTION(FSO_BUILD_WITH_OPENGL "Enable compilation of the OpenGL renderer" ON)
|
||||
OPTION(FSO_BUILD_WITH_OPENGL_DEBUG "Enables debug option for OpenGL" OFF)
|
||||
OPTION(FSO_BUILD_WITH_OPENGL_ES "When building OpenGL, use OpenGL ES compatibility layer (External shaders only!)" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" OFF)
|
||||
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" ON)
|
||||
|
||||
if(NOT FSO_BUILD_WITH_OPENGL AND FSO_BUILD_WITH_OPENGL_ES)
|
||||
# Disable GLES if not building with OpenGL
|
||||
|
||||
@@ -18,13 +18,8 @@ fi
|
||||
# branch
|
||||
BASE_COMMIT=$(git merge-base $1 $2)
|
||||
|
||||
# Note: Manually passing in the Vulkan flags that are normally provided by cmake (but are not so, here), to ensure
|
||||
# that the source files are checked with the actual configuration used.
|
||||
echo "Running clang-tidy on changed files"
|
||||
git diff -U0 --no-color "$BASE_COMMIT..$2" | \
|
||||
$HERE/clang-tidy-diff.py -path "$(pwd)/build" -p1 \
|
||||
-extra-arg="-DWITH_VULKAN" \
|
||||
-extra-arg="-DVULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1" \
|
||||
-extra-arg="-DVK_NO_PROTOTYPES" \
|
||||
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)|(\/def_files\/data)))|freespace2|qtfred|test\/src|build|tools)\/.*\.(cpp|h)' \
|
||||
-clang-tidy-binary /usr/bin/clang-tidy-16 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
|
||||
@@ -17,11 +17,6 @@ if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
CXXFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
|
||||
CFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
|
||||
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
|
||||
# the ccache-action should install via homebrew, which means that we can't
|
||||
# hardcode the correct path in the workflow and must override it instead
|
||||
if [ ! "$CCACHE_PATH" = "" ]; then
|
||||
CCACHE_PATH="$(brew --prefix)/bin/ccache"
|
||||
fi
|
||||
else
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON -DFORCED_SIMD_INSTRUCTIONS=SSE2"
|
||||
|
||||
@@ -39,13 +34,16 @@ if [[ "$COMPILER" =~ ^clang.*$ ]]; then
|
||||
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCLANG_USE_LIBCXX=${CLANG_USE_LIBCXX:-OFF}"
|
||||
fi
|
||||
|
||||
if [ ! "$CCACHE_PATH" = "" ] && [ ! -x "$CCACHE_PATH" ]; then
|
||||
# The configured path doesn't exist on this runner (e.g. macOS runners on Apple
|
||||
# Silicon hosts install Homebrew under /opt/homebrew instead of /usr/local),
|
||||
# so fall back to whatever ccache is actually on PATH.
|
||||
CCACHE_PATH="$(command -v ccache || true)"
|
||||
fi
|
||||
|
||||
if [ ! "$CCACHE_PATH" = "" ]; then
|
||||
if [ -x "$CCACHE_PATH" ]; then
|
||||
echo "Using ccache at $CCACHE_PATH"
|
||||
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_C_COMPILER_LAUNCHER=$CCACHE_PATH -DCMAKE_CXX_COMPILER_LAUNCHER=$CCACHE_PATH"
|
||||
else
|
||||
echo "Invalid or missing ccache binary: $CCACHE_PATH"
|
||||
fi
|
||||
echo "Using ccache at $CCACHE_PATH"
|
||||
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_C_COMPILER_LAUNCHER=$CCACHE_PATH -DCMAKE_CXX_COMPILER_LAUNCHER=$CCACHE_PATH"
|
||||
fi
|
||||
|
||||
if [ -n "${ENABLE_QTFRED:-}" ]; then
|
||||
|
||||
+23
-19
@@ -66,33 +66,37 @@ ENDIF(EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${FILE}\")
|
||||
SET(${OUTVAR} "${CMAKE_COMMAND}" -P ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${NAME} PARENT_SCOPE)
|
||||
ENDFUNCTION(EP_CHECK_FILE_EXISTS)
|
||||
|
||||
# Use rsync if possible for COPY_FILE_TO_TARGET macro in order to preserve
|
||||
# symlinks as copy_if_different follows them which results in multiple copies
|
||||
if(PLATFORM_UNIX AND NOT DEFINED RSYNC_BIN)
|
||||
find_program(RSYNC_BIN rsync)
|
||||
endif()
|
||||
|
||||
MACRO(COPY_FILE_TO_TARGET _target _file)
|
||||
if (IS_DIRECTORY "${_file}")
|
||||
get_filename_component(_dirName "${_file}" NAME)
|
||||
if (PLATFORM_MAC AND ("${_file}" MATCHES ".framework$"))
|
||||
# This is stupid, but it preserves symlinks, unlike copy_directory_if_different.
|
||||
# Otherwise we end up creating duplicate files in the copied framework.
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND rsync -rlq "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
else()
|
||||
if(RSYNC_BIN)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${RSYNC_BIN} -rlq "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
else()
|
||||
if (IS_DIRECTORY "${_file}")
|
||||
get_filename_component(_dirName "${_file}" NAME)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/${_dirName}"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
else()
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
endmacro(COPY_FILE_TO_TARGET)
|
||||
|
||||
|
||||
+3
-10
@@ -113,16 +113,9 @@ if (FSO_BUILD_WITH_OPENGL)
|
||||
target_compile_definitions(code PUBLIC WITH_OPENGL)
|
||||
endif()
|
||||
if (FSO_BUILD_WITH_VULKAN)
|
||||
find_package(Vulkan REQUIRED)
|
||||
if (Vulkan_FOUND)
|
||||
target_compile_definitions(code PUBLIC WITH_VULKAN)
|
||||
target_link_libraries(code PRIVATE Vulkan::Vulkan)
|
||||
|
||||
target_compile_definitions(code PUBLIC WITH_VULKAN VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1 VK_NO_PROTOTYPES)
|
||||
else()
|
||||
message(WARNING "FSO_BUILD_WITH_VULKAN was set, but the package was unable to be found. Forcing OFF.")
|
||||
set(FSO_BUILD_WITH_VULKAN OFF CACHE BOOL "Enable compilation of the Vulkan renderer" FORCE)
|
||||
endif()
|
||||
target_compile_definitions(code PUBLIC WITH_VULKAN VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1 VK_NO_PROTOTYPES)
|
||||
target_include_directories(code PUBLIC Vulkan::Headers)
|
||||
target_link_libraries(code PUBLIC VulkanMemoryAllocator)
|
||||
endif()
|
||||
|
||||
include(shaders.cmake)
|
||||
|
||||
@@ -356,6 +356,7 @@ cmdline_parm fb_explosions_arg("-fb_explosions", NULL, AT_NONE);
|
||||
cmdline_parm fb_thrusters_arg("-fb_thrusters", NULL, AT_NONE);
|
||||
cmdline_parm shadow_quality_arg("-shadow_quality", NULL, AT_INT);
|
||||
cmdline_parm enable_shadows_arg("-enable_shadows", NULL, AT_NONE);
|
||||
cmdline_parm rt_shadows_arg("-rt_shadows", nullptr, AT_NONE);
|
||||
cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline_no_deferred
|
||||
cmdline_parm deferred_lighting_cockpit_arg("-deferred_cockpit", nullptr, AT_NONE);
|
||||
cmdline_parm anisotropy_level_arg("-anisotropic_filter", NULL, AT_INT);
|
||||
@@ -513,6 +514,7 @@ cmdline_parm deprecated_res_arg("-res", "Deprecated, resolution, formatted like
|
||||
cmdline_parm render_res_arg("-render_res", "Resolution, formatted like 1600x900", AT_STRING);
|
||||
cmdline_parm window_res_arg("-window_res", "Window resolution, formatted like 1600x900.", AT_STRING);
|
||||
cmdline_parm center_res_arg("-center_res", "Resolution of center monitor, formatted like 1600x900", AT_STRING);
|
||||
cmdline_parm hdr_nits_arg("-hdr", "Forces HDR output on, overriding the in-game HDR setting. Optionally takes paper white and peak luminance in nits, formatted like 400,1500, overriding the in-game HDR nits settings.", AT_STRING);
|
||||
cmdline_parm verify_vps_arg("-verify_vps", NULL, AT_NONE); // Cmdline_verify_vps -- spew VP crcs to vp_crcs.txt
|
||||
cmdline_parm parse_cmdline_only(PARSE_COMMAND_LINE_STRING, "Ignore any cmdline_fso.cfg files", AT_NONE);
|
||||
cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline_reparse_mainhall
|
||||
@@ -527,6 +529,7 @@ cmdline_parm show_video_info("-show_video_info", NULL, AT_NONE); //Cmdline_show_
|
||||
cmdline_parm frame_profile_arg("-profile_frame_time", NULL, AT_NONE); //Cmdline_frame_profile
|
||||
cmdline_parm debug_window_arg("-debug_window", NULL, AT_NONE); // Cmdline_debug_window
|
||||
cmdline_parm graphics_debug_output_arg("-gr_debug", nullptr, AT_NONE); // Cmdline_graphics_debug_output
|
||||
cmdline_parm gr_sync_validation_arg("-gr_sync_validation", nullptr, AT_NONE); // Cmdline_gr_sync_validation (implies -gr_debug)
|
||||
cmdline_parm log_to_stdout_arg("-stdout_log", nullptr, AT_NONE); // Cmdline_log_to_stdout
|
||||
cmdline_parm slow_frames_ok_arg("-slow_frames_ok", nullptr, AT_NONE); // Cmdline_slow_frames_ok
|
||||
cmdline_parm fixed_seed_rand("-seed", nullptr, AT_INT); // Cmdline_rng_seed,Cmdline_reuse_rng_seed;
|
||||
@@ -534,6 +537,7 @@ cmdline_parm luadev_arg("-luadev", "Make lua errors non-fatal", AT_NONE); // Cmd
|
||||
cmdline_parm override_arg("-override_data", "Enable override directory", AT_NONE); // Cmdline_override_data
|
||||
cmdline_parm imgui_debug_arg("-imgui_debug", nullptr, AT_NONE);
|
||||
cmdline_parm vulkan("-vulkan", nullptr, AT_NONE);
|
||||
cmdline_parm opengl("-opengl", nullptr, AT_NONE);
|
||||
cmdline_parm multithreading("-threads", nullptr, AT_INT);
|
||||
|
||||
char *Cmdline_start_mission = NULL;
|
||||
@@ -567,12 +571,13 @@ bool Cmdline_frame_profile = false;
|
||||
bool Cmdline_show_video_info = false;
|
||||
bool Cmdline_debug_window = false;
|
||||
bool Cmdline_graphics_debug_output = false;
|
||||
bool Cmdline_gr_sync_validation = false;
|
||||
bool Cmdline_log_to_stdout = false;
|
||||
bool Cmdline_slow_frames_ok = false;
|
||||
bool Cmdline_lua_devmode = false;
|
||||
bool Cmdline_override_data = false;
|
||||
bool Cmdline_show_imgui_debug = false;
|
||||
bool Cmdline_vulkan = false;
|
||||
GraphicsAPI Cmdline_graphics_api = GraphicsAPI::Default;
|
||||
int Cmdline_multithreading = 1;
|
||||
|
||||
// Other
|
||||
@@ -1822,6 +1827,22 @@ bool SetCmdlineParams()
|
||||
if(center_res_arg.found()){
|
||||
Cmdline_center_res = center_res_arg.str();
|
||||
}
|
||||
if (hdr_nits_arg.found()) {
|
||||
// presence of the flag alone forces HDR output on, overriding the in-game HDR setting
|
||||
options::OptionsManager::instance()->setOverride("Graphics.HDR", "true");
|
||||
|
||||
if (hdr_nits_arg.has_param()) {
|
||||
float paperwhite_nits = 0.0f, peak_nits = 0.0f;
|
||||
if (sscanf(hdr_nits_arg.str(), "%f,%f", &paperwhite_nits, &peak_nits) == 2 && paperwhite_nits > 0.0f && peak_nits > 0.0f) {
|
||||
// std::to_string always includes a decimal point, so this is a valid JSON real
|
||||
// (json_unpack's "f" format rejects a bare integer like "400")
|
||||
options::OptionsManager::instance()->setOverride("Graphics.HDRPaperWhite", std::to_string(paperwhite_nits));
|
||||
options::OptionsManager::instance()->setOverride("Graphics.HDRPeakLuminance", std::to_string(peak_nits));
|
||||
} else {
|
||||
Warning(LOCATION, "Failed to parse -hdr parameter \"%s\". Must be in format \"<paperwhite_nits>,<peak_nits>\".\n", hdr_nits_arg.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
if(almission_arg.found()){//DTP for autoload mission // developer oritentated
|
||||
Cmdline_almission = almission_arg.str();
|
||||
Cmdline_use_last_pilot = 1;
|
||||
@@ -2244,6 +2265,14 @@ bool SetCmdlineParams()
|
||||
}
|
||||
}
|
||||
|
||||
if( rt_shadows_arg.found() )
|
||||
{
|
||||
// Equivalent to picking "Raytraced" in the Shadow Method option. Silently
|
||||
// has no effect if the renderer/hardware doesn't support
|
||||
// CAPABILITY_RAYTRACED_SHADOWS -- the CSM path is used either way.
|
||||
Shadow_render_method = ShadowRenderMethod::Raytraced;
|
||||
}
|
||||
|
||||
if( no_deferred_lighting_arg.found() )
|
||||
{
|
||||
Cmdline_no_deferred_lighting = 1;
|
||||
@@ -2307,6 +2336,16 @@ bool SetCmdlineParams()
|
||||
Cmdline_graphics_debug_output = true;
|
||||
}
|
||||
|
||||
if (gr_sync_validation_arg.found()) {
|
||||
// Enables the Vulkan validation layer + debug messenger + synchronization
|
||||
// validation feature (see VulkanRenderer::initializeInstance), but NOT the
|
||||
// engine-level graphics debug output: -gr_debug additionally draws debug
|
||||
// overlays (e.g. output_uniform_debug_data), which are unrelated to GPU
|
||||
// sync validation and would otherwise appear as spurious on-screen
|
||||
// artifacts. Keep this a pure GPU-validation switch.
|
||||
Cmdline_gr_sync_validation = true;
|
||||
}
|
||||
|
||||
if (log_to_stdout_arg.found()) {
|
||||
Cmdline_log_to_stdout = true;
|
||||
}
|
||||
@@ -2332,7 +2371,10 @@ bool SetCmdlineParams()
|
||||
}
|
||||
|
||||
if (vulkan.found()) {
|
||||
Cmdline_vulkan = true;
|
||||
Cmdline_graphics_api = GraphicsAPI::Vulkan;
|
||||
}
|
||||
else if (opengl.found()) {
|
||||
Cmdline_graphics_api = GraphicsAPI::OpenGL;
|
||||
}
|
||||
|
||||
//Deprecated flags - CommanderDJ
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define FS_CMDLINE_HEADER_FILE
|
||||
|
||||
#include <optional>
|
||||
#include "graphics/2d.h"
|
||||
|
||||
int parse_cmdline(int argc, char *argv[]);
|
||||
|
||||
@@ -153,12 +154,13 @@ extern bool Cmdline_frame_profile;
|
||||
extern bool Cmdline_show_video_info;
|
||||
extern bool Cmdline_debug_window;
|
||||
extern bool Cmdline_graphics_debug_output;
|
||||
extern bool Cmdline_gr_sync_validation;
|
||||
extern bool Cmdline_log_to_stdout;
|
||||
extern bool Cmdline_slow_frames_ok;
|
||||
extern bool Cmdline_lua_devmode;
|
||||
extern bool Cmdline_override_data;
|
||||
extern bool Cmdline_show_imgui_debug;
|
||||
extern bool Cmdline_vulkan;
|
||||
extern GraphicsAPI Cmdline_graphics_api;
|
||||
extern int Cmdline_multithreading;
|
||||
|
||||
enum class WeaponSpewType { NONE = 0, STANDARD, ALL };
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "cutscene/VideoPresenter.h"
|
||||
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
|
||||
|
||||
#include "cmdline/cmdline.h"
|
||||
|
||||
#include "graphics/2d.h"
|
||||
|
||||
#include "globalincs/alphacolors.h"
|
||||
@@ -52,7 +54,7 @@ void videoPlaybackInit(PlayerState* state) {
|
||||
|
||||
Assert(state != NULL);
|
||||
|
||||
if (gr_screen.mode != GR_STUB) {
|
||||
if (gr_screen.mode != GraphicsAPI::Stub) {
|
||||
// The video presenter is independent of the underlying graphics API
|
||||
state->videoPresenter.reset(new VideoPresenter(state->props));
|
||||
}
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
|
||||
#include "ddsutils/ddsutils.h"
|
||||
#include "cfile/cfile.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "osapi/osregistry.h"
|
||||
#ifdef USE_OPENGL_ES
|
||||
#include "graphics/opengl/es_compatibility.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENGL
|
||||
#include <glad/glad.h>
|
||||
#else
|
||||
static constexpr int GLAD_GL_EXT_texture_compression_s3tc = 0;
|
||||
static constexpr int GLAD_GL_ARB_texture_compression_bptc = 0;
|
||||
#endif
|
||||
|
||||
#define BCDEC_IMPLEMENTATION 1
|
||||
PUSH_SUPPRESS_WARNINGS
|
||||
#include "ddsutils/bcdec.h"
|
||||
@@ -60,11 +54,11 @@ static bool conversion_needed(const DDS_HEADER &dds_header)
|
||||
case FOURCC_DXT1:
|
||||
case FOURCC_DXT3:
|
||||
case FOURCC_DXT5:
|
||||
return !GLAD_GL_EXT_texture_compression_s3tc;
|
||||
return !gr_is_capable(gr_capability::CAPABILITY_S3TC);
|
||||
|
||||
case FOURCC_DX10:
|
||||
// anything other than BC7 will end up invalid
|
||||
return !GLAD_GL_ARB_texture_compression_bptc;
|
||||
return !gr_is_capable(gr_capability::CAPABILITY_BPTC);
|
||||
|
||||
default:
|
||||
break;
|
||||
@@ -226,7 +220,7 @@ static size_t compute_dds_size(const DDS_HEADER &dds_header, bool converting = f
|
||||
|
||||
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
// size of data block (4x4)
|
||||
d_size += ((d_width + 3) / 4) * ((d_height + 3) / 4) * d_depth * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
|
||||
d_size += dds_compressed_mip_size(d_width, d_height, (dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16) * d_depth;
|
||||
} else {
|
||||
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
|
||||
}
|
||||
|
||||
@@ -273,6 +273,27 @@ typedef struct {
|
||||
} DDS_HEADER_DXT10;
|
||||
#pragma pack()
|
||||
|
||||
// Block size in bytes for a 4x4 texel block of a compressed DDS format.
|
||||
// comp_type is one of the DDS_DXT*/DDS_CUBEMAP_DXT* constants.
|
||||
inline int dds_block_size(int comp_type) {
|
||||
switch (comp_type) {
|
||||
case DDS_DXT1:
|
||||
case DDS_CUBEMAP_DXT1:
|
||||
return 8;
|
||||
case DDS_DXT3: case DDS_CUBEMAP_DXT3:
|
||||
case DDS_DXT5: case DDS_CUBEMAP_DXT5:
|
||||
case DDS_BC7:
|
||||
return 16;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Size in bytes of one mip level of a block-compressed texture.
|
||||
inline size_t dds_compressed_mip_size(int w, int h, int block_size) {
|
||||
return static_cast<size_t>(((w + 3) / 4) * ((h + 3) / 4) * block_size);
|
||||
}
|
||||
|
||||
#define DDS_OFFSET 4+sizeof(DDS_HEADER) //place where the data starts -- should be 128
|
||||
#define DX10_OFFSET DDS_OFFSET+sizeof(DDS_HEADER_DXT10) // Unless a DX10 header is present
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ float smoothstep(float edge0, float edge1, float x) {
|
||||
namespace decals {
|
||||
|
||||
void initialize() {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
Decal_system_active = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
|
||||
#include "gamma.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout (location = 0) in vec4 fragTexCoord;
|
||||
layout (location = 1) in vec4 fragColor;
|
||||
|
||||
layout (location = 0) out vec4 fragOut0;
|
||||
|
||||
layout (set = 1, binding = 1) uniform sampler2DArray baseMap;
|
||||
|
||||
layout (set = 2, binding = 0, std140) uniform genericData {
|
||||
vec4 color;
|
||||
float intensity;
|
||||
};
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
@@ -12,6 +25,7 @@ layout (std140) uniform genericData {
|
||||
vec4 color;
|
||||
float intensity;
|
||||
};
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
#ifdef VULKAN
|
||||
layout (location = 0) in vec4 vertPosition;
|
||||
layout (location = 1) in vec4 vertColor;
|
||||
layout (location = 2) in vec4 vertTexCoord;
|
||||
|
||||
layout (location = 0) out vec4 fragTexCoord;
|
||||
layout (location = 1) out vec4 fragColor;
|
||||
|
||||
layout (set = 2, binding = 1, std140) uniform matrixData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
};
|
||||
|
||||
layout (set = 2, binding = 0, std140) uniform genericData {
|
||||
vec4 color;
|
||||
float intensity;
|
||||
};
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in vec4 vertTexCoord;
|
||||
in vec4 vertColor;
|
||||
@@ -14,6 +32,7 @@ layout (std140) uniform genericData {
|
||||
vec4 color;
|
||||
float intensity;
|
||||
};
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(set = 1, binding = 1) uniform sampler2D bloomed;
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D bloomed;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
float bloom_intensity;
|
||||
int levels;
|
||||
};
|
||||
|
||||
@@ -1,16 +1,26 @@
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(set = 1, binding = 1) uniform sampler2D tex;
|
||||
#else
|
||||
out vec4 fragOut0;
|
||||
|
||||
in vec4 fragTexCoord;
|
||||
|
||||
uniform sampler2D tex;
|
||||
#endif
|
||||
|
||||
const float TapSize = 1.0;
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
float texSize;
|
||||
int level;
|
||||
int pad[2];
|
||||
};
|
||||
|
||||
const float TapSize = 1.0;
|
||||
|
||||
// Gaussian Blur
|
||||
// 2 passes required
|
||||
void main()
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(set = 1, binding = 1) uniform sampler2D tex;
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2D tex;
|
||||
#endif
|
||||
const float Luminance = 0.08;
|
||||
const float fMiddleGray = 0.2;
|
||||
const float fWhiteCutoff = 0.4;
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(set = 1, binding = 1) uniform sampler2D tex;
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
|
||||
#ifdef COPY_ARRAY
|
||||
uniform sampler2DArray tex;
|
||||
#else
|
||||
uniform sampler2D tex;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef COPY_ARRAY
|
||||
#if defined(COPY_ARRAY) && !defined(VULKAN)
|
||||
fragOut0 = texture(tex, vec3(fragTexCoord.xy, 0));
|
||||
#else
|
||||
fragOut0 = texture(tex, fragTexCoord.xy);
|
||||
#endif
|
||||
|
||||
#ifdef CLAMP01
|
||||
// Used to derive a [0,1]-bounded proxy from an extended-range HDR source,
|
||||
// e.g. for FXAA/SMAA edge detection when the real output carries values
|
||||
// above 1.0.
|
||||
fragOut0 = min(fragOut0, vec4(1.0));
|
||||
#endif
|
||||
}
|
||||
@@ -6,6 +6,29 @@
|
||||
#include "normals.sdr"
|
||||
#include "gamma.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
// G-buffer: 6 attachments, 1/3/5 are write-masked by pipeline blend state
|
||||
layout (location = 0) out vec4 fragOut0; // Color/Diffuse
|
||||
layout (location = 1) out vec4 fragOut1; // Position (masked)
|
||||
layout (location = 2) out vec4 fragOut2; // Normal
|
||||
layout (location = 3) out vec4 fragOut3; // Specular (masked)
|
||||
layout (location = 4) out vec4 fragOut4; // Emissive
|
||||
layout (location = 5) out vec4 fragOut5; // Composite (masked)
|
||||
|
||||
layout (location = 0) flat in mat4 invModelMatrix; // locations 0-3
|
||||
layout (location = 4) flat in vec3 decalDirection;
|
||||
layout (location = 5) flat in float normal_angle_cutoff;
|
||||
layout (location = 6) flat in float angle_fade_start;
|
||||
layout (location = 7) flat in float alpha_scale;
|
||||
|
||||
layout (set = 1, binding = 1) uniform sampler2DArray decalTextures;
|
||||
#define diffuseMap decalTextures
|
||||
#define glowMap decalTextures
|
||||
#define normalMap decalTextures
|
||||
|
||||
layout (set = 1, binding = 4) uniform sampler2D gDepthBuffer;
|
||||
layout (set = 1, binding = 6) uniform sampler2D gNormalBuffer;
|
||||
#else
|
||||
out vec4 fragOut0; // Diffuse buffer
|
||||
out vec4 fragOut1; // Normal buffer
|
||||
out vec4 fragOut2; // Emissive buffer
|
||||
@@ -22,8 +45,14 @@ uniform sampler2D gNormalBuffer;
|
||||
uniform sampler2DArray diffuseMap;
|
||||
uniform sampler2DArray glowMap;
|
||||
uniform sampler2DArray normalMap;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform decalGlobalData {
|
||||
#ifdef VULKAN
|
||||
layout (set = 1, binding = 2, std140)
|
||||
#else
|
||||
layout (std140)
|
||||
#endif
|
||||
uniform decalGlobalData {
|
||||
mat4 viewMatrix;
|
||||
mat4 projMatrix;
|
||||
mat4 invViewMatrix;
|
||||
@@ -32,7 +61,12 @@ layout (std140) uniform decalGlobalData {
|
||||
vec2 viewportSize;
|
||||
};
|
||||
|
||||
layout (std140) uniform decalInfoData {
|
||||
#ifdef VULKAN
|
||||
layout (set = 2, binding = 3, std140)
|
||||
#else
|
||||
layout (std140)
|
||||
#endif
|
||||
uniform decalInfoData {
|
||||
int diffuse_index;
|
||||
int glow_index;
|
||||
int normal_index;
|
||||
@@ -45,8 +79,16 @@ vec3 computeViewPosition(vec2 textureCoord) {
|
||||
vec4 clipSpaceLocation;
|
||||
vec2 normalizedCoord = textureCoord / viewportSize;
|
||||
|
||||
#ifdef VULKAN
|
||||
clipSpaceLocation.x = normalizedCoord.x * 2.0 - 1.0;
|
||||
// Vulkan negative viewport inverts Y mapping
|
||||
clipSpaceLocation.y = 1.0 - normalizedCoord.y * 2.0;
|
||||
// Vulkan depth is [0,1] — use directly
|
||||
clipSpaceLocation.z = texelFetch(gDepthBuffer, ivec2(textureCoord), 0).r;
|
||||
#else
|
||||
clipSpaceLocation.xy = normalizedCoord * 2.0f - 1.0f;
|
||||
clipSpaceLocation.z = texelFetch(gDepthBuffer, ivec2(textureCoord), 0).r * 2.0f - 1.0f;
|
||||
#endif
|
||||
clipSpaceLocation.w = 1.0f;
|
||||
|
||||
vec4 homogenousLocation = invProjMatrix * clipSpaceLocation;
|
||||
@@ -57,24 +99,24 @@ vec3 computeViewPosition(vec2 textureCoord) {
|
||||
vec3 getPixelNormal(vec3 frag_position, vec2 tex_coord, inout float alpha, out vec3 binormal, out vec3 tangent) {
|
||||
#ifdef USE_NORMAL_MAP
|
||||
// If we can then we just use the existing normal buffer
|
||||
vec3 normal = texelFetch(gNormalBuffer, ivec2(tex_coord), 0).xyz;
|
||||
vec3 normal = texelFetch(gNormalBuffer, ivec2(tex_coord), 0).xyz;
|
||||
|
||||
// If we use the normal map then we don't really need these values so we don't need to compute them here
|
||||
binormal = vec3(0.0);
|
||||
tangent = vec3(0.0);
|
||||
binormal = vec3(0.0);
|
||||
tangent = vec3(0.0);
|
||||
#else
|
||||
// Use some fancy screen-space derivates to determine the normal of the current pixel by looking at the surrounding pixels
|
||||
vec3 pos_dx = dFdx(frag_position);
|
||||
vec3 pos_dy = dFdy(frag_position);
|
||||
|
||||
vec3 normal = normalize(cross(pos_dx, pos_dy));
|
||||
vec3 normal = normalize(cross(pos_dx, pos_dy));
|
||||
|
||||
binormal = normalize(pos_dx);
|
||||
tangent = normalize(pos_dy);
|
||||
binormal = normalize(pos_dx);
|
||||
tangent = normalize(pos_dy);
|
||||
#endif
|
||||
|
||||
//Calculate angle between surface normal and decal direction
|
||||
float angle = acos(dot(normal, decalDirection));
|
||||
float angle = acos(clamp(dot(normal, decalDirection), -1.0, 1.0));
|
||||
|
||||
if (angle > normal_angle_cutoff) {
|
||||
// The angle between surface normal and decal direction is too big
|
||||
@@ -162,7 +204,18 @@ void main() {
|
||||
normal_out = tangentToView * decalNormal * alpha;
|
||||
}
|
||||
|
||||
#ifdef VULKAN
|
||||
// 6-attachment G-buffer; attachments 1/3/5 are write-masked
|
||||
fragOut0 = diffuse_out;
|
||||
fragOut1 = vec4(0.0);
|
||||
fragOut2 = vec4(normal_out, 0.0);
|
||||
fragOut3 = vec4(0.0);
|
||||
fragOut4 = emissive_out;
|
||||
fragOut5 = vec4(0.0);
|
||||
#else
|
||||
// OpenGL: 3 draw buffers mapped to attachments 0/2/4
|
||||
fragOut0 = diffuse_out;
|
||||
fragOut1 = vec4(normal_out, 0.0);
|
||||
fragOut2 = emissive_out;
|
||||
#endif
|
||||
}
|
||||
@@ -1,4 +1,20 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
// Binding 0: box vertex positions
|
||||
layout (location = 0) in vec4 vertPosition;
|
||||
|
||||
// Binding 1: per-instance model matrix (mat4 = 4 vec4s at locations 8-11)
|
||||
layout (location = 8) in vec4 vertModelMatrix0;
|
||||
layout (location = 9) in vec4 vertModelMatrix1;
|
||||
layout (location = 10) in vec4 vertModelMatrix2;
|
||||
layout (location = 11) in vec4 vertModelMatrix3;
|
||||
|
||||
layout (location = 0) flat out mat4 invModelMatrix; // locations 0-3
|
||||
layout (location = 4) flat out vec3 decalDirection;
|
||||
layout (location = 5) flat out float normal_angle_cutoff;
|
||||
layout (location = 6) flat out float angle_fade_start;
|
||||
layout (location = 7) flat out float alpha_scale;
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in mat4 vertModelMatrix;
|
||||
|
||||
@@ -7,8 +23,14 @@ flat out vec3 decalDirection;
|
||||
flat out float normal_angle_cutoff;
|
||||
flat out float angle_fade_start;
|
||||
flat out float alpha_scale;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform decalGlobalData {
|
||||
#ifdef VULKAN
|
||||
layout (set = 1, binding = 2, std140)
|
||||
#else
|
||||
layout (std140)
|
||||
#endif
|
||||
uniform decalGlobalData {
|
||||
mat4 viewMatrix;
|
||||
mat4 projMatrix;
|
||||
mat4 invViewMatrix;
|
||||
@@ -17,7 +39,12 @@ layout (std140) uniform decalGlobalData {
|
||||
vec2 viewportSize;
|
||||
};
|
||||
|
||||
layout (std140) uniform decalInfoData {
|
||||
#ifdef VULKAN
|
||||
layout (set = 2, binding = 3, std140)
|
||||
#else
|
||||
layout (std140)
|
||||
#endif
|
||||
uniform decalInfoData {
|
||||
int diffuse_index;
|
||||
int glow_index;
|
||||
int normal_index;
|
||||
@@ -27,6 +54,11 @@ layout (std140) uniform decalInfoData {
|
||||
};
|
||||
|
||||
void main() {
|
||||
#ifdef VULKAN
|
||||
// Reconstruct per-instance model matrix from 4 vec4 columns
|
||||
mat4 vertModelMatrix = mat4(vertModelMatrix0, vertModelMatrix1, vertModelMatrix2, vertModelMatrix3);
|
||||
#endif
|
||||
|
||||
normal_angle_cutoff = vertModelMatrix[0][3];
|
||||
angle_fade_start = vertModelMatrix[1][3];
|
||||
alpha_scale = vertModelMatrix[2][3];
|
||||
|
||||
+27
-13
@@ -1,14 +1,9 @@
|
||||
#version 450
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
|
||||
#include "gamma.sdr"
|
||||
|
||||
layout (location = 0) in vec4 fragTexCoord;
|
||||
layout (location = 1) in vec4 fragColor;
|
||||
|
||||
layout (location = 0) out vec4 fragOut0;
|
||||
|
||||
layout (binding = 1, std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
mat4 modelMatrix;
|
||||
|
||||
vec4 color;
|
||||
@@ -22,10 +17,29 @@ layout (binding = 1, std140) uniform genericData {
|
||||
|
||||
float intensity;
|
||||
float alphaThreshold;
|
||||
bool clipEnabled;
|
||||
uint clipEnabled;
|
||||
};
|
||||
|
||||
layout(binding = 2) uniform sampler2DArray baseMap;
|
||||
#ifdef VULKAN
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler2DArray baseMap;
|
||||
|
||||
layout(location = 0) in vec4 fragTexCoord;
|
||||
layout(location = 1) in vec4 fragColor;
|
||||
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
|
||||
#else
|
||||
|
||||
uniform sampler2DArray baseMap;
|
||||
|
||||
in vec4 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
out vec4 fragOut0;
|
||||
|
||||
#endif
|
||||
|
||||
#include "gamma.sdr"
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -0,0 +1,70 @@
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
mat4 modelMatrix;
|
||||
|
||||
vec4 color;
|
||||
|
||||
vec4 clipEquation;
|
||||
|
||||
int baseMapIndex;
|
||||
int alphaTexture;
|
||||
int noTexturing;
|
||||
int srgb;
|
||||
|
||||
float intensity;
|
||||
float alphaThreshold;
|
||||
uint clipEnabled;
|
||||
};
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 1, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform matrixData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
};
|
||||
|
||||
#ifdef VULKAN
|
||||
|
||||
layout(location = 0) in vec4 vertPosition;
|
||||
layout(location = 1) in vec4 vertColor;
|
||||
layout(location = 2) in vec4 vertTexCoord;
|
||||
|
||||
layout(location = 0) out vec4 fragTexCoord;
|
||||
layout(location = 1) out vec4 fragColor;
|
||||
|
||||
#else
|
||||
|
||||
out float gl_ClipDistance[1];
|
||||
|
||||
out vec4 fragTexCoord;
|
||||
in vec4 vertTexCoord;
|
||||
out vec4 fragColor;
|
||||
in vec4 vertColor;
|
||||
in vec4 vertPosition;
|
||||
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
fragTexCoord = vertTexCoord;
|
||||
fragColor = vertColor * color;
|
||||
gl_Position = projMatrix * modelViewMatrix * vertPosition;
|
||||
|
||||
if (clipEnabled != 0u) {
|
||||
gl_ClipDistance[0] = dot(clipEquation, modelMatrix * vertPosition);
|
||||
} else {
|
||||
#ifdef VULKAN
|
||||
// Vulkan has no glEnable(GL_CLIP_DISTANCE0) equivalent — clip distances are
|
||||
// always evaluated when declared in the shader. Must write a positive value
|
||||
// when clipping is disabled to prevent undefined-value vertex culling.
|
||||
gl_ClipDistance[0] = 1.0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,30 @@
|
||||
#include "shadows.sdr" //! #include "shadows.sdr"
|
||||
#include "z-compress.sdr" //! #include "z-compress.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
#else
|
||||
out vec4 fragOut0;
|
||||
#endif
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(set = 1, binding = 1) uniform sampler2D sTextures[16];
|
||||
#define ColorBuffer sTextures[0]
|
||||
#define NormalBuffer sTextures[1]
|
||||
#define PositionBuffer sTextures[2]
|
||||
#define SpecBuffer sTextures[3]
|
||||
|
||||
layout(set = 0, binding = 2) uniform sampler2DArrayShadow shadow_map;
|
||||
|
||||
#ifdef ENV_MAP
|
||||
layout(set = 0, binding = 3) uniform samplerCube sEnvmap;
|
||||
layout(set = 0, binding = 4) uniform samplerCube sIrrmap;
|
||||
#endif
|
||||
|
||||
#ifdef RT_SHADOWS
|
||||
layout(set = 0, binding = 5) uniform accelerationStructureEXT shadow_tlas;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2D ColorBuffer;
|
||||
uniform sampler2D NormalBuffer;
|
||||
uniform sampler2D PositionBuffer;
|
||||
@@ -16,8 +38,14 @@ uniform sampler2DArrayShadow shadow_map;
|
||||
uniform samplerCube sEnvmap;
|
||||
uniform samplerCube sIrrmap;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
layout (std140) uniform globalDeferredData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 0, binding = 1, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform globalDeferredData {
|
||||
mat4 inv_view_matrix;
|
||||
|
||||
float invScreenWidth;
|
||||
@@ -25,9 +53,16 @@ layout (std140) uniform globalDeferredData {
|
||||
float nearPlane;
|
||||
};
|
||||
|
||||
layout (std140) uniform shadowCascadeParams {
|
||||
#ifdef VULKAN
|
||||
layout(set = 0, binding = 6, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform shadowCascadeParams {
|
||||
int cascade_offset;
|
||||
int cascade_count;
|
||||
float rtShadowBiasMin;
|
||||
float rtShadowBiasMax;
|
||||
|
||||
mat4 shadow_mv_matrix;
|
||||
mat4 shadow_proj_matrix[NUM_SHADOW_CASCADES];
|
||||
@@ -35,12 +70,22 @@ layout (std140) uniform shadowCascadeParams {
|
||||
vec4 smoothness_factors[(NUM_SHADOW_CASCADES + 4 - 1) / 4];
|
||||
};
|
||||
|
||||
layout (std140) uniform matrixData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 1, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform matrixData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
};
|
||||
|
||||
layout (std140) uniform lightData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 0, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform lightData {
|
||||
vec3 diffuseLightColor;
|
||||
float coneAngle;
|
||||
|
||||
@@ -48,18 +93,18 @@ layout (std140) uniform lightData {
|
||||
float coneInnerAngle;
|
||||
|
||||
vec3 coneDir;
|
||||
bool dualCone;
|
||||
int dualCone;
|
||||
|
||||
vec3 scale;
|
||||
float lightRadius;
|
||||
|
||||
int lightType;
|
||||
bool enable_shadows;
|
||||
int enable_shadows;
|
||||
|
||||
float sourceRadius;
|
||||
};
|
||||
|
||||
// Nearest point sphere and tube light calculations taken from
|
||||
// Nearest point sphere and tube light calculations taken from
|
||||
// "Real Shading in Unreal Engine 4" by Brian Karis, Epic Games
|
||||
// Part of SIGGRAPH 2013 Course: Physically Based Shading in Theory and Practice
|
||||
|
||||
@@ -67,7 +112,7 @@ vec3 ExpandLightSize(in vec3 lightDir, in vec3 reflectDir) {
|
||||
// There's an extra max(...,sourceRadius) call here vs the version in the paper.
|
||||
// This prevents the centerToRay calculation from choosing a point behind
|
||||
// the reflection ray's origin (i.e. underneath the surface).
|
||||
// this is necessary for situations where the fragment being shaded lies inside
|
||||
// this is necessary for situations where the fragment being shaded lies inside
|
||||
// the sourceRadius of the light.
|
||||
// Instead, we choose a point suffciently far away from the reflection origin (hence max(...,sourceRadius))
|
||||
// so that we have a gradual transition as the shaded fragments along the surface
|
||||
@@ -75,12 +120,13 @@ vec3 ExpandLightSize(in vec3 lightDir, in vec3 reflectDir) {
|
||||
vec3 centerToRay = max(dot(lightDir, reflectDir),sourceRadius) * reflectDir - lightDir;
|
||||
return lightDir + centerToRay * clamp(sourceRadius/length(centerToRay), 0.0, 1.0);
|
||||
}
|
||||
void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 lightDirOut, out float attenuation, out float area_normalisation)
|
||||
void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 lightDirOut, out float attenuation, out float area_normalisation, out float lightDist)
|
||||
{
|
||||
if (lightType == LT_DIRECTIONAL) {
|
||||
lightDirOut = normalize(lightDir);
|
||||
attenuation = 1.0;
|
||||
area_normalisation = 1.0;
|
||||
lightDist = RT_SHADOW_MAX_DISTANCE;
|
||||
} else {
|
||||
vec3 lightPosition = modelViewMatrix[3].xyz;
|
||||
// Positional light source
|
||||
@@ -93,6 +139,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
// move lightDirOut towards the ray defined by reflectDir
|
||||
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
|
||||
dist = length(lightDirOut);
|
||||
lightDist = dist;
|
||||
// Energy conservation term
|
||||
float alpha_adjust = clamp(alpha + (sourceRadius/(2*dist)), 0.0, 1.0);
|
||||
area_normalisation = alpha/alpha_adjust;
|
||||
@@ -135,6 +182,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
// Same principle as in LT_POINT, treat chosen location as a spherelight.
|
||||
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
|
||||
float dist = length(lightDirOut);
|
||||
lightDist = dist;
|
||||
// Energy conservation term
|
||||
float alpha_adjust = min(alpha + (sourceRadius/(2*dist)), 1.0);
|
||||
area_normalisation = alpha/alpha_adjust;
|
||||
@@ -150,10 +198,11 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
lightDirOut = lightPosition - position.xyz;
|
||||
float coneDot = dot(normalize(-lightDirOut), coneDir);
|
||||
float dist = length(lightDirOut);
|
||||
lightDist = dist;
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
area_normalisation = 1.0;
|
||||
|
||||
if(dualCone) {
|
||||
if(dualCone != 0) {
|
||||
if(abs(coneDot) < coneAngle) {
|
||||
discard;
|
||||
} else {
|
||||
@@ -256,9 +305,18 @@ void main()
|
||||
vec3 lightDir;
|
||||
float attenuation;
|
||||
float area_normalisation;
|
||||
GetLightInfo(position, alpha, reflectDir, lightDir, attenuation, area_normalisation);
|
||||
float lightDist;
|
||||
GetLightInfo(position, alpha, reflectDir, lightDir, attenuation, area_normalisation, lightDist);
|
||||
|
||||
if (enable_shadows) {
|
||||
if (enable_shadows != 0) {
|
||||
#ifdef RT_SHADOWS
|
||||
vec3 worldPos = (inv_view_matrix * vec4(position, 1.0)).xyz;
|
||||
vec3 worldNormal = normalize((inv_view_matrix * vec4(normal, 0.0)).xyz);
|
||||
vec3 worldLightDir = normalize((inv_view_matrix * vec4(lightDir, 0.0)).xyz);
|
||||
|
||||
float rtShadowBias = computeRtShadowBias(length(position), rtShadowBiasMin, rtShadowBiasMax);
|
||||
attenuation *= traceShadowRay(shadow_tlas, worldPos, worldNormal, worldLightDir, lightDist, rtShadowBias);
|
||||
#else
|
||||
vec4 fragShadowPos = shadow_mv_matrix * inv_view_matrix * vec4(position, 1.0);
|
||||
vec4 fragShadowUV[NUM_SHADOW_CASCADES];
|
||||
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
||||
@@ -266,6 +324,7 @@ void main()
|
||||
}
|
||||
|
||||
attenuation *= getShadowValue(shadow_map, -position.z, fragShadowUV, cascade_distances, smoothness_factors, cascade_offset, cascade_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
vec3 halfVec = normalize(lightDir + eyeDir);
|
||||
|
||||
@@ -1,14 +1,28 @@
|
||||
|
||||
#include "lighting.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec4 vertPosition;
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform matrixData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 1, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform matrixData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
};
|
||||
|
||||
layout (std140) uniform lightData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 0, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform lightData {
|
||||
vec3 diffuseLightColor;
|
||||
float coneAngle;
|
||||
|
||||
@@ -16,13 +30,13 @@ layout (std140) uniform lightData {
|
||||
float coneInnerAngle;
|
||||
|
||||
vec3 coneDir;
|
||||
bool dualCone;
|
||||
int dualCone;
|
||||
|
||||
vec3 scale;
|
||||
float lightRadius;
|
||||
|
||||
int lightType;
|
||||
bool enable_shadows;
|
||||
int enable_shadows;
|
||||
|
||||
float sourceRadius;
|
||||
};
|
||||
@@ -30,7 +44,13 @@ layout (std140) uniform lightData {
|
||||
void main()
|
||||
{
|
||||
if (lightType == LT_DIRECTIONAL || lightType == LT_AMBIENT) {
|
||||
#ifdef VULKAN
|
||||
// Fullscreen triangle from gl_VertexIndex (no vertex buffer)
|
||||
vec2 pos = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
gl_Position = vec4(pos * 2.0 - 1.0, 0.0, 1.0);
|
||||
#else
|
||||
gl_Position = vec4(vertPosition.xyz, 1.0);
|
||||
#endif
|
||||
} else {
|
||||
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec4 fragTexCoord;
|
||||
layout(location = 1) in vec4 fragColor;
|
||||
layout(location = 2) in float fragOffset;
|
||||
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler2DArray baseMap;
|
||||
layout(set = 1, binding = 4) uniform sampler2D depthMap;
|
||||
layout(set = 1, binding = 5) uniform sampler2D frameBuffer;
|
||||
layout(set = 1, binding = 6) uniform sampler2D distMap;
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
in float fragOffset;
|
||||
@@ -8,8 +20,14 @@ uniform sampler2DArray baseMap;
|
||||
uniform sampler2D depthMap;
|
||||
uniform sampler2D distMap;
|
||||
uniform sampler2D frameBuffer;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0)
|
||||
#else
|
||||
layout (std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
float window_width;
|
||||
float window_height;
|
||||
float use_offset;
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec4 vertPosition;
|
||||
layout(location = 1) in vec4 vertColor;
|
||||
layout(location = 2) in vec4 vertTexCoord;
|
||||
layout(location = 6) in float vertRadius;
|
||||
|
||||
layout(location = 0) out vec4 fragTexCoord;
|
||||
layout(location = 1) out vec4 fragColor;
|
||||
layout(location = 2) out float fragOffset;
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in vec4 vertTexCoord;
|
||||
in vec4 vertColor;
|
||||
@@ -5,13 +15,24 @@ in float vertRadius;
|
||||
out vec4 fragTexCoord;
|
||||
out vec4 fragColor;
|
||||
out float fragOffset;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform matrixData {
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 1)
|
||||
#else
|
||||
layout (std140)
|
||||
#endif
|
||||
uniform matrixData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
};
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0)
|
||||
#else
|
||||
layout (std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
float window_width;
|
||||
float window_height;
|
||||
float use_offset;
|
||||
|
||||
@@ -2,6 +2,17 @@
|
||||
#include "gamma.sdr"
|
||||
#include "z-compress.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec4 fragTexCoord;
|
||||
layout(location = 1) in vec4 fragColor;
|
||||
layout(location = 2) in float fragRadius;
|
||||
layout(location = 3) in vec4 fragPosition;
|
||||
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler2DArray baseMap;
|
||||
layout(set = 1, binding = 4) uniform sampler2D depthMap;
|
||||
#else
|
||||
in float fragRadius;
|
||||
in vec4 fragPosition;
|
||||
in vec4 fragTexCoord;
|
||||
@@ -11,8 +22,14 @@ out vec4 fragOut0;
|
||||
|
||||
uniform sampler2DArray baseMap;
|
||||
uniform sampler2D depthMap;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
float window_width;
|
||||
float window_height;
|
||||
float nearZ;
|
||||
@@ -39,7 +56,13 @@ void main()
|
||||
float sceneDepthLinear;
|
||||
float fragDepthLinear;
|
||||
if ( linear_depth == 1 ) {
|
||||
sceneDepthLinear = -uncompress_depth_value(sceneDepth.z);
|
||||
// Position buffer .z == 0 means no deferred geometry was rendered at this pixel
|
||||
// (G-buffer was cleared to zero). Treat as max distance so particles render fully.
|
||||
if (sceneDepth.z == 0.0) {
|
||||
sceneDepthLinear = farZ;
|
||||
} else {
|
||||
sceneDepthLinear = -uncompress_depth_value(sceneDepth.z);
|
||||
}
|
||||
fragDepthLinear = -fragPosition.z;
|
||||
} else {
|
||||
sceneDepthLinear = ( 2.0 * farZ * nearZ ) / ( farZ + nearZ - sceneDepth.x * (farZ-nearZ) );
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec4 vertPosition;
|
||||
layout(location = 1) in vec4 vertColor;
|
||||
layout(location = 2) in vec4 vertTexCoord;
|
||||
layout(location = 6) in float vertRadius;
|
||||
|
||||
layout(location = 0) out vec4 fragTexCoord;
|
||||
layout(location = 1) out vec4 fragColor;
|
||||
layout(location = 2) out float fragRadius;
|
||||
layout(location = 3) out vec4 fragPosition;
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in vec4 vertTexCoord;
|
||||
in vec4 vertColor;
|
||||
@@ -16,15 +27,21 @@ in float vertRadius;
|
||||
out vec4 fragTexCoord;
|
||||
out vec4 fragColor;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
layout (std140) uniform matrixData {
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 1)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform matrixData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef FLAG_EFFECT_GEOMETRY
|
||||
#if !defined(VULKAN) && defined(FLAG_EFFECT_GEOMETRY)
|
||||
geoRadius = vertRadius;
|
||||
geoUvec = vertUvec;
|
||||
gl_Position = modelViewMatrix * vertPosition;
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
|
||||
#include "gamma.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler2D tex;
|
||||
layout(set = 1, binding = 4) uniform sampler2D depth_tex;
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform sampler2D depth_tex;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0)
|
||||
#else
|
||||
layout (std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
vec3 fog_color;
|
||||
float fog_start;
|
||||
|
||||
|
||||
@@ -487,10 +487,27 @@ FxaaFloat4 FxaaPixelShader(
|
||||
return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM);
|
||||
#endif
|
||||
}
|
||||
#ifdef VULKAN
|
||||
layout(set = 1, binding = 1) uniform sampler2D tex0;
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(std140, set = 2, binding = 0) uniform genericData {
|
||||
float rt_w;
|
||||
float rt_h;
|
||||
float pad0;
|
||||
float pad1;
|
||||
};
|
||||
#else
|
||||
uniform sampler2D tex0;
|
||||
in vec2 v_rcpFrame;
|
||||
noperspective in vec2 v_pos;
|
||||
out vec4 fragOut0;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
#ifdef VULKAN
|
||||
vec2 v_rcpFrame = vec2(1.0 / rt_w, 1.0 / rt_h);
|
||||
vec2 v_pos = fragTexCoord;
|
||||
#endif
|
||||
fragOut0 = FxaaPixelShader(v_pos, tex0, v_rcpFrame, FXAA_QUALITY_SUBPIX, FXAA_QUALITY_EDGE_THRESHOLD, FXAA_QUALITY_EDGE_THRESHOLD_MIN);
|
||||
}
|
||||
@@ -1,4 +1,12 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) out vec2 fragTexCoord;
|
||||
void main() {
|
||||
vec2 uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
fragTexCoord = uv;
|
||||
gl_Position = vec4(uv * 2.0 - 1.0, 0.0, 1.0);
|
||||
}
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
|
||||
out vec2 v_rcpFrame;
|
||||
@@ -14,3 +22,4 @@ void main() {
|
||||
v_rcpFrame = vec2(1.0/rt_w, 1.0/rt_h);
|
||||
v_pos = vertPosition.xy*0.5 + 0.5;
|
||||
}
|
||||
#endif
|
||||
@@ -1,7 +1,22 @@
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
// [0]=real color (passed through as-is), [1]=luma detection proxy (see
|
||||
// getAADetectionView; may be the same view as [0] when not HDR)
|
||||
layout(set = 1, binding = 1) uniform sampler2D fxaaTex[2];
|
||||
#define tex fxaaTex[0]
|
||||
#define lumaTex fxaaTex[1]
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2D tex;
|
||||
#endif
|
||||
void main() {
|
||||
vec4 color = texture(tex, fragTexCoord.xy);
|
||||
#ifdef VULKAN
|
||||
vec3 lumaColor = texture(lumaTex, fragTexCoord.xy).rgb;
|
||||
fragOut0 = vec4(color.rgb, dot(lumaColor, vec3(0.299, 0.587, 0.114)));
|
||||
#else
|
||||
fragOut0 = vec4(color.rgb, dot(color.rgb, vec3(0.299, 0.587, 0.114)) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,18 +1,55 @@
|
||||
#include "gamma.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(set = 1, binding = 1) uniform sampler2D tex;
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D tex;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
float gamma;
|
||||
float hdr_paperwhite_nits; // HDR10_OUTPUT only
|
||||
float hdr_peak_nits; // HDR10_OUTPUT only
|
||||
float pad[1];
|
||||
};
|
||||
|
||||
// Final whole-frame output-encode pass: applies the user gamma/brightness
|
||||
// slider to the fully composited, display-ready frame (3D scene + menus/HUD
|
||||
// alike) right before it's written into the swap chain image. The gamma curve
|
||||
// is shared between the two output legs so the slider behaves consistently:
|
||||
//
|
||||
// * SDR (default, both backends): the input is already sRGB-encoded, so just
|
||||
// apply the gamma slider. See VulkanRenderer::encodeToSwapChain().
|
||||
// * HDR10_OUTPUT (Vulkan only, when the swap chain negotiated HDR10 =
|
||||
// BT.2020 + ST.2084): the input is the shared extended-sRGB encoding from
|
||||
// tonemapping-f.sdr's HdrScene tonemapper (1.0 == paper white). After the
|
||||
// gamma slider, decode to linear, scale to display nits, convert to BT.2020
|
||||
// primaries and apply PQ (ST.2084).
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture(tex, fragTexCoord.xy);
|
||||
|
||||
float g = max(gamma, 0.001);
|
||||
|
||||
#ifdef HDR10_OUTPUT
|
||||
color.rgb = pow(max(color.rgb, vec3(0.0)), vec3(1.0 / g));
|
||||
|
||||
vec3 lin = srgb_to_linear(max(color.rgb, vec3(0.0)));
|
||||
vec3 nits = min(lin * hdr_paperwhite_nits, vec3(hdr_peak_nits));
|
||||
vec3 rec2020 = bt709_to_bt2020(nits / 10000.0);
|
||||
fragOut0 = vec4(linear_to_pq(rec2020), 1.0);
|
||||
#else
|
||||
color.rgb = pow(color.rgb, vec3(1.0 / g));
|
||||
|
||||
fragOut0 = color;
|
||||
#endif
|
||||
}
|
||||
@@ -27,3 +27,34 @@ vec3 linear_to_srgb(vec3 val) {
|
||||
vec4 linear_to_srgb(vec4 val) {
|
||||
return pow(val, vec4(SRGB_GAMMA_INVERSE));
|
||||
}
|
||||
|
||||
// ===== HDR10 helpers (PQ / ST.2084 + BT.2020) =====
|
||||
//
|
||||
// These are used by the final output-encode pass when HDR10 output is active.
|
||||
// The composition buffer stores values in an extended-sRGB encoding where 1.0
|
||||
// maps to "paper white"; the encode pass decodes to linear, scales to display
|
||||
// nits, converts BT.709 primaries to BT.2020, then applies the PQ transfer.
|
||||
|
||||
// BT.709 -> BT.2020 primary conversion (linear light). GLSL is column-major,
|
||||
// so each vec3 below is a COLUMN of the standard row-major conversion matrix.
|
||||
const mat3 bt709_to_bt2020_mat = mat3(
|
||||
vec3(0.627403914, 0.069097158, 0.016391439),
|
||||
vec3(0.329283028, 0.919540405, 0.088013308),
|
||||
vec3(0.043313057, 0.011362437, 0.895595253));
|
||||
|
||||
vec3 bt709_to_bt2020(vec3 c) {
|
||||
return bt709_to_bt2020_mat * c;
|
||||
}
|
||||
|
||||
// SMPTE ST.2084 (PQ) inverse-EOTF / OETF. Input is linear luminance normalized
|
||||
// so that 1.0 == 10000 nits (the PQ system peak). Output is the PQ-encoded
|
||||
// signal in [0,1] suitable for an HDR10 (BT.2020 + ST.2084) swap chain.
|
||||
vec3 linear_to_pq(vec3 L) {
|
||||
const float m1 = 0.1593017578125;
|
||||
const float m2 = 78.84375;
|
||||
const float c1 = 0.8359375;
|
||||
const float c2 = 18.8515625;
|
||||
const float c3 = 18.6875;
|
||||
vec3 Lm1 = pow(max(L, vec3(0.0)), vec3(m1));
|
||||
return pow((c1 + c2 * Lm1) / (1.0 + c3 * Lm1), vec3(m2));
|
||||
}
|
||||
@@ -1,16 +1,26 @@
|
||||
//!#version 150
|
||||
#include "gamma.sdr" //! #include "gamma.sdr"
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
uniform samplerCube envmap;
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(set = 1, binding = 1) uniform samplerCube envmap;
|
||||
#else
|
||||
uniform samplerCube envmap;
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
#endif
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
int face;
|
||||
};
|
||||
|
||||
in vec4 fragTexCoord;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
// Iteratively optimised points to give low discrepancy distribution on arbitrary hemisphere.
|
||||
const vec3 points[128] = vec3[128](
|
||||
vec3(-0.2268, 0.6185, 0.7523),
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler2D textures[16];
|
||||
#define scene textures[0]
|
||||
#define cockpit textures[1]
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D scene;
|
||||
uniform sampler2D cockpit;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0)
|
||||
#else
|
||||
layout (std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
vec2 sun_pos;
|
||||
float density;
|
||||
float weight;
|
||||
|
||||
@@ -25,7 +25,12 @@ struct model_light {
|
||||
|
||||
};
|
||||
|
||||
layout (std140) uniform modelData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 1, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform modelData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 modelMatrix;
|
||||
mat4 viewMatrix;
|
||||
@@ -44,7 +49,7 @@ layout (std140) uniform modelData {
|
||||
vec4 clip_equation;
|
||||
|
||||
float thruster_scale;
|
||||
bool use_clip_plane;
|
||||
int use_clip_plane;
|
||||
int n_lights;
|
||||
float defaultGloss;
|
||||
|
||||
@@ -56,10 +61,10 @@ layout (std140) uniform modelData {
|
||||
|
||||
vec3 emissionFactor;
|
||||
|
||||
bool alphaGloss;
|
||||
int alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
int gammaSpec;
|
||||
int envGloss;
|
||||
int effect_num;
|
||||
int sBasemapIndex;
|
||||
|
||||
@@ -72,7 +77,7 @@ layout (std140) uniform modelData {
|
||||
float vpwidth;
|
||||
|
||||
float vpheight;
|
||||
bool team_glow_enabled;
|
||||
int team_glow_enabled;
|
||||
float znear;
|
||||
float zfar;
|
||||
|
||||
@@ -86,9 +91,16 @@ layout (std140) uniform modelData {
|
||||
int flags;
|
||||
};
|
||||
|
||||
layout (std140) uniform shadowCascadeParams {
|
||||
#ifdef VULKAN
|
||||
layout(set = 0, binding = 6, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform shadowCascadeParams {
|
||||
int cascade_offset;
|
||||
int cascade_count;
|
||||
float rtShadowBiasMin;
|
||||
float rtShadowBiasMax;
|
||||
|
||||
mat4 shadow_mv_matrix;
|
||||
mat4 shadow_proj_matrix[NUM_SHADOW_CASCADES];
|
||||
@@ -96,16 +108,28 @@ layout (std140) uniform shadowCascadeParams {
|
||||
vec4 smoothness_factors[(NUM_SHADOW_CASCADES + 4 - 1) / 4];
|
||||
};
|
||||
|
||||
in VertexOutput {
|
||||
mat3 tangentMatrix;
|
||||
#ifdef VULKAN
|
||||
layout(set = 1, binding = 1) uniform sampler2DArray materialTextures[16];
|
||||
#define sBasemap materialTextures[0]
|
||||
#define sGlowmap materialTextures[1]
|
||||
#define sSpecmap materialTextures[2]
|
||||
#define sNormalmap materialTextures[3]
|
||||
#define sAmbientmap materialTextures[5]
|
||||
#define sMiscmap materialTextures[6]
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
float fogDist;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
layout(set = 0, binding = 2) uniform sampler2DArrayShadow shadow_map;
|
||||
layout(set = 1, binding = 5) uniform sampler2D sFramebuffer;
|
||||
|
||||
#ifdef MODEL_SDR_FLAG_RT_SHADOWS
|
||||
layout(set = 0, binding = 5) uniform accelerationStructureEXT shadow_tlas;
|
||||
#endif
|
||||
|
||||
layout(location = 0) in VertexOutput {
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
mat3 tangentMatrix;
|
||||
float fogDist;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
vec4 shadowUV[NUM_SHADOW_CASCADES];
|
||||
@@ -113,6 +137,12 @@ in VertexOutput {
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
} vertIn;
|
||||
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(location = 1) out vec4 fragOut1;
|
||||
layout(location = 2) out vec4 fragOut2;
|
||||
layout(location = 3) out vec4 fragOut3;
|
||||
layout(location = 4) out vec4 fragOut4;
|
||||
#else
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_DIFFUSE
|
||||
uniform sampler2DArray sBasemap;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_DIFFUSE
|
||||
@@ -136,16 +166,33 @@ uniform sampler2DArray sMiscmap;
|
||||
uniform sampler2DArrayShadow shadow_map;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
|
||||
out vec4 fragOut0;
|
||||
in VertexOutput {
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
float fogDist;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
vec4 shadowUV[NUM_SHADOW_CASCADES];
|
||||
vec4 shadowPos;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
} vertIn;
|
||||
|
||||
out vec4 fragOut0;
|
||||
out vec4 fragOut1;
|
||||
out vec4 fragOut2;
|
||||
out vec4 fragOut3;
|
||||
out vec4 fragOut4;
|
||||
#endif
|
||||
|
||||
vec3 FresnelLazarovEnv(vec3 specColor, vec3 view, vec3 normal, float gloss)
|
||||
{
|
||||
// Fresnel for environment lighting
|
||||
// Fresnel for environment lighting
|
||||
// Equation referenced from Dimitar Lazarov's presentation titled Physically Based Rendering in Call of Duty: Black Ops
|
||||
return specColor + (vec3(1.0) - specColor) * pow(1.0 - clamp(dot(view, normal), 0.0, 1.0), 5.0) / (4.0 - 3.0 * gloss);
|
||||
}
|
||||
@@ -180,11 +227,34 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
|
||||
vec3 lightAmbient = ambientFactor * aoFactor;
|
||||
vec3 lightDiffuse = vec3(0.0, 0.0, 0.0);
|
||||
vec3 lightSpecular = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
#ifdef MODEL_SDR_FLAG_RT_SHADOWS
|
||||
// Whenever this compile-time flag is present we're always in Vulkan/large-shader
|
||||
// mode, so `flags`/MODEL_SDR_FLAG_SHADOWS (the runtime shadow-receiving gate that
|
||||
// IF_FLAG expands to elsewhere in this file) are guaranteed to exist here too.
|
||||
bool rtShadowsActive = (flags & MODEL_SDR_FLAG_SHADOWS) != 0;
|
||||
mat4 invView = inverse(viewMatrix);
|
||||
vec3 worldPos = (invView * vertIn.position).xyz;
|
||||
vec3 worldNormal = normalize((invView * vec4(normal, 0.0)).xyz);
|
||||
int shadowedDirectionalCount = 0;
|
||||
#endif
|
||||
|
||||
#pragma optionNV unroll all
|
||||
for (int i = 0; i < n_lights; ++i) {
|
||||
#ifdef MODEL_SDR_FLAG_RT_SHADOWS
|
||||
if (rtShadowsActive && lights[i].light_type == LT_DIRECTIONAL && shadowedDirectionalCount < MAX_RT_SHADOW_LIGHTS) {
|
||||
vec3 worldSunDir = normalize((invView * vec4(lights[i].position.xyz, 0.0)).xyz);
|
||||
float rtShadowBias = computeRtShadowBias(length(vertIn.position.xyz), rtShadowBiasMin, rtShadowBiasMax);
|
||||
shadow = traceShadowRay(shadow_tlas, worldPos, worldNormal, worldSunDir, RT_SHADOW_MAX_DISTANCE, rtShadowBias);
|
||||
++shadowedDirectionalCount;
|
||||
} else {
|
||||
shadow = 1.0;
|
||||
}
|
||||
#else
|
||||
if(i > 0) {
|
||||
shadow = 1.0;
|
||||
}
|
||||
#endif
|
||||
float roughness = clamp(1.0f - gloss, 0.0f, 1.0f);
|
||||
float alpha = roughness * roughness;
|
||||
vec3 lightDir;
|
||||
@@ -207,7 +277,6 @@ void main()
|
||||
|
||||
// setup our baseline values for base, emissive, fresnel, gloss, AO and normal
|
||||
// default specular value is set below, as it depends on the diffuse color
|
||||
|
||||
vec4 baseColor = color;
|
||||
vec4 emissiveColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
float fresnelFactor = 0.0;
|
||||
@@ -216,6 +285,7 @@ void main()
|
||||
vec3 unitNormal = normalize(vertIn.normal);
|
||||
vec3 normal = unitNormal;
|
||||
|
||||
// Ambient occlusion map
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_AMBIENT
|
||||
// red channel is ambient occlusion factor which only affects ambient lighting.
|
||||
// green is cavity occlusion factor which only affects diffuse and specular lighting.
|
||||
@@ -242,6 +312,7 @@ void main()
|
||||
distort = vec2(cos(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005),sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*cos(vertIn.position.y*vertIn.position.w*0.005))*0.03;
|
||||
}
|
||||
|
||||
// Diffuse map
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
|
||||
vec2 diffuseTexCoord = texCoord;
|
||||
if (effect_num == 2) {
|
||||
@@ -249,7 +320,7 @@ void main()
|
||||
}
|
||||
baseColor = texture(sBasemap, vec3(diffuseTexCoord, float(sBasemapIndex)));
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
|
||||
baseColor.rgb = srgb_to_linear(baseColor.rgb);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
|
||||
|
||||
@@ -265,7 +336,7 @@ void main()
|
||||
|
||||
// Anti-glint "trick" based on Valve's "Advanced VR Rendering" talk at GDC2015:
|
||||
// http://media.steampowered.com/apps/valve/2015/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf Page 43
|
||||
// basically make surfaces rougher if local normals change too fast in screenspace
|
||||
// basically make surfaces rougher if local normals change too fast in screenspace
|
||||
vec2 normDx = dFdx(unitNormal.xy);
|
||||
vec2 normDy = dFdy(unitNormal.xy);
|
||||
float glossGeo = 1.0f - pow(clamp(max(dot(normDx,normDx), dot(normDy,normDy)),0.0,1.0),0.33);
|
||||
@@ -273,19 +344,20 @@ void main()
|
||||
|
||||
// Now that we have a base color and min gloss value, compute the spec color
|
||||
vec4 specColor = vec4(baseColor.rgb * SPEC_FACTOR_NO_SPEC_MAP, glossData);
|
||||
|
||||
|
||||
// Specular map
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
|
||||
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ALPHA_MULT
|
||||
specColor *= alphaMult;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ALPHA_MULT
|
||||
|
||||
if(alphaGloss) glossData = specColor.a;
|
||||
if(gammaSpec) {
|
||||
specColor.rgb = max(specColor.rgb, vec3(0.03f)); // hardcoded minimum specular value. read John Hable's blog post titled 'Everything Is Shiny'.
|
||||
if(alphaGloss != 0) glossData = specColor.a;
|
||||
if(gammaSpec != 0) {
|
||||
specColor.rgb = max(specColor.rgb, vec3(0.03f)); // hardcoded minimum specular value. read John Hable's blog post titled 'Everything Is Shiny'.
|
||||
fresnelFactor = 1.0;
|
||||
}
|
||||
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
|
||||
specColor.rgb = srgb_to_linear(specColor.rgb);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
|
||||
@@ -297,11 +369,12 @@ void main()
|
||||
vec4 teamMask = vec4(0.0);
|
||||
vec3 team_color_glow = vec3(0.0);
|
||||
|
||||
// Misc map / team colors
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_MISC
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_TEAMCOLOR
|
||||
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
|
||||
|
||||
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
|
||||
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
|
||||
//at this point is vec3(0.5). To get accurate results, we subtract 0.5 from the team colors
|
||||
vec3 color_offset = vec3(-0.5) * (teamMask.x + teamMask.y);
|
||||
|
||||
@@ -313,11 +386,11 @@ void main()
|
||||
specColor.rgb = linear_to_srgb(specColor.rgb);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
|
||||
|
||||
baseColor.rgb += team_color;
|
||||
baseColor.rgb += team_color;
|
||||
baseColor.rgb = max(baseColor.rgb, vec3(0.0)); // We need to make sure that nothing here ever goes negative
|
||||
specColor.rgb += team_color;
|
||||
specColor.rgb = max(specColor.rgb, vec3(0.03));
|
||||
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
|
||||
baseColor.rgb = srgb_to_linear(baseColor.rgb);
|
||||
specColor.rgb = srgb_to_linear(specColor.rgb);
|
||||
@@ -330,7 +403,12 @@ void main()
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
|
||||
float shadow = 1.0;
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
|
||||
// Raytraced shadows are computed per-light (for every directional light,
|
||||
// up to MAX_RT_SHADOW_LIGHTS) inside CalculateLighting()'s loop instead --
|
||||
// this single shared `shadow` value only matters for the CSM fallback below.
|
||||
#ifndef MODEL_SDR_FLAG_RT_SHADOWS
|
||||
shadow = getShadowValue(shadow_map, -vertIn.position.z, vertIn.shadowUV, cascade_distances, smoothness_factors, cascade_offset, cascade_count);
|
||||
#endif
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
|
||||
baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors.x);
|
||||
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
@@ -340,12 +418,13 @@ void main()
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
|
||||
// Glow map
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_GLOW
|
||||
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_MISC
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_TEAMCOLOR
|
||||
float glowColorLuminance = dot(glowColor, vec3(0.299, 0.587, 0.114));
|
||||
glowColor = team_glow_enabled ? mix(max(team_color_glow, vec3(0.0)), glowColor, clamp(glowColorLuminance - teamMask.b - teamMask.a, 0.0, 1.0)) : glowColor;
|
||||
glowColor = (team_glow_enabled != 0) ? mix(max(team_color_glow, vec3(0.0)), glowColor, clamp(glowColorLuminance - teamMask.b - teamMask.a, 0.0, 1.0)) : glowColor;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TEAMCOLOR
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_MISC
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
|
||||
@@ -375,12 +454,14 @@ void main()
|
||||
specColor.rgb *= fogDensityFinal;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
|
||||
|
||||
// Desaturation
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
|
||||
if(desaturate == 1) {
|
||||
baseColor.rgb = color.rgb * dot(vec3(1.0), baseColor.rgb) * 0.3333333;
|
||||
}
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
|
||||
|
||||
|
||||
// Ship effects
|
||||
if (effect_num == 0) {
|
||||
float shinefactor = 1.0/(1.0 + pow(abs((fract(abs(texCoord.x))-anim_timer) * 1000.0), 2.0)) * 1000.0;
|
||||
emissiveColor.rgb += vec3(shinefactor);
|
||||
@@ -427,5 +508,11 @@ void main()
|
||||
fragOut2 = vec4(normal, glossData);
|
||||
fragOut3 = vec4(specColor.rgb, fresnelFactor);
|
||||
fragOut4 = emissiveColor;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
}
|
||||
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
// Vulkan has undefined values for unwritten outputs; zero-init G-buffer outputs
|
||||
fragOut1 = vec4(0.0);
|
||||
fragOut2 = vec4(0.0);
|
||||
fragOut3 = vec4(0.0);
|
||||
fragOut4 = vec4(0.0);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
}
|
||||
@@ -41,7 +41,7 @@ layout (std140) uniform modelData {
|
||||
vec4 clip_equation;
|
||||
|
||||
float thruster_scale;
|
||||
bool use_clip_plane;
|
||||
int use_clip_plane;
|
||||
int n_lights;
|
||||
float defaultGloss;
|
||||
|
||||
@@ -53,10 +53,10 @@ layout (std140) uniform modelData {
|
||||
|
||||
vec3 emissionFactor;
|
||||
|
||||
bool alphaGloss;
|
||||
int alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
int gammaSpec;
|
||||
int envGloss;
|
||||
int effect_num;
|
||||
int sBasemapIndex;
|
||||
|
||||
@@ -69,7 +69,7 @@ layout (std140) uniform modelData {
|
||||
float vpwidth;
|
||||
|
||||
float vpheight;
|
||||
bool team_glow_enabled;
|
||||
int team_glow_enabled;
|
||||
float znear;
|
||||
float zfar;
|
||||
|
||||
@@ -165,7 +165,7 @@ out VertexOutput {
|
||||
vertOut.shadowPos = vertIn[vert].shadowPos;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
|
||||
|
||||
if (use_clip_plane) {
|
||||
if (use_clip_plane != 0) {
|
||||
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
|
||||
}
|
||||
EmitVertex();
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
|
||||
#ifndef VULKAN
|
||||
//? #version 150
|
||||
#extension GL_ARB_gpu_shader5: enable
|
||||
|
||||
#endif
|
||||
#include "shadows.sdr"
|
||||
|
||||
#conditional_include +"LARGE_SHADER" "main_large.sdr"
|
||||
#conditional_include -"LARGE_SHADER" "main_small.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec4 vertPosition;
|
||||
layout(location = 1) in vec4 vertColor;
|
||||
layout(location = 2) in vec4 vertTexCoord;
|
||||
layout(location = 3) in vec3 vertNormal;
|
||||
layout(location = 4) in vec4 vertTangent;
|
||||
layout(location = 5) in float vertModelID;
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in vec4 vertTexCoord;
|
||||
in vec3 vertNormal;
|
||||
in vec4 vertTangent;
|
||||
in float vertModelID;
|
||||
#endif
|
||||
|
||||
#define MAX_LIGHTS 8
|
||||
|
||||
@@ -26,7 +37,12 @@ struct model_light {
|
||||
float ml_sourceRadius;
|
||||
};
|
||||
|
||||
layout (std140) uniform modelData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 1, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform modelData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 modelMatrix;
|
||||
mat4 viewMatrix;
|
||||
@@ -45,7 +61,7 @@ layout (std140) uniform modelData {
|
||||
vec4 clip_equation;
|
||||
|
||||
float thruster_scale;
|
||||
bool use_clip_plane;
|
||||
int use_clip_plane;
|
||||
int n_lights;
|
||||
float defaultGloss;
|
||||
|
||||
@@ -57,10 +73,10 @@ layout (std140) uniform modelData {
|
||||
|
||||
vec3 emissionFactor;
|
||||
|
||||
bool alphaGloss;
|
||||
int alphaGloss;
|
||||
|
||||
bool gammaSpec;
|
||||
bool envGloss;
|
||||
int gammaSpec;
|
||||
int envGloss;
|
||||
int effect_num;
|
||||
int sBasemapIndex;
|
||||
|
||||
@@ -73,7 +89,7 @@ layout (std140) uniform modelData {
|
||||
float vpwidth;
|
||||
|
||||
float vpheight;
|
||||
bool team_glow_enabled;
|
||||
int team_glow_enabled;
|
||||
float znear;
|
||||
float zfar;
|
||||
|
||||
@@ -89,9 +105,16 @@ layout (std140) uniform modelData {
|
||||
int flags;
|
||||
};
|
||||
|
||||
layout (std140) uniform shadowCascadeParams {
|
||||
#ifdef VULKAN
|
||||
layout(set = 0, binding = 6, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform shadowCascadeParams {
|
||||
int cascade_offset;
|
||||
int cascade_count;
|
||||
float rtShadowBiasMin;
|
||||
float rtShadowBiasMax;
|
||||
|
||||
mat4 shadow_mv_matrix;
|
||||
mat4 shadow_proj_matrix[NUM_SHADOW_CASCADES];
|
||||
@@ -99,6 +122,23 @@ layout (std140) uniform shadowCascadeParams {
|
||||
vec4 smoothness_factors[(NUM_SHADOW_CASCADES + 4 - 1) / 4];
|
||||
};
|
||||
|
||||
#ifdef VULKAN
|
||||
// Transform buffer for batched submodel rendering
|
||||
layout(set = 1, binding = 3, std430) readonly buffer TransformBuffer {
|
||||
mat4 transforms[];
|
||||
} transformBuf;
|
||||
|
||||
// Outputs to fragment shader
|
||||
layout(location = 0) out VertexOutput {
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
mat3 tangentMatrix;
|
||||
float fogDist;
|
||||
vec4 shadowUV[NUM_SHADOW_CASCADES];
|
||||
vec4 shadowPos;
|
||||
} vertOut;
|
||||
#else
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
|
||||
uniform samplerBuffer transform_tex;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
|
||||
@@ -132,6 +172,7 @@ void getModelTransform(inout mat4 transform, out bool invisible, int id, int mat
|
||||
transform[3].w = 1.0;
|
||||
}
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -139,20 +180,30 @@ void main()
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
mat4 orient = mat4(1.0);
|
||||
mat4 scale = mat4(1.0);
|
||||
bool clipModel = false;
|
||||
|
||||
|
||||
// Transform loading
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
|
||||
#ifdef VULKAN
|
||||
int id = int(vertModelID);
|
||||
orient = transformBuf.transforms[buffer_matrix_offset + id];
|
||||
clipModel = (orient[3].w >= 0.9);
|
||||
orient[3].w = 1.0;
|
||||
#else
|
||||
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
|
||||
#endif
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
|
||||
|
||||
texCoord = textureMatrix * vertTexCoord;
|
||||
vec4 vertex = vertPosition;
|
||||
|
||||
// Thruster scale
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_THRUSTER
|
||||
if(vertex.z < -1.5) {
|
||||
vertex.z *= thruster_scale;
|
||||
}
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_THRUSTER
|
||||
|
||||
// Transform the normal into eye space and normalize the result.
|
||||
normal = normalize(mat3(modelViewMatrix) * mat3(orient) * vertNormal);
|
||||
position = modelViewMatrix * orient * vertex;
|
||||
@@ -170,10 +221,17 @@ void main()
|
||||
vec3 b = cross(normal, t) * vertTangent.w;
|
||||
vertOut.tangentMatrix = mat3(t, b, normal);
|
||||
|
||||
// Fog distance
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
|
||||
vertOut.fogDist = gl_Position.z - fogNear;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
|
||||
#ifdef VULKAN
|
||||
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_FOG
|
||||
vertOut.fogDist = 0.0;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
|
||||
#endif
|
||||
|
||||
// Clip invisible (blown-off) submodels
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
|
||||
if (clipModel) {
|
||||
// Clip this model by moving all vertices outside the clip volume
|
||||
@@ -181,7 +239,8 @@ void main()
|
||||
}
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
|
||||
|
||||
if(use_clip_plane) {
|
||||
// Clip plane
|
||||
if(use_clip_plane != 0) {
|
||||
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
|
||||
} else {
|
||||
gl_ClipDistance[0] = 1.0;
|
||||
|
||||
@@ -27,8 +27,14 @@ SDR_FLAG(MODEL_SDR_FLAG_ALPHA_MULT , (1 << 14), false)
|
||||
#ifndef MODEL_SDR_FLAG_MODE_GLSL
|
||||
//The following ones are used ONLY as compile-time flags, but they still need to be defined here to ensure no conflict occurs
|
||||
//But since these are checked with ifdefs even for the large shader, they must never be available in GLSL mode
|
||||
|
||||
SDR_FLAG(MODEL_SDR_FLAG_SHADOW_MAP , (1 << 15), true)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_THICK_OUTLINES, (1 << 16), true)
|
||||
|
||||
// Like MODEL_SDR_FLAG_SHADOW_MAP/THICK_OUTLINES above, this must stay a genuine
|
||||
// compile-time ifdef check (not the runtime flag-branch macros used for ordinary
|
||||
// MODEL_SDR_FLAG_* bits) since Vulkan always runs in "large shader" mode, where
|
||||
// those bits are only checked via a runtime `flags` uniform -- ray query usage
|
||||
// can't be gated that way, since the GL_EXT_ray_query extension and its types
|
||||
// must not appear at all in a shader compiled for hardware that doesn't support it.
|
||||
SDR_FLAG(MODEL_SDR_FLAG_RT_SHADOWS , (1 << 17), true)
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,27 @@
|
||||
#include "z-compress.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(location = 1) out vec4 fragOut1;
|
||||
layout(location = 2) out vec4 fragOut2;
|
||||
layout(location = 3) out vec4 fragOut3;
|
||||
layout(location = 4) out vec4 fragOut4;
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler2DMS msaaTex[6];
|
||||
#define texColor msaaTex[0]
|
||||
#define texPos msaaTex[1]
|
||||
#define texNormal msaaTex[2]
|
||||
#define texSpecular msaaTex[3]
|
||||
#define texEmissive msaaTex[4]
|
||||
#define texDepth msaaTex[5]
|
||||
|
||||
layout(std140, set = 2, binding = 0) uniform genericData {
|
||||
int samples;
|
||||
float fov;
|
||||
};
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
out vec4 fragOut1;
|
||||
@@ -19,17 +41,20 @@ layout (std140) uniform genericData {
|
||||
int samples;
|
||||
float fov;
|
||||
};
|
||||
#endif
|
||||
|
||||
const float voxelDepth = 2.5f;
|
||||
const float voxelDepthFalloff = 2.5f;
|
||||
|
||||
#define SORT(a, b) if (a > b) { float t = dists[a]; dists[a] = dists[b]; dists[b] = t; }
|
||||
#define SORT(a, b) if (dists[a] > dists[b]) { float t = dists[a]; dists[a] = dists[b]; dists[b] = t; }
|
||||
|
||||
//The following sorting networks for median calculation are NOT complete. Calculations that don't affect the
|
||||
//median entry are removed, and thus, while the median element is correct, the rest of the array is NOT fully sorted
|
||||
|
||||
#ifdef SAMPLES_4
|
||||
|
||||
#define SAMPLE_CNT 4
|
||||
|
||||
float getMedianDist(ivec2 texel) {
|
||||
float dists[4];
|
||||
|
||||
@@ -49,6 +74,8 @@ float getMedianDist(ivec2 texel) {
|
||||
#else
|
||||
#ifdef SAMPLES_8
|
||||
|
||||
#define SAMPLE_CNT 8
|
||||
|
||||
float getMedianDist(ivec2 texel) {
|
||||
float dists[8];
|
||||
|
||||
@@ -80,6 +107,8 @@ float getMedianDist(ivec2 texel) {
|
||||
#else
|
||||
#ifdef SAMPLES_16
|
||||
|
||||
#define SAMPLE_CNT 16
|
||||
|
||||
float getMedianDist(ivec2 texel) {
|
||||
float dists[16];
|
||||
|
||||
@@ -143,6 +172,8 @@ float getMedianDist(ivec2 texel) {
|
||||
|
||||
#else
|
||||
|
||||
#define SAMPLE_CNT samples
|
||||
|
||||
//Fallback, do front first
|
||||
float getMedianDist(ivec2 texel) {
|
||||
float minDist = -1000000;
|
||||
@@ -160,7 +191,11 @@ float getMedianDist(ivec2 texel) {
|
||||
void main()
|
||||
{
|
||||
vec2 texSize = textureSize(texColor);
|
||||
#ifdef VULKAN
|
||||
ivec2 texel = ivec2(texSize * fragTexCoord);
|
||||
#else
|
||||
ivec2 texel = ivec2(texSize * fragTexCoord.xy);
|
||||
#endif
|
||||
|
||||
float texelWidthFactor = tan(fov / texSize.y);
|
||||
float dist = getMedianDist(texel);
|
||||
@@ -173,7 +208,7 @@ void main()
|
||||
vec4 emissive = vec4(0);
|
||||
float depth = 0;
|
||||
|
||||
for(int i = 0; i < samples; i++) {
|
||||
for(int i = 0; i < SAMPLE_CNT; i++) {
|
||||
vec4 localPos = texelFetch(texPos, texel, i);
|
||||
localPos.z = uncompress_depth_value(localPos.z);
|
||||
//Calculate local weight from distance Voxel, but if the distance is 0 (i.e. no model at all), set weight to 1 to allow stuff like background emissive
|
||||
|
||||
@@ -1,37 +1,44 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout (location = 0) in vec2 ftcoord;
|
||||
layout (location = 1) in vec2 fpos;
|
||||
|
||||
layout (location = 0) out vec4 outColor;
|
||||
|
||||
layout (set = 1, binding = 1) uniform sampler2DArray nvg_tex;
|
||||
#else
|
||||
// Enabled at all times but the define is kept here in case this should be configurable in the future
|
||||
#define EDGE_AA
|
||||
|
||||
layout(std140) uniform NanoVGUniformData {
|
||||
mat3 scissorMat;
|
||||
|
||||
mat3 paintMat;
|
||||
|
||||
vec4 innerCol;
|
||||
|
||||
vec4 outerCol;
|
||||
|
||||
vec2 scissorExt;
|
||||
vec2 scissorScale;
|
||||
|
||||
vec2 extent;
|
||||
float radius;
|
||||
float feather;
|
||||
|
||||
float strokeMult;
|
||||
float strokeThr;
|
||||
int texType;
|
||||
int type;
|
||||
|
||||
vec2 viewSize;
|
||||
int texArrayIndex;
|
||||
};
|
||||
|
||||
uniform sampler2DArray nvg_tex;
|
||||
|
||||
in vec2 ftcoord;
|
||||
in vec2 fpos;
|
||||
out vec4 outColor;
|
||||
#endif
|
||||
|
||||
#ifdef VULKAN
|
||||
layout (set = 2, binding = 2, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform NanoVGUniformData {
|
||||
mat3 scissorMat;
|
||||
mat3 paintMat;
|
||||
vec4 innerCol;
|
||||
vec4 outerCol;
|
||||
vec2 scissorExt;
|
||||
vec2 scissorScale;
|
||||
vec2 extent;
|
||||
float radius;
|
||||
float feather;
|
||||
float strokeMult;
|
||||
float strokeThr;
|
||||
int texType;
|
||||
int type;
|
||||
vec2 viewSize;
|
||||
int texArrayIndex;
|
||||
};
|
||||
|
||||
float sdroundrect(vec2 pt, vec2 ext, float rad) {
|
||||
vec2 ext2 = ext - vec2(rad,rad);
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
|
||||
layout(std140) uniform NanoVGUniformData {
|
||||
#ifdef VULKAN
|
||||
layout (location = 0) in vec4 vertPosition;
|
||||
layout (location = 2) in vec4 vertTexCoord;
|
||||
|
||||
layout (location = 0) out vec2 ftcoord;
|
||||
layout (location = 1) out vec2 fpos;
|
||||
#else
|
||||
in vec2 vertPosition;
|
||||
in vec2 vertTexCoord;
|
||||
|
||||
out vec2 ftcoord;
|
||||
out vec2 fpos;
|
||||
#endif
|
||||
|
||||
#ifdef VULKAN
|
||||
layout (set = 2, binding = 2, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform NanoVGUniformData {
|
||||
mat3 scissorMat;
|
||||
|
||||
mat3 paintMat;
|
||||
@@ -24,14 +43,16 @@ layout(std140) uniform NanoVGUniformData {
|
||||
int texArrayIndex;
|
||||
};
|
||||
|
||||
in vec2 vertPosition;
|
||||
in vec2 vertTexCoord;
|
||||
|
||||
out vec2 ftcoord;
|
||||
out vec2 fpos;
|
||||
|
||||
void main(void) {
|
||||
#ifdef VULKAN
|
||||
ftcoord = vertTexCoord.xy;
|
||||
fpos = vertPosition.xy;
|
||||
gl_Position = vec4(2.0 * vertPosition.x / viewSize.x - 1.0,
|
||||
1.0 - 2.0 * vertPosition.y / viewSize.y,
|
||||
0.0, 1.0);
|
||||
#else
|
||||
ftcoord = vertTexCoord;
|
||||
fpos = vertPosition;
|
||||
gl_Position = vec4(2.0*vertPosition.x/viewSize.x - 1.0, 1.0 - 2.0*vertPosition.y/viewSize.y, 0, 1);
|
||||
#endif
|
||||
}
|
||||
@@ -1,11 +1,21 @@
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(set = 1, binding = 1) uniform sampler2D tex;
|
||||
layout(set = 1, binding = 4) uniform sampler2D depth_tex;
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform sampler2D depth_tex;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
float timer;
|
||||
float noise_amount;
|
||||
float saturation;
|
||||
@@ -19,7 +29,7 @@ layout (std140) uniform genericData {
|
||||
vec3 tint;
|
||||
float dither;
|
||||
|
||||
// these are blank, valid slots for modders to create custom effects
|
||||
// these are blank, valid slots for modders to create custom effects
|
||||
// that can be defined in post_processing.tbl and coded below
|
||||
vec3 custom_effect_vec3_a;
|
||||
float custom_effect_float_a;
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) out vec2 fragTexCoord;
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in vec4 vertTexCoord;
|
||||
out vec4 fragTexCoord;
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef VULKAN
|
||||
vec2 pos = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
fragTexCoord = pos;
|
||||
gl_Position = vec4(pos * 2.0 - 1.0, 0.0, 1.0);
|
||||
#else
|
||||
fragTexCoord = vertTexCoord;
|
||||
gl_Position = vertPosition;
|
||||
#endif
|
||||
}
|
||||
@@ -1,4 +1,13 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 1) in vec4 fragColor;
|
||||
layout(location = 2) in vec2 fragScreenPosition;
|
||||
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler2DArray baseMap;
|
||||
#else
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
in vec2 fragScreenPosition;
|
||||
@@ -6,12 +15,18 @@ in vec2 fragScreenPosition;
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2DArray baseMap;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
mat4 projMatrix;
|
||||
|
||||
vec2 offset;
|
||||
bool textured;
|
||||
int textured;
|
||||
int baseMapIndex;
|
||||
|
||||
float horizontalSwipeOffset;
|
||||
@@ -25,7 +40,7 @@ void main() {
|
||||
float distance = horizontalSwipeOffset - fragScreenPosition.x;
|
||||
|
||||
vec4 color;
|
||||
if (textured) {
|
||||
if (textured != 0) {
|
||||
color = texture(baseMap, vec3(fragTexCoord, float(baseMapIndex))) * fragColor;
|
||||
} else {
|
||||
color = fragColor;
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 vertPosition;
|
||||
layout(location = 1) in vec4 vertColor;
|
||||
layout(location = 2) in vec2 vertTexCoord;
|
||||
|
||||
layout(location = 0) out vec2 fragTexCoord;
|
||||
layout(location = 1) out vec4 fragColor;
|
||||
layout(location = 2) out vec2 fragScreenPosition;
|
||||
#else
|
||||
in vec2 vertPosition;
|
||||
in vec4 vertColor;
|
||||
in vec2 vertTexCoord;
|
||||
@@ -6,12 +15,18 @@ in vec2 vertTexCoord;
|
||||
out vec2 fragTexCoord;
|
||||
out vec4 fragColor;
|
||||
out vec2 fragScreenPosition;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
mat4 projMatrix;
|
||||
|
||||
vec2 offset;
|
||||
bool textured;
|
||||
int textured;
|
||||
int baseMapIndex;
|
||||
|
||||
float horizontalSwipeOffset;
|
||||
|
||||
@@ -5,23 +5,43 @@
|
||||
#extension GL_ARB_shader_viewport_layer_array : enable
|
||||
#endif
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec4 vertPosition;
|
||||
layout(location = 2) in vec4 vertTexCoord;
|
||||
layout(location = 3) in vec3 vertNormal;
|
||||
layout(location = 4) in vec4 vertTangent;
|
||||
layout(location = 5) in float vertModelID;
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in vec4 vertTexCoord;
|
||||
in vec3 vertNormal;
|
||||
in vec4 vertTangent;
|
||||
in float vertModelID;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform shadowMapData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 1, binding = 7, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform shadowMapData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 modelMatrix;
|
||||
vec4 clip_equation;
|
||||
bool use_clip_plane;
|
||||
int use_clip_plane;
|
||||
int buffer_matrix_offset;
|
||||
};
|
||||
|
||||
layout (std140) uniform shadowCascadeParams {
|
||||
#ifdef VULKAN
|
||||
layout(set = 0, binding = 6, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform shadowCascadeParams {
|
||||
int cascade_offset;
|
||||
int cascade_count;
|
||||
float rtShadowBiasMin;
|
||||
float rtShadowBiasMax;
|
||||
|
||||
mat4 shadow_mv_matrix;
|
||||
mat4 shadow_proj_matrix[NUM_SHADOW_CASCADES];
|
||||
@@ -29,8 +49,17 @@ layout (std140) uniform shadowCascadeParams {
|
||||
vec4 smoothness_factors[(NUM_SHADOW_CASCADES + 4 - 1) / 4];
|
||||
};
|
||||
|
||||
#ifdef VULKAN
|
||||
// Transform buffer for batched submodel rendering (matches main-v.sdr)
|
||||
layout(set = 1, binding = 3, std430) readonly buffer TransformBuffer {
|
||||
mat4 transforms[];
|
||||
} transformBuf;
|
||||
#else
|
||||
uniform samplerBuffer transform_tex;
|
||||
#endif
|
||||
|
||||
// GEOMETRY_FALLBACK is only ever requested on the OpenGL backend (Vulkan always
|
||||
// supports writing gl_Layer from the vertex shader, see CAPABILITY_FAST_SHADOWS).
|
||||
#ifdef GEOMETRY_FALLBACK
|
||||
out VertexOutput {
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
@@ -43,6 +72,7 @@ out VertexOutput {
|
||||
|
||||
#define TEXELS_PER_MATRIX 4
|
||||
|
||||
#ifndef VULKAN
|
||||
void getModelTransform(inout mat4 transform, out bool invisible, int id, int matrix_offset)
|
||||
{
|
||||
transform[0] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX);
|
||||
@@ -52,6 +82,7 @@ void getModelTransform(inout mat4 transform, out bool invisible, int id, int mat
|
||||
invisible = transform[3].w >= 0.9;
|
||||
transform[3].w = 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -60,19 +91,31 @@ void main()
|
||||
mat4 orient = mat4(1.0);
|
||||
bool clipModel = false;
|
||||
|
||||
#ifdef VULKAN
|
||||
int id = int(vertModelID);
|
||||
orient = transformBuf.transforms[buffer_matrix_offset + id];
|
||||
clipModel = (orient[3].w >= 0.9);
|
||||
orient[3].w = 1.0;
|
||||
#else
|
||||
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
|
||||
#endif
|
||||
|
||||
vec4 vertex = vertPosition;
|
||||
|
||||
normal = normalize(mat3(modelViewMatrix) * mat3(orient) * vertNormal);
|
||||
position = modelViewMatrix * orient * vertex;
|
||||
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
#ifdef APPLE
|
||||
vertOut.instance = float(gl_InstanceIDARB);
|
||||
#else
|
||||
vertOut.instance = float(gl_InstanceID);
|
||||
#endif
|
||||
#ifdef VULKAN
|
||||
int instanceIndex = gl_InstanceIndex;
|
||||
#else
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
#ifdef APPLE
|
||||
vertOut.instance = float(gl_InstanceIDARB);
|
||||
#else
|
||||
vertOut.instance = float(gl_InstanceID);
|
||||
#endif
|
||||
#endif
|
||||
int instanceIndex = gl_InstanceID;
|
||||
#endif
|
||||
|
||||
if (clipModel) {
|
||||
@@ -80,13 +123,13 @@ void main()
|
||||
}
|
||||
else {
|
||||
#ifndef GEOMETRY_FALLBACK
|
||||
int cascade_id = cascade_offset + gl_InstanceID;
|
||||
int cascade_id = cascade_offset + instanceIndex;
|
||||
position = shadow_proj_matrix[cascade_id] * position;
|
||||
#endif
|
||||
gl_Position = position;
|
||||
}
|
||||
|
||||
if (use_clip_plane) {
|
||||
if (use_clip_plane != 0) {
|
||||
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
|
||||
} else {
|
||||
gl_ClipDistance[0] = 1.0;
|
||||
@@ -96,6 +139,6 @@ void main()
|
||||
vertOut.normal = normal;
|
||||
vertOut.clipModel = clipModel ? 1.0 : 0.0;
|
||||
#else
|
||||
gl_Layer = cascade_offset + gl_InstanceID;
|
||||
gl_Layer = cascade_offset + instanceIndex;
|
||||
#endif
|
||||
}
|
||||
@@ -6,17 +6,6 @@
|
||||
#define SAMPLES_PCSS 1
|
||||
#endif
|
||||
|
||||
vec4 transformToShadowMap(mat4 shadow_proj_matrix, int i, vec4 pos)
|
||||
{
|
||||
vec4 shadow_proj;
|
||||
shadow_proj = shadow_proj_matrix * pos;
|
||||
shadow_proj += 1.0;
|
||||
shadow_proj *= 0.5;
|
||||
shadow_proj.w = shadow_proj.z;
|
||||
shadow_proj.z = float(i);
|
||||
return shadow_proj;
|
||||
}
|
||||
|
||||
float samplePoissonPCSS(sampler2DArrayShadow shadow_map, vec4 shadowUV, float maxUVOffset)
|
||||
{
|
||||
#if SMOOTH_PCSS
|
||||
@@ -78,3 +67,80 @@ float getShadowValue(sampler2DArrayShadow shadow_map, float depth, vec4 shadowUV
|
||||
samplePoissonPCSS(shadow_map, shadowUV[cascade + 1], smoothness_factors[(cascade + 1) / 4][(cascade + 1) % 4]),
|
||||
smoothstep(cascade_end - dist_threshold, cascade_end, depth));
|
||||
}
|
||||
// Raytraced shadow test via inline ray query against the shadow TLAS. Only
|
||||
// compiled in for the specific shader variants that request it (MODEL shaders
|
||||
// via MODEL_SDR_FLAG_RT_SHADOWS, deferred lighting via RT_SHADOWS) -- both are
|
||||
// genuine compile-time #defines (not the runtime `flags` uniform branch that
|
||||
// other MODEL_SDR_FLAG_* bits use), so GL_EXT_ray_query and its types never
|
||||
// appear in a shader compiled for hardware that doesn't support them.
|
||||
// Distance used for lights with no physical extent to shadow against (directional/sun
|
||||
// lights) -- effectively unbounded relative to any FS2Open mission scale. Defined
|
||||
// unconditionally (not just under the RT_SHADOWS guard below) since GetLightInfo()
|
||||
// in deferred-f.sdr/main-f.sdr references it regardless of which shadow method is active.
|
||||
const float RT_SHADOW_MAX_DISTANCE = 10000.0;
|
||||
|
||||
#if defined(MODEL_SDR_FLAG_RT_SHADOWS) || defined(RT_SHADOWS)
|
||||
#extension GL_EXT_ray_query : require
|
||||
|
||||
// Ray origin bias grows with distance from the camera, between the rtShadowBiasMin/
|
||||
// rtShadowBiasMax bounds (see shadowCascadeParams uniform block, and the Min/Max
|
||||
// Raytraced Shadow Bias options in shadows.cpp). Empirically, geometry close to the
|
||||
// camera only needs biasMin worth of offset to clear self-intersection acne, while
|
||||
// distant geometry needs more -- consistent with the error source being G-buffer/
|
||||
// rasterization position-reconstruction precision (which degrades with view depth),
|
||||
// not a fixed float-precision quantity (a prior attempt using the Ray Tracing Gems
|
||||
// ch.6 "next representable float" technique, which only accounts for the latter,
|
||||
// made acne *worse* since its offset was far too small for the actual error here).
|
||||
// cameraDist is view-space distance (i.e. length() of the camera-relative position
|
||||
// already available at both call sites), not world-space distance from the origin.
|
||||
const float RT_SHADOW_BIAS_RAMP_DISTANCE = 2000.0;
|
||||
|
||||
float computeRtShadowBias(float cameraDist, float biasMin, float biasMax)
|
||||
{
|
||||
return mix(biasMin, biasMax, clamp(cameraDist / RT_SHADOW_BIAS_RAMP_DISTANCE, 0.0, 1.0));
|
||||
}
|
||||
|
||||
// worldPos/worldNormal/worldLightDir must all be in the same world space the
|
||||
// shadow TLAS was built in (see VulkanRaytracingManager::buildTlas()) -- i.e.
|
||||
// FS2Open object-space positions/orientations, not view/eye-space. worldLightDir
|
||||
// must point FROM the surface TOWARD the light.
|
||||
//
|
||||
// tMax must be the actual distance to the light (RT_SHADOW_MAX_DISTANCE for
|
||||
// directional lights, which have no real distance). For point/tube/cone lights this
|
||||
// is a correctness requirement, not just a cost bound: without it, geometry sitting
|
||||
// behind the light (farther from the surface than the light itself) would register
|
||||
// as a hit and incorrectly shadow the fragment, since a light can't be occluded by
|
||||
// something it doesn't reach.
|
||||
//
|
||||
// bias is a world-unit offset applied along worldNormal before tracing, to clear
|
||||
// the source triangle -- see computeRtShadowBias() above for how callers derive it.
|
||||
float traceShadowRay(accelerationStructureEXT tlas, vec3 worldPos, vec3 worldNormal, vec3 worldLightDir, float tMax, float bias)
|
||||
{
|
||||
vec3 origin = worldPos + worldNormal * bias;
|
||||
vec3 direction = normalize(worldLightDir);
|
||||
|
||||
rayQueryEXT rq;
|
||||
rayQueryInitializeEXT(rq, tlas, gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT,
|
||||
0xFF, origin, 0.001, direction, tMax);
|
||||
while (rayQueryProceedEXT(rq)) {}
|
||||
|
||||
return (rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionNoneEXT) ? 1.0 : 0.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
vec4 transformToShadowMap(mat4 shadow_proj_matrix, int i, vec4 pos)
|
||||
{
|
||||
vec4 shadow_proj;
|
||||
shadow_proj = shadow_proj_matrix * pos;
|
||||
#ifdef VULKAN
|
||||
// Vulkan shadow projection: XY is [-1,1] → [0,1], Z is already [0,1]
|
||||
shadow_proj.xy = shadow_proj.xy * 0.5 + 0.5;
|
||||
#else
|
||||
// OpenGL: all components [-1,1] → [0,1]
|
||||
shadow_proj += 1.0;
|
||||
shadow_proj *= 0.5;
|
||||
#endif
|
||||
shadow_proj.w = shadow_proj.z;
|
||||
shadow_proj.z = float(i);
|
||||
return shadow_proj;
|
||||
}
|
||||
@@ -3,14 +3,28 @@
|
||||
|
||||
const float EMISSIVE_GAIN = 2.0;
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec4 fragImpactUV;
|
||||
layout(location = 1) in float fragNormOffset;
|
||||
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler2DArray shieldMap;
|
||||
#else
|
||||
in vec4 fragImpactUV;
|
||||
in float fragNormOffset;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2DArray shieldMap;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
mat4 shieldModelViewMatrix;
|
||||
mat4 shieldProjMatrix;
|
||||
|
||||
|
||||
@@ -1,17 +1,34 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec4 vertPosition;
|
||||
layout(location = 3) in vec3 vertNormal;
|
||||
|
||||
layout(location = 0) out vec4 fragImpactUV;
|
||||
layout(location = 1) out float fragNormOffset;
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in vec3 vertNormal;
|
||||
|
||||
out vec4 fragImpactUV;
|
||||
out float fragNormOffset;
|
||||
#endif
|
||||
|
||||
|
||||
layout (std140) uniform matrixData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 1, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform matrixData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
};
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
mat4 shieldModelViewMatrix;
|
||||
mat4 shieldProjMatrix;
|
||||
|
||||
@@ -26,7 +43,6 @@ layout (std140) uniform genericData {
|
||||
void main()
|
||||
{
|
||||
gl_Position = projMatrix * modelViewMatrix * vertPosition;
|
||||
//vec3 normal = normalize(mat3(modelViewMatrix) * vertNormal);
|
||||
fragNormOffset = dot(hitNormal, vertNormal);
|
||||
fragImpactUV = shieldProjMatrix * shieldModelViewMatrix * vertPosition;
|
||||
fragImpactUV += 1.0f;
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#else
|
||||
layout (std140) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define SMAA_RT_METRICS vec4(1.0 / smaa_rt_metrics, smaa_rt_metrics)
|
||||
|
||||
@@ -10,6 +16,19 @@ layout (std140) uniform genericData {
|
||||
|
||||
#include "SMAA.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 1) in vec2 fragPixcoord;
|
||||
layout(location = 2) in vec4 fragOffset[3];
|
||||
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
|
||||
// [0]=edgesTex, [1]=areaTex, [2]=searchTex
|
||||
layout(set = 1, binding = 1) uniform sampler2D smaaTex[3];
|
||||
#define edgesTex smaaTex[0]
|
||||
#define areaTex smaaTex[1]
|
||||
#define searchTex smaaTex[2]
|
||||
#else
|
||||
in vec2 fragTexCoord;
|
||||
in vec2 fragPixcoord;
|
||||
in vec4 fragOffset[3];
|
||||
@@ -19,6 +38,7 @@ out vec4 fragOut0;
|
||||
uniform sampler2D edgesTex;
|
||||
uniform sampler2D areaTex;
|
||||
uniform sampler2D searchTex;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
fragOut0 = SMAABlendingWeightCalculationPS(fragTexCoord, fragPixcoord, fragOffset, edgesTex, areaTex, searchTex, vec4(0.0));
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#else
|
||||
layout (std140) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define SMAA_RT_METRICS vec4(1.0 / smaa_rt_metrics, smaa_rt_metrics)
|
||||
|
||||
@@ -10,6 +16,18 @@ layout (std140) uniform genericData {
|
||||
|
||||
#include "SMAA.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) out vec2 fragTexCoord;
|
||||
layout(location = 1) out vec2 fragPixcoord;
|
||||
layout(location = 2) out vec4 fragOffset[3];
|
||||
|
||||
void main() {
|
||||
vec2 uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
fragTexCoord = uv;
|
||||
gl_Position = vec4(uv * 2.0 - 1.0, 0.0, 1.0);
|
||||
SMAABlendingWeightCalculationVS(uv, fragPixcoord, fragOffset);
|
||||
}
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in vec2 vertTexCoord;
|
||||
|
||||
@@ -22,3 +40,4 @@ void main() {
|
||||
fragTexCoord = vertTexCoord;
|
||||
SMAABlendingWeightCalculationVS(vertTexCoord, fragPixcoord, fragOffset);
|
||||
}
|
||||
#endif
|
||||
@@ -1,7 +1,13 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#else
|
||||
layout (std140) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define SMAA_RT_METRICS vec4(1.0 / smaa_rt_metrics, smaa_rt_metrics)
|
||||
|
||||
@@ -10,12 +16,21 @@ layout (std140) uniform genericData {
|
||||
|
||||
#include "SMAA.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 1) in vec4 fragOffset[3];
|
||||
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler2D colorTex;
|
||||
#else
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragOffset[3];
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D colorTex;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
fragOut0 = vec4(SMAALumaEdgeDetectionPS(fragTexCoord, fragOffset, colorTex), 0.0, 1.0);
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#else
|
||||
layout (std140) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define SMAA_RT_METRICS vec4(1.0 / smaa_rt_metrics, smaa_rt_metrics)
|
||||
|
||||
@@ -10,6 +16,17 @@ layout (std140) uniform genericData {
|
||||
|
||||
#include "SMAA.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) out vec2 fragTexCoord;
|
||||
layout(location = 1) out vec4 fragOffset[3];
|
||||
|
||||
void main() {
|
||||
vec2 uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
fragTexCoord = uv;
|
||||
gl_Position = vec4(uv * 2.0 - 1.0, 0.0, 1.0);
|
||||
SMAAEdgeDetectionVS(uv, fragOffset);
|
||||
}
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in vec2 vertTexCoord;
|
||||
|
||||
@@ -21,3 +38,4 @@ void main() {
|
||||
fragTexCoord = vertTexCoord;
|
||||
SMAAEdgeDetectionVS(vertTexCoord, fragOffset);
|
||||
}
|
||||
#endif
|
||||
@@ -1,7 +1,13 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#else
|
||||
layout (std140) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define SMAA_RT_METRICS vec4(1.0 / smaa_rt_metrics, smaa_rt_metrics)
|
||||
|
||||
@@ -10,6 +16,17 @@ layout (std140) uniform genericData {
|
||||
|
||||
#include "SMAA.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 1) in vec4 fragOffset;
|
||||
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
|
||||
// [0]=colorTex, [1]=blendTex
|
||||
layout(set = 1, binding = 1) uniform sampler2D smaaTex[2];
|
||||
#define colorTex smaaTex[0]
|
||||
#define blendTex smaaTex[1]
|
||||
#else
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragOffset;
|
||||
|
||||
@@ -17,6 +34,7 @@ out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D colorTex;
|
||||
uniform sampler2D blendTex;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
fragOut0 = SMAANeighborhoodBlendingPS(fragTexCoord, fragOffset, colorTex, blendTex);
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 0) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#else
|
||||
layout (std140) uniform genericData {
|
||||
vec2 smaa_rt_metrics;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define SMAA_RT_METRICS vec4(1.0 / smaa_rt_metrics, smaa_rt_metrics)
|
||||
|
||||
@@ -10,6 +16,17 @@ layout (std140) uniform genericData {
|
||||
|
||||
#include "SMAA.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) out vec2 fragTexCoord;
|
||||
layout(location = 1) out vec4 fragOffset;
|
||||
|
||||
void main() {
|
||||
vec2 uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
fragTexCoord = uv;
|
||||
gl_Position = vec4(uv * 2.0 - 1.0, 0.0, 1.0);
|
||||
SMAANeighborhoodBlendingVS(uv, fragOffset);
|
||||
}
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in vec2 vertTexCoord;
|
||||
|
||||
@@ -21,3 +38,4 @@ void main() {
|
||||
fragTexCoord = vertTexCoord;
|
||||
SMAANeighborhoodBlendingVS(vertTexCoord, fragOffset);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(set = 1, binding = 1) uniform sampler2D tex;
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2D tex;
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
fragOut0 = texture(tex, fragTexCoord.xy);
|
||||
}
|
||||
@@ -1,11 +1,22 @@
|
||||
|
||||
#include "gamma.sdr"
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(set = 1, binding = 1) uniform sampler2D tex;
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2D tex;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 0, std140)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
float exposure;
|
||||
int tonemapper;
|
||||
float x0; //from here on these are for the PPC tonemappers
|
||||
@@ -19,6 +30,9 @@ layout (std140) uniform genericData {
|
||||
float sh_lnA;
|
||||
float sh_offsetX;
|
||||
float sh_offsetY;
|
||||
|
||||
float hdr_paperwhite_nits;
|
||||
float hdr_peak_nits;
|
||||
};
|
||||
//Tonemapping options, aside from the previous standard UC2, pulled from wookiejedi and qazwsxal's
|
||||
//work on testing them for FSO, which itself was based on these references:
|
||||
@@ -110,6 +124,20 @@ vec3 linearToneMapping(vec3 hdr_color)
|
||||
return hdr_color;
|
||||
}
|
||||
|
||||
// Display-referred, paper-white-relative. Unlike every other tonemapper here,
|
||||
// this one does not compress to [0,1] -- it keeps linear values with
|
||||
// head-room above paper white (up to peak_nits/paperwhite_nits), stored in
|
||||
// the shared extended-sRGB encoding that the HDR10 output-encode pass
|
||||
// (gamma-correct-f.sdr's HDR10_OUTPUT variant) later expects as its input.
|
||||
// Only ever selected via TonemapperAlgorithm::HdrScene, which
|
||||
// current_tonemapper() forces exclusively whenever HDR10 output is active.
|
||||
vec3 hdrSceneToneMapping(vec3 hdr_color)
|
||||
{
|
||||
float headroom = max(hdr_peak_nits / max(hdr_paperwhite_nits, 1.0), 1.0);
|
||||
hdr_color = min(hdr_color, vec3(headroom));
|
||||
return hdr_color;
|
||||
}
|
||||
|
||||
float toe( float x ) {
|
||||
return exp(toe_lnA + toe_B * log(x));
|
||||
}
|
||||
@@ -175,6 +203,7 @@ vec3 PPC( vec3 color ) {
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture(tex, fragTexCoord.xy);
|
||||
|
||||
color *= exposure;
|
||||
|
||||
switch(tonemapper){
|
||||
@@ -205,6 +234,9 @@ void main()
|
||||
case 8:
|
||||
color.rgb = PPC_RGB(color.rgb);
|
||||
break;
|
||||
case 9:
|
||||
color.rgb = hdrSceneToneMapping(color.rgb);
|
||||
break;
|
||||
|
||||
}
|
||||
#ifdef LINEAR_OUT
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec4 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler2DArray textures[16];
|
||||
#define ytex textures[0]
|
||||
#define utex textures[1]
|
||||
#define vtex textures[2]
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
out vec4 fragOut0;
|
||||
uniform sampler2DArray ytex;
|
||||
uniform sampler2DArray utex;
|
||||
uniform sampler2DArray vtex;
|
||||
layout (std140) uniform movieData {
|
||||
#endif
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 4)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform movieData {
|
||||
float alpha;
|
||||
float pad[3];
|
||||
};
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec4 vertPosition;
|
||||
layout(location = 2) in vec4 vertTexCoord;
|
||||
layout(location = 0) out vec4 fragTexCoord;
|
||||
#else
|
||||
in vec4 vertPosition;
|
||||
in vec4 vertTexCoord;
|
||||
out vec4 fragTexCoord;
|
||||
#endif
|
||||
|
||||
layout (std140) uniform matrixData {
|
||||
#ifdef VULKAN
|
||||
layout(std140, set = 2, binding = 1)
|
||||
#else
|
||||
layout(std140)
|
||||
#endif
|
||||
uniform matrixData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
};
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
|
||||
#ifdef VULKAN
|
||||
layout(location = 0) in vec2 fragTexCoord;
|
||||
layout(location = 0) out vec4 fragOut0;
|
||||
layout(set = 1, binding = 1) uniform sampler2D tex2D[16];
|
||||
#define composite tex2D[0]
|
||||
#define emissive tex2D[1]
|
||||
layout(set = 1, binding = 4) uniform sampler2D depth_tex;
|
||||
layout(set = 1, binding = 5) uniform sampler3D volume_tex;
|
||||
layout(set = 1, binding = 6) uniform sampler3D noise_volume_tex;
|
||||
#else
|
||||
in vec4 fragTexCoord;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
layout (binding = 0) uniform sampler2D composite;
|
||||
layout (binding = 1) uniform sampler2D emissive;
|
||||
layout (binding = 2) uniform sampler2D depth;
|
||||
layout (binding = 2) uniform sampler2D depth_tex;
|
||||
layout (binding = 3) uniform sampler3D volume_tex;
|
||||
#ifdef NOISE
|
||||
layout (binding = 4) uniform sampler3D noise_volume_tex;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
layout (std140) uniform genericData {
|
||||
#ifdef VULKAN
|
||||
layout(set = 2, binding = 0, std140)
|
||||
#else
|
||||
layout (std140)
|
||||
#endif
|
||||
uniform genericData {
|
||||
mat4 p_inv;
|
||||
mat4 v_inv;
|
||||
vec3 camera;
|
||||
@@ -56,7 +70,13 @@ part of the volumetrics is adapted from Andrew Schneider's 2015 SIGGRAPH talk "T
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef VULKAN
|
||||
// Vulkan's clip space has an inverted Y relative to OpenGL, so flip the
|
||||
// reconstructed NDC Y when building the eye-space ray direction.
|
||||
vec4 eyeDirection = p_inv * vec4(fragTexCoord.x * 2.0 - 1.0, -fragTexCoord.y * 2.0 + 1.0, -1, 1);
|
||||
#else
|
||||
vec4 eyeDirection = p_inv * vec4(fragTexCoord.xy * 2.0 - 1.0, -1, 1);
|
||||
#endif
|
||||
eyeDirection.w = 0;
|
||||
vec3 rayDirection = normalize((v_inv * eyeDirection).xyz);
|
||||
|
||||
@@ -73,12 +93,19 @@ void main()
|
||||
|
||||
vec2 fragcoordAngle = (fragTexCoord.xy - 0.5) * fov;
|
||||
fragcoordAngle.x *= aspect;
|
||||
float depth = (2.0 * zNear * zFar / (zFar + zNear - (2 * texture(depth, fragTexCoord.xy).x - 1) * (zFar - zNear))) * sqrt(1.0 + tan(fragcoordAngle.x) * tan(fragcoordAngle.x) + tan(fragcoordAngle.y) * tan(fragcoordAngle.y));
|
||||
float rawDepth = texture(depth_tex, fragTexCoord.xy).x;
|
||||
#ifdef VULKAN
|
||||
// Vulkan depth range is [0,1]
|
||||
float fragDepth = (zNear * zFar / (zFar - rawDepth * (zFar - zNear))) * sqrt(1.0 + tan(fragcoordAngle.x) * tan(fragcoordAngle.x) + tan(fragcoordAngle.y) * tan(fragcoordAngle.y));
|
||||
#else
|
||||
// OpenGL depth range is [-1,1]
|
||||
float fragDepth = (2.0 * zNear * zFar / (zFar + zNear - (2.0 * rawDepth - 1.0) * (zFar - zNear))) * sqrt(1.0 + tan(fragcoordAngle.x) * tan(fragcoordAngle.x) + tan(fragcoordAngle.y) * tan(fragcoordAngle.y));
|
||||
#endif
|
||||
|
||||
//The t at which the ray enters the nebula cube
|
||||
float maxtMin = max(0,max(tMin.x, max(tMin.y, tMin.z)));
|
||||
//The t at which the ray leaves the nebula cube
|
||||
float mintMax = min(depth, min(tMax.x, min(tMax.y, tMax.z)));
|
||||
float mintMax = min(fragDepth, min(tMax.x, min(tMax.y, tMax.z)));
|
||||
|
||||
//The cumulative one minus alpha value of the nebula. Corresponds to the multiplier of the current step when additively drawing to a fragment for which the steps closer to the camera are already drawn.
|
||||
float cumOMAlpha = 1;
|
||||
@@ -151,7 +178,7 @@ void main()
|
||||
//Emissive
|
||||
cumnebdist += stepcolor_alpha * stepsize_current;
|
||||
vec3 emissive_lod = textureLod(emissive, fragTexCoord.xy, clamp(cumnebdist * emissiveSpreadFactor, 0, float(textureQueryLevels(emissive) - 1))).rgb;
|
||||
vec3 stepcolor_emissive = clamp(emissive_lod.rgb * pow(alphalim, 1.0 / (opacitydistance / ((depth - stept) * emissiveFalloff + 0.01))) * emissiveIntensity, 0, 1);
|
||||
vec3 stepcolor_emissive = clamp(emissive_lod.rgb * pow(alphalim, 1.0 / (opacitydistance / ((fragDepth - stept) * emissiveFalloff + 0.01))) * emissiveIntensity, 0, 1);
|
||||
|
||||
//Step finish
|
||||
vec3 stepcolor = clamp(stepcolor_diffuse + stepcolor_emissive, 0, 1);
|
||||
|
||||
@@ -23,13 +23,23 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
bool LoadExternal( const char* externlib )
|
||||
bool LoadExternal( const char* externlib, const char* basePath = nullptr )
|
||||
{
|
||||
if ( !externlib )
|
||||
return FALSE;
|
||||
|
||||
m_library = SDL_LoadObject(externlib);
|
||||
|
||||
// check full path as a fallback for our own libraries
|
||||
// NOTE: basePath is assumed to have a trailing slash!
|
||||
if ( !m_library && basePath )
|
||||
{
|
||||
SCP_string fullpath = basePath;
|
||||
fullpath += externlib;
|
||||
|
||||
m_library = SDL_LoadObject(fullpath.c_str());
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (m_library == NULL)
|
||||
{
|
||||
@@ -113,4 +123,4 @@ typedef int (SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version*);
|
||||
v->major = Major; v->minor = Minor; v->patch = Patch;\
|
||||
return 0; }
|
||||
|
||||
#endif /* EXTERNALCODE_H_INCLUDED_ */
|
||||
#endif /* EXTERNALCODE_H_INCLUDED_ */
|
||||
@@ -597,6 +597,11 @@ inline void* memset_if_trivial_else_error(ImDrawListSplitter* memset_data, int c
|
||||
return ptr_memcpy(memcpy_dest, memcpy_src, count);
|
||||
}
|
||||
|
||||
inline void *memcpy_if_trivial_else_error(void *memcpy_dest, const void *memcpy_src, size_t count)
|
||||
{
|
||||
return ptr_memcpy(memcpy_dest, memcpy_src, count);
|
||||
}
|
||||
|
||||
// MEMMOVE!
|
||||
const auto ptr_memmove = std::memmove;
|
||||
#define memmove memmove_if_trivial_else_error
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#ifdef NO_RESTRICT_USE
|
||||
# define RESTRICT
|
||||
#else
|
||||
# define RESTRICT restrict
|
||||
# define RESTRICT __restrict
|
||||
#endif
|
||||
|
||||
#define ASSUME(x)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#ifdef NO_RESTRICT_USE
|
||||
# define RESTRICT
|
||||
#else
|
||||
# define RESTRICT restrict
|
||||
# define RESTRICT __restrict
|
||||
#endif
|
||||
|
||||
#define ASSUME(x)
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#ifdef NO_RESTRICT_USE
|
||||
# define RESTRICT
|
||||
#else
|
||||
# define RESTRICT restrict
|
||||
# define RESTRICT __restrict__
|
||||
#endif
|
||||
|
||||
#define ASSUME(x)
|
||||
|
||||
@@ -201,15 +201,18 @@ SCP_string get_version_string()
|
||||
|
||||
// Lets get some more info in here
|
||||
switch (gr_screen.mode) {
|
||||
case GR_OPENGL:
|
||||
case GraphicsAPI::OpenGL:
|
||||
str += " OpenGL";
|
||||
#ifdef USE_OPENGL_ES
|
||||
str += " ES";
|
||||
#endif
|
||||
break;
|
||||
case GR_VULKAN:
|
||||
case GraphicsAPI::Vulkan:
|
||||
str += " Vulkan";
|
||||
break;
|
||||
default:
|
||||
str += " Unknown???";
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
|
||||
@@ -2,7 +2,24 @@
|
||||
|
||||
#include "globalincs/vmallocator.h"
|
||||
|
||||
std::locale SCP_default_locale("");
|
||||
// std::locale("") pulls in the process's environment locale categories (LC_CTYPE,
|
||||
// LC_MONETARY, LC_PAPER, etc.), any one of which can name a locale that isn't actually
|
||||
// installed on the host (e.g. mismatched regional-format overrides). That throws
|
||||
// std::runtime_error, and since this runs during static initialization -- before
|
||||
// main(), before any of our own exception handling exists -- an uncaught throw here
|
||||
// aborts the whole process before the game even starts. SCP_default_locale is only
|
||||
// ever used for plain ASCII case-folding (SCP_toupper/tolower/isdigit), so falling
|
||||
// back to the classic "C" locale is a safe, silent degradation.
|
||||
static std::locale make_scp_default_locale()
|
||||
{
|
||||
try {
|
||||
return std::locale("");
|
||||
} catch (const std::runtime_error&) {
|
||||
return std::locale::classic();
|
||||
}
|
||||
}
|
||||
|
||||
std::locale SCP_default_locale = make_scp_default_locale();
|
||||
|
||||
void SCP_tolower(SCP_string &str)
|
||||
{
|
||||
|
||||
+141
-48
@@ -80,9 +80,11 @@ gr_capability_def gr_capabilities[] = {
|
||||
GR_CAPABILITY_ENTRY(SEPARATE_BLEND_FUNCTIONS),
|
||||
GR_CAPABILITY_ENTRY(PERSISTENT_BUFFER_MAPPING),
|
||||
gr_capability_def {gr_capability::CAPABILITY_BPTC, "BPTC Texture Compression"}, //This one had a different parse string already!
|
||||
gr_capability_def {gr_capability::CAPABILITY_S3TC, "S3TC Texture Compression"},
|
||||
GR_CAPABILITY_ENTRY(LARGE_SHADER),
|
||||
GR_CAPABILITY_ENTRY(INSTANCED_RENDERING),
|
||||
GR_CAPABILITY_ENTRY(FAST_SHADOWS),
|
||||
GR_CAPABILITY_ENTRY(RAYTRACED_SHADOWS),
|
||||
};
|
||||
|
||||
const size_t gr_capabilities_num = sizeof(gr_capabilities) / sizeof(gr_capabilities[0]);
|
||||
@@ -753,6 +755,75 @@ void removeVSyncOption()
|
||||
options::OptionsManager::instance()->removeOption(VSyncOption);
|
||||
}
|
||||
|
||||
bool Gr_enable_hdr = false;
|
||||
bool Gr_hdr_output_active = false;
|
||||
|
||||
static void parse_hdr_func()
|
||||
{
|
||||
bool value;
|
||||
stuff_boolean(&value);
|
||||
|
||||
Gr_enable_hdr = value;
|
||||
}
|
||||
|
||||
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
|
||||
static auto HDROption __UNUSED = options::OptionBuilder<bool>("Graphics.HDR",
|
||||
std::pair<const char*, int>{"HDR Output", -1},
|
||||
std::pair<const char*, int>{"Enables HDR10 (PQ / BT.2020) output on supported displays. Vulkan renderer only. Requires a restart to take effect.", -1})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_func([]() { return Gr_enable_hdr; })
|
||||
.bind_to_once(&Gr_enable_hdr)
|
||||
.importance(68)
|
||||
.parser(parse_hdr_func)
|
||||
.finish();
|
||||
|
||||
float Gr_hdr_paperwhite_nits = 200.0f;
|
||||
|
||||
static void parse_hdr_paperwhite_func()
|
||||
{
|
||||
float value;
|
||||
stuff_float(&value);
|
||||
|
||||
Gr_hdr_paperwhite_nits = value;
|
||||
}
|
||||
|
||||
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
|
||||
static auto HDRPaperWhiteOption __UNUSED = options::OptionBuilder<float>("Graphics.HDRPaperWhite",
|
||||
std::pair<const char*, int>{"HDR Paper White", -1},
|
||||
std::pair<const char*, int>{"Reference white luminance in nits for UI and SDR-referenced content when HDR output is active.", -1})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_func([]() { return Gr_hdr_paperwhite_nits; })
|
||||
.range(80.0f, 480.0f)
|
||||
.bind_to(&Gr_hdr_paperwhite_nits)
|
||||
.importance(67)
|
||||
.parser(parse_hdr_paperwhite_func)
|
||||
.finish();
|
||||
|
||||
float Gr_hdr_peak_nits = 1000.0f;
|
||||
|
||||
static void parse_hdr_peak_func()
|
||||
{
|
||||
float value;
|
||||
stuff_float(&value);
|
||||
|
||||
Gr_hdr_peak_nits = value;
|
||||
}
|
||||
|
||||
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
|
||||
static auto HDRPeakOption __UNUSED = options::OptionBuilder<float>("Graphics.HDRPeakLuminance",
|
||||
std::pair<const char*, int>{"HDR Peak Luminance", -1},
|
||||
std::pair<const char*, int>{"Display peak luminance in nits used for HDR tone curve clamping and HDR10 metadata.", -1})
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_func([]() { return Gr_hdr_peak_nits; })
|
||||
.range(400.0f, 4000.0f)
|
||||
.bind_to(&Gr_hdr_peak_nits)
|
||||
.importance(66)
|
||||
.parser(parse_hdr_peak_func)
|
||||
.finish();
|
||||
|
||||
static std::unique_ptr<graphics::util::UniformBufferManager> UniformBufferManager;
|
||||
|
||||
// Forward definitions
|
||||
@@ -1316,28 +1387,30 @@ void gr_close()
|
||||
|
||||
graphics::paths::PathRenderer::shutdown();
|
||||
|
||||
// Free bitmaps before destroying the graphics backend, since
|
||||
// gf_bm_free_data needs the backend (texture manager, GL context, etc.)
|
||||
bm_close();
|
||||
|
||||
switch (gr_screen.mode) {
|
||||
case GR_OPENGL:
|
||||
case GraphicsAPI::OpenGL:
|
||||
#ifdef WITH_OPENGL
|
||||
gr_opengl_cleanup(true);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case GR_VULKAN:
|
||||
case GraphicsAPI::Vulkan:
|
||||
#ifdef WITH_VULKAN
|
||||
graphics::vulkan::cleanup();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case GR_STUB:
|
||||
case GraphicsAPI::Stub:
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
Int3(); // Invalid graphics mode
|
||||
}
|
||||
|
||||
bm_close();
|
||||
|
||||
Gr_inited = 0;
|
||||
}
|
||||
|
||||
@@ -1527,33 +1600,33 @@ static void init_colors()
|
||||
Gr_ta_alpha.scale = 17;
|
||||
}
|
||||
|
||||
static void gr_init_function_pointers(int mode) {
|
||||
static void gr_init_function_pointers(GraphicsAPI mode) {
|
||||
gr_screen = {};
|
||||
|
||||
switch (mode) {
|
||||
case GR_OPENGL:
|
||||
case GraphicsAPI::OpenGL:
|
||||
#ifdef WITH_OPENGL
|
||||
gr_opengl_init_function_pointers();
|
||||
#else
|
||||
Error(LOCATION, "OpenGL renderer was requested but that was not compiled into this build.");
|
||||
#endif
|
||||
break;
|
||||
case GR_VULKAN:
|
||||
case GraphicsAPI::Vulkan:
|
||||
#ifdef WITH_VULKAN
|
||||
graphics::vulkan::initialize_function_pointers();
|
||||
#else
|
||||
Error(LOCATION, "Vulkan renderer was requested but that was not compiled into this build.");
|
||||
#endif
|
||||
break;
|
||||
case GR_STUB:
|
||||
case GraphicsAPI::Stub:
|
||||
gr_stub_init_function_pointers();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Invalid graphics mode %d requested", mode); // Invalid graphics mode
|
||||
UNREACHABLE("Invalid graphics mode requested"); // Invalid graphics mode
|
||||
}
|
||||
}
|
||||
|
||||
static bool gr_init_sub(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int mode, int width, int height,
|
||||
static bool gr_init_sub(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, GraphicsAPI mode, int width, int height,
|
||||
int depth, float center_aspect_ratio)
|
||||
{
|
||||
int res = GR_1024;
|
||||
@@ -1587,7 +1660,6 @@ static bool gr_init_sub(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, i
|
||||
if (Fred_running) {
|
||||
gr_screen.custom_size = false;
|
||||
res = GR_640;
|
||||
mode = GR_OPENGL;
|
||||
}
|
||||
|
||||
Save_custom_screen_size = gr_screen.custom_size;
|
||||
@@ -1655,7 +1727,7 @@ static bool gr_init_sub(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, i
|
||||
init_colors();
|
||||
|
||||
switch (mode) {
|
||||
case GR_OPENGL:
|
||||
case GraphicsAPI::OpenGL:
|
||||
#ifdef WITH_OPENGL
|
||||
rc = gr_opengl_init(std::move(graphicsOps));
|
||||
#else
|
||||
@@ -1663,7 +1735,7 @@ static bool gr_init_sub(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, i
|
||||
rc = false;
|
||||
#endif
|
||||
break;
|
||||
case GR_VULKAN:
|
||||
case GraphicsAPI::Vulkan:
|
||||
#ifdef WITH_VULKAN
|
||||
rc = graphics::vulkan::initialize(std::move(graphicsOps));
|
||||
#else
|
||||
@@ -1671,7 +1743,7 @@ static bool gr_init_sub(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, i
|
||||
rc = false;
|
||||
#endif
|
||||
break;
|
||||
case GR_STUB:
|
||||
case GraphicsAPI::Stub:
|
||||
SCP_UNUSED(graphicsOps);
|
||||
rc = gr_stub_init();
|
||||
break;
|
||||
@@ -1727,21 +1799,22 @@ SCP_string gr_capability_to_human_readable_string(gr_capability capability)
|
||||
return "Invalid Capability";
|
||||
}
|
||||
|
||||
bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode, int d_width, int d_height, int d_depth)
|
||||
bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, GraphicsAPI d_mode, int d_width, int d_height, int d_depth)
|
||||
{
|
||||
int width = 1024, height = 768, depth = 32, mode = GR_OPENGL;
|
||||
int width = 1024, height = 768, depth = 32;
|
||||
GraphicsAPI mode = GraphicsAPI::OpenGL;
|
||||
float center_aspect_ratio = -1.0f;
|
||||
const char *ptr = NULL;
|
||||
// If already inited, shutdown the previous graphics
|
||||
if (Gr_inited) {
|
||||
switch (gr_screen.mode) {
|
||||
case GR_OPENGL:
|
||||
case GraphicsAPI::OpenGL:
|
||||
#ifdef WITH_OPENGL
|
||||
gr_opengl_cleanup(false);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case GR_STUB:
|
||||
case GraphicsAPI::Stub:
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1751,7 +1824,7 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
|
||||
if (Using_in_game_options) {
|
||||
if (Cmdline_enable_vr) {
|
||||
// in VR mode, so set resolution using VR values
|
||||
// in VR mode, so set resolution using VR values
|
||||
// and hide/disable the default resolution option
|
||||
auto res = ResolutionVROption->getValue();
|
||||
width = res.width;
|
||||
@@ -1765,6 +1838,7 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
height = res.height;
|
||||
removeResolutionVROption();
|
||||
}
|
||||
//TODO set d_mode from Ingame Options if available here
|
||||
} else if ( !Is_standalone ) {
|
||||
// We cannot continue without this, quit, but try to help the user out first
|
||||
ptr = os_config_read_string(nullptr, NOX("VideocardFs2open"), nullptr);
|
||||
@@ -1824,26 +1898,31 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
SCP_string videoApi(ptr, ptr + 4);
|
||||
|
||||
if (videoApi == "OGL ") {
|
||||
d_mode = GR_OPENGL; // GR_OPENGL;
|
||||
d_mode = GraphicsAPI::OpenGL; // GR_OPENGL;
|
||||
} else if (videoApi == "VK ") {
|
||||
d_mode = GR_VULKAN;
|
||||
d_mode = GraphicsAPI::Vulkan;
|
||||
} else {
|
||||
ReleaseWarning(LOCATION, "Unknown video API '%s'", videoApi.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (Cmdline_res != nullptr) {
|
||||
int tmp_width = 0;
|
||||
int tmp_height = 0;
|
||||
|
||||
if ( sscanf(Cmdline_res, "%dx%d", &tmp_width, &tmp_height) == 2 ) {
|
||||
width = tmp_width;
|
||||
height = tmp_height;
|
||||
}
|
||||
}
|
||||
|
||||
Gr_enable_soft_particles = Cmdline_softparticles != 0;
|
||||
}
|
||||
|
||||
//Commandline ALWAYS wins for Graphics API and resolution
|
||||
if (Cmdline_graphics_api != GraphicsAPI::Default)
|
||||
d_mode = Cmdline_graphics_api;
|
||||
|
||||
if (Cmdline_res != nullptr) {
|
||||
int tmp_width = 0;
|
||||
int tmp_height = 0;
|
||||
|
||||
if ( sscanf(Cmdline_res, "%dx%d", &tmp_width, &tmp_height) == 2 ) {
|
||||
width = tmp_width;
|
||||
height = tmp_height;
|
||||
}
|
||||
}
|
||||
|
||||
if (Cmdline_center_res != NULL) {
|
||||
int tmp_center_width = 0;
|
||||
int tmp_center_height = 0;
|
||||
@@ -1871,9 +1950,9 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
Cmdline_window_res.emplace(static_cast<uint16_t>(width), static_cast<uint16_t>(height));
|
||||
}
|
||||
|
||||
if (d_mode == GR_DEFAULT) {
|
||||
// OpenGL should be default
|
||||
mode = GR_OPENGL;
|
||||
if (d_mode == GraphicsAPI::Default) {
|
||||
// OpenGL should be default.
|
||||
mode = GraphicsAPI::OpenGL;
|
||||
} else {
|
||||
mode = d_mode;
|
||||
}
|
||||
@@ -1890,13 +1969,21 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
|
||||
// if we are in standalone mode then just use special defaults
|
||||
if (Is_standalone) {
|
||||
mode = GR_STUB;
|
||||
mode = GraphicsAPI::Stub;
|
||||
width = 640;
|
||||
height = 480;
|
||||
depth = 16;
|
||||
center_aspect_ratio = -1.0f;
|
||||
}
|
||||
|
||||
// FRED doesn't support Vulkan yet (see qtfred/README.md for what's needed to change that), so it always
|
||||
// falls back to OpenGL regardless of what was requested. This must happen before gr_init_function_pointers()
|
||||
// below, since that's what binds gr_screen's gf_* dispatch table to the chosen API; doing the override any
|
||||
// later (e.g. in gr_init_sub()) would leave the dispatch table pointing at the wrong backend.
|
||||
if (Fred_running) {
|
||||
mode = GraphicsAPI::OpenGL;
|
||||
}
|
||||
|
||||
gr_init_function_pointers(mode);
|
||||
|
||||
if (gr_get_resolution_class(width, height) != GR_640) {
|
||||
@@ -2182,7 +2269,7 @@ void gr_bitmap(int _x, int _y, int resize_mode, bool mirror, float scale_factor)
|
||||
float x, y, w, h;
|
||||
vertex verts[4];
|
||||
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2903,7 +2990,7 @@ void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float a
|
||||
|
||||
static void output_uniform_debug_data()
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2935,6 +3022,16 @@ void gr_flip(bool execute_scripting)
|
||||
|
||||
model_process_cached_ui_render_instances();
|
||||
|
||||
if (Cmdline_graphics_debug_output) {
|
||||
output_uniform_debug_data();
|
||||
}
|
||||
|
||||
// IMPORTANT: No rendering may happen after this point until gf_flip()/gr_setup_frame().
|
||||
// gr_reset_immediate_buffer() resets the write offset to 0, so any subsequent immediate
|
||||
// buffer write would overwrite vertex data that already-recorded draw commands reference.
|
||||
// In Vulkan (deferred submission), the GPU reads the final buffer state at submit time,
|
||||
// so overwrites here silently corrupt earlier draws. OpenGL's immediate execution hides
|
||||
// this, but it is still logically wrong for any deferred-submission backend.
|
||||
gr_reset_immediate_buffer();
|
||||
|
||||
// Do per frame operations on the matrix state
|
||||
@@ -2944,10 +3041,6 @@ void gr_flip(bool execute_scripting)
|
||||
|
||||
mouse_reset_deltas();
|
||||
|
||||
if (Cmdline_graphics_debug_output) {
|
||||
output_uniform_debug_data();
|
||||
}
|
||||
|
||||
// Use this opportunity for retiring the uniform buffers
|
||||
uniform_buffer_managers_retire_buffers();
|
||||
|
||||
@@ -2990,7 +3083,7 @@ void gr_print_timestamp(int x, int y, fix timestamp, int resize_mode)
|
||||
|
||||
void gr_uniform_buffer_managers_init()
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2999,7 +3092,7 @@ void gr_uniform_buffer_managers_init()
|
||||
|
||||
static void uniform_buffer_managers_deinit()
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3008,7 +3101,7 @@ static void uniform_buffer_managers_deinit()
|
||||
|
||||
static void uniform_buffer_managers_retire_buffers()
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3149,7 +3242,7 @@ size_t vertex_layout::hash() const {
|
||||
static std::unique_ptr<graphics::util::GPUMemoryHeap> gpu_heaps [static_cast<size_t>(GpuHeap::NUM_VALUES)];
|
||||
|
||||
static void gpu_heap_init() {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3192,7 +3285,7 @@ void gr_heap_deallocate(GpuHeap heap_type, size_t data_offset)
|
||||
|
||||
void gr_set_gamma(float gamma)
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+83
-12
@@ -41,6 +41,9 @@ extern float Min_draw_distance;
|
||||
extern float Max_draw_distance;
|
||||
extern int Gr_inited;
|
||||
|
||||
// # Software Re-added by Kazan --- THIS HAS TO STAY -- It is used by standalone!
|
||||
enum class GraphicsAPI : uint8_t { Default, Stub, OpenGL, Vulkan };
|
||||
|
||||
// z-buffering stuff
|
||||
extern int gr_zbuffering, gr_zbuffering_mode;
|
||||
extern int gr_global_zbuffering;
|
||||
@@ -72,6 +75,16 @@ extern bool Gr_post_processing_enabled;
|
||||
|
||||
extern bool Gr_enable_vsync;
|
||||
|
||||
// HDR10 (PQ/ST.2084 + BT.2020) output. Currently only honored by the Vulkan renderer.
|
||||
extern bool Gr_enable_hdr;
|
||||
// True once the renderer has actually negotiated an HDR10 swap chain (read-only,
|
||||
// set by the active renderer). Distinct from Gr_enable_hdr, which is the request.
|
||||
extern bool Gr_hdr_output_active;
|
||||
// Reference white luminance in nits (the brightness of SDR "paper white" / UI when HDR is active).
|
||||
extern float Gr_hdr_paperwhite_nits;
|
||||
// Display peak luminance in nits used for tone curve clamping and HDR10 metadata.
|
||||
extern float Gr_hdr_peak_nits;
|
||||
|
||||
extern bool Deferred_lighting;
|
||||
extern bool High_dynamic_range;
|
||||
|
||||
@@ -209,13 +222,14 @@ enum shader_type {
|
||||
SDR_TYPE_POST_PROCESS_SMAA_EDGE,
|
||||
SDR_TYPE_POST_PROCESS_SMAA_BLENDING_WEIGHT,
|
||||
SDR_TYPE_POST_PROCESS_SMAA_NEIGHBORHOOD_BLENDING,
|
||||
SDR_TYPE_POST_PROCESS_SMAA_RESOLVE,
|
||||
|
||||
SDR_TYPE_ENVMAP_SPHERE_WARP,
|
||||
|
||||
SDR_TYPE_IRRADIANCE_MAP_GEN,
|
||||
|
||||
SDR_TYPE_SHADOW_MAP_GEN,
|
||||
|
||||
|
||||
SDR_TYPE_GAMMA_BLIT,
|
||||
|
||||
NUM_SHADER_TYPES
|
||||
@@ -240,10 +254,16 @@ enum shader_type {
|
||||
#define SDR_FLAG_VOLUMETRICS_NOISE (1<<1)
|
||||
|
||||
#define SDR_FLAG_COPY_FROM_ARRAY (1 << 0)
|
||||
#define SDR_FLAG_COPY_CLAMP01 (1 << 1)
|
||||
|
||||
#define SDR_FLAG_TONEMAPPING_LINEAR_OUT (1 << 0)
|
||||
|
||||
#define SDR_FLAG_GAMMA_HDR10 (1 << 0)
|
||||
|
||||
#define SDR_FLAG_ENV_MAP (1 << 0)
|
||||
#define SDR_FLAG_DEFERRED_RT_SHADOWS (1 << 1)
|
||||
|
||||
#define SDR_FLAG_SHADOW_FALLBACK (1 << 0)
|
||||
|
||||
#define SDR_FLAG_SHADOW_FALLBACK (1 << 0)
|
||||
|
||||
@@ -270,7 +290,6 @@ struct vertex_format_data
|
||||
POSITION4,
|
||||
POSITION3,
|
||||
POSITION2,
|
||||
SCREEN_POS,
|
||||
COLOR3,
|
||||
COLOR4,
|
||||
COLOR4F,
|
||||
@@ -346,9 +365,12 @@ enum class gr_capability {
|
||||
CAPABILITY_SEPARATE_BLEND_FUNCTIONS,
|
||||
CAPABILITY_PERSISTENT_BUFFER_MAPPING,
|
||||
CAPABILITY_BPTC,
|
||||
CAPABILITY_S3TC,
|
||||
CAPABILITY_LARGE_SHADER,
|
||||
CAPABILITY_INSTANCED_RENDERING,
|
||||
CAPABILITY_FAST_SHADOWS,
|
||||
CAPABILITY_QUERIES_REUSABLE,
|
||||
CAPABILITY_RAYTRACED_SHADOWS
|
||||
};
|
||||
|
||||
struct gr_capability_def {
|
||||
@@ -680,7 +702,7 @@ typedef struct screen {
|
||||
int save_center_w = 0, save_center_h = 0; // Width and height of center monitor
|
||||
int save_center_offset_x = 0, save_center_offset_y = 0;
|
||||
int res = 0; // GR_640 or GR_1024
|
||||
int mode = 0; // What mode gr_init was called with.
|
||||
GraphicsAPI mode = GraphicsAPI::Default; // What mode gr_init was called with.
|
||||
float aspect = 0.0f, clip_aspect = 0.0f; // Aspect ratio = 0, aspect of clip_width/clip_height
|
||||
int rowsize = 0; // What you need to add to go to next row (includes bytes_per_pixel)
|
||||
int bits_per_pixel = 0; // How many bits per pixel it is. (7,8,15,16,24,32)
|
||||
@@ -798,9 +820,22 @@ typedef struct screen {
|
||||
|
||||
std::function<void(int)> gf_set_texture_addressing;
|
||||
|
||||
std::function<gr_buffer_handle(BufferType type, BufferUsageHint usage)> gf_create_buffer;
|
||||
std::function<gr_buffer_handle(BufferType type, BufferUsageHint usage, bool rt_capable)> gf_create_buffer;
|
||||
std::function<void(gr_buffer_handle handle)> gf_delete_buffer;
|
||||
|
||||
// Optional lifecycle hooks for backends that maintain auxiliary per-model GPU
|
||||
// state (e.g. Vulkan's raytraced-shadow BLAS cache). Default to no-ops so
|
||||
// backends that don't need them (OpenGL, stub) don't have to assign anything.
|
||||
std::function<void(int pm_id)> gf_model_loaded = [](int) {};
|
||||
std::function<void(int pm_id)> gf_model_unloaded = [](int) {};
|
||||
|
||||
// Rebuilds the raytraced-shadow top-level acceleration structure for the
|
||||
// current frame from the live shadow-casting object set. Called once per
|
||||
// frame from shadows_render_all(), alongside the cascaded shadow map pass --
|
||||
// the shading pass picks between the two per shadows_use_raytracing().
|
||||
// No-op default.
|
||||
std::function<void()> gf_build_shadow_tlas = []() {};
|
||||
|
||||
std::function<void(gr_buffer_handle handle, size_t size, const void* data)> gf_update_buffer_data;
|
||||
std::function<void(gr_buffer_handle handle, size_t offset, size_t size, const void* data)>
|
||||
gf_update_buffer_data_offset;
|
||||
@@ -948,6 +983,10 @@ typedef struct screen {
|
||||
|
||||
std::function<void(bool set_override)> gf_override_fog;
|
||||
|
||||
// ImGui backend integration
|
||||
std::function<void()> gf_imgui_new_frame;
|
||||
std::function<void()> gf_imgui_render_draw_data;
|
||||
|
||||
//OpenXR functions
|
||||
std::function<SCP_vector<const char*>()> gf_openxr_get_extensions;
|
||||
std::function<bool()> gf_openxr_test_capabilities;
|
||||
@@ -1000,11 +1039,7 @@ bool gr_lua_context_active();
|
||||
//--------------------------------------
|
||||
// Call this at application startup
|
||||
|
||||
// # Software Re-added by Kazan --- THIS HAS TO STAY -- It is used by standalone!
|
||||
#define GR_DEFAULT (-1) // set to use default settings
|
||||
#define GR_STUB (100)
|
||||
#define GR_OPENGL (104) // Use OpenGl hardware renderer
|
||||
#define GR_VULKAN (105) // Use Vulkan hardware renderer
|
||||
#define GR_DEFAULT (-1)
|
||||
|
||||
// resolution constants - always keep resolutions in ascending order and starting from 0
|
||||
#define GR_NUM_RESOLUTIONS 2
|
||||
@@ -1016,7 +1051,7 @@ bool gr_lua_context_active();
|
||||
|
||||
extern const char *Resolution_prefixes[GR_NUM_RESOLUTIONS];
|
||||
|
||||
extern bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode = GR_DEFAULT,
|
||||
extern bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, GraphicsAPI d_mode = GraphicsAPI::Default,
|
||||
int d_width = GR_DEFAULT, int d_height = GR_DEFAULT, int d_depth = GR_DEFAULT);
|
||||
|
||||
extern void gr_screen_resize(int width, int height);
|
||||
@@ -1152,12 +1187,45 @@ inline int gr_bm_set_render_target(int n, int face = -1)
|
||||
|
||||
#define gr_set_texture_addressing GR_CALL(gr_screen.gf_set_texture_addressing)
|
||||
|
||||
inline gr_buffer_handle gr_create_buffer(BufferType type, BufferUsageHint usage)
|
||||
/**
|
||||
* @brief Create a GPU buffer
|
||||
* @param type The buffer type (Vertex, Index, Uniform)
|
||||
* @param usage Usage hint for optimization
|
||||
* @param rt_capable If true (Vulkan only), the buffer is created with the extra
|
||||
* usage flags (VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT and
|
||||
* VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR)
|
||||
* needed to use it as acceleration structure geometry input. Ignored by
|
||||
* backends without raytraced shadow support.
|
||||
*/
|
||||
inline gr_buffer_handle gr_create_buffer(BufferType type, BufferUsageHint usage, bool rt_capable = false)
|
||||
{
|
||||
return gr_screen.gf_create_buffer(type, usage);
|
||||
return gr_screen.gf_create_buffer(type, usage, rt_capable);
|
||||
}
|
||||
|
||||
#define gr_delete_buffer GR_CALL(gr_screen.gf_delete_buffer)
|
||||
|
||||
/**
|
||||
* @brief Notify the graphics backend that a model finished loading (its GPU
|
||||
* vertex/index buffers are already uploaded at this point). No-op on backends
|
||||
* that don't need per-model GPU state.
|
||||
*/
|
||||
inline void gr_model_loaded(int pm_id)
|
||||
{
|
||||
gr_screen.gf_model_loaded(pm_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Notify the graphics backend that a model is about to be freed, so it
|
||||
* can release any auxiliary per-model GPU state before the model's own GPU
|
||||
* buffers are destroyed.
|
||||
*/
|
||||
inline void gr_model_unloaded(int pm_id)
|
||||
{
|
||||
gr_screen.gf_model_unloaded(pm_id);
|
||||
}
|
||||
|
||||
#define gr_build_shadow_tlas GR_CALL(gr_screen.gf_build_shadow_tlas)
|
||||
|
||||
#define gr_update_buffer_data GR_CALL(gr_screen.gf_update_buffer_data)
|
||||
#define gr_update_buffer_data_offset GR_CALL(gr_screen.gf_update_buffer_data_offset)
|
||||
inline void* gr_map_buffer(gr_buffer_handle handle)
|
||||
@@ -1210,6 +1278,9 @@ inline void gr_post_process_restore_zbuffer()
|
||||
|
||||
#define gr_override_fog GR_CALL(gr_screen.gf_override_fog)
|
||||
|
||||
#define gr_imgui_new_frame GR_CALL(gr_screen.gf_imgui_new_frame)
|
||||
#define gr_imgui_render_draw_data GR_CALL(gr_screen.gf_imgui_render_draw_data)
|
||||
|
||||
inline void gr_render_primitives(material* material_info,
|
||||
primitive_type prim_type,
|
||||
vertex_layout* layout,
|
||||
|
||||
@@ -28,7 +28,7 @@ uint gr_stub_lock()
|
||||
return 1;
|
||||
}
|
||||
|
||||
gr_buffer_handle gr_stub_create_buffer(BufferType, BufferUsageHint)
|
||||
gr_buffer_handle gr_stub_create_buffer(BufferType, BufferUsageHint, bool)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ static void pre_render_init_lights() {
|
||||
}
|
||||
|
||||
void gr_set_light(light* fs_light) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ void gr_set_light(light* fs_light) {
|
||||
}
|
||||
|
||||
void gr_set_center_alpha(int type) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ void gr_set_center_alpha(int type) {
|
||||
}
|
||||
|
||||
void gr_reset_lighting() {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ void gr_light_shutdown() {
|
||||
}
|
||||
|
||||
void gr_light_init() {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ void gr_light_init() {
|
||||
}
|
||||
|
||||
void gr_set_lighting() {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ void gr_set_lighting() {
|
||||
}
|
||||
|
||||
void gr_set_ambient_light(int red, int green, int blue) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ void gr_get_ambient_light(vec3d* light_vector) {
|
||||
}
|
||||
|
||||
void gr_lighting_fill_uniforms(void* data_out, size_t buffer_size) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "graphics/grinternal.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/material.h"
|
||||
#include "graphics/shadows.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "cmdline/cmdline.h"
|
||||
|
||||
@@ -742,6 +743,13 @@ uint model_material::get_shader_flags() const
|
||||
Shader_flags |= MODEL_SDR_FLAG_THICK_OUTLINES;
|
||||
}
|
||||
|
||||
// Must stay a genuine compile-time flag (like SHADOW_MAP/THICK_OUTLINES above),
|
||||
// not one gated only via the runtime `flags` uniform below -- see the comment
|
||||
// on MODEL_SDR_FLAG_RT_SHADOWS in model_shader_flags.h.
|
||||
if (is_shadow_receiving() && shadows_use_raytracing()) {
|
||||
Shader_flags |= MODEL_SDR_FLAG_RT_SHADOWS;
|
||||
}
|
||||
|
||||
if (!gr_is_capable(gr_capability::CAPABILITY_LARGE_SHADER)) {
|
||||
Shader_flags |= get_shader_runtime_flags();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "matrix.h"
|
||||
|
||||
#include "graphics/util/UniformBuffer.h"
|
||||
#include "cmdline/cmdline.h"
|
||||
|
||||
#include <graphics/util/uniform_structs.h>
|
||||
|
||||
@@ -56,9 +57,18 @@ static void create_perspective_projection_matrix(matrix4 *out, float left, float
|
||||
out->a1d[5] = 2.0f * near_dist / (top - bottom);
|
||||
out->a1d[8] = (right + left) / (right - left);
|
||||
out->a1d[9] = (top + bottom) / (top - bottom);
|
||||
out->a1d[10] = -(far_dist + near_dist) / (far_dist - near_dist);
|
||||
out->a1d[11] = -1.0f;
|
||||
out->a1d[14] = -2.0f * far_dist * near_dist / (far_dist - near_dist);
|
||||
|
||||
if (gr_screen.mode == GraphicsAPI::Vulkan) {
|
||||
// Vulkan NDC Z range is [0, 1] (OpenGL is [-1, 1])
|
||||
// Y-flip is handled by negative viewport height (VK_KHR_maintenance1)
|
||||
out->a1d[10] = -far_dist / (far_dist - near_dist);
|
||||
out->a1d[14] = -far_dist * near_dist / (far_dist - near_dist);
|
||||
} else {
|
||||
// OpenGL NDC Z range is [-1, 1]
|
||||
out->a1d[10] = -(far_dist + near_dist) / (far_dist - near_dist);
|
||||
out->a1d[14] = -2.0f * far_dist * near_dist / (far_dist - near_dist);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_orthographic_projection_matrix(matrix4* out, float left, float right, float bottom, float top, float near_dist, float far_dist)
|
||||
@@ -67,11 +77,20 @@ static void create_orthographic_projection_matrix(matrix4* out, float left, floa
|
||||
|
||||
out->a1d[0] = 2.0f / (right - left);
|
||||
out->a1d[5] = 2.0f / (top - bottom);
|
||||
out->a1d[10] = -2.0f / (far_dist - near_dist);
|
||||
out->a1d[12] = -(right + left) / (right - left);
|
||||
out->a1d[13] = -(top + bottom) / (top - bottom);
|
||||
out->a1d[14] = -(far_dist + near_dist) / (far_dist - near_dist);
|
||||
out->a1d[15] = 1.0f;
|
||||
|
||||
if (gr_screen.mode == GraphicsAPI::Vulkan) {
|
||||
// Vulkan NDC Z range is [0, 1] (OpenGL is [-1, 1])
|
||||
// Y-flip is handled by negative viewport height (VK_KHR_maintenance1)
|
||||
out->a1d[10] = -1.0f / (far_dist - near_dist);
|
||||
out->a1d[14] = -near_dist / (far_dist - near_dist);
|
||||
} else {
|
||||
// OpenGL NDC Z range is [-1, 1]
|
||||
out->a1d[10] = -2.0f / (far_dist - near_dist);
|
||||
out->a1d[14] = -(far_dist + near_dist) / (far_dist - near_dist);
|
||||
}
|
||||
}
|
||||
|
||||
void gr_start_instance_matrix(const vec3d *offset, const matrix *rotation)
|
||||
@@ -286,7 +305,11 @@ void gr_end_2d_matrix()
|
||||
Assert( htl_2d_matrix_depth == 1 );
|
||||
|
||||
// reset viewport to what it was originally set to by the proj matrix
|
||||
gr_set_viewport(gr_screen.offset_x, (gr_screen.max_h - gr_screen.offset_y - gr_screen.clip_height), gr_screen.clip_width, gr_screen.clip_height);
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
gr_set_viewport(gr_screen.offset_x, gr_screen.offset_y, gr_screen.clip_width, gr_screen.clip_height);
|
||||
} else {
|
||||
gr_set_viewport(gr_screen.offset_x, (gr_screen.max_h - gr_screen.offset_y - gr_screen.clip_height), gr_screen.clip_width, gr_screen.clip_height);
|
||||
}
|
||||
|
||||
gr_projection_matrix = gr_last_projection_matrix;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <vector>
|
||||
#include <glad/glad.h>
|
||||
#include <KHR/khrplatform.h>
|
||||
#include "graphics/util/pixel_swizzle.h"
|
||||
/*
|
||||
OpenGL ES 3.2 compatibility layer
|
||||
---------------------------------
|
||||
@@ -58,106 +59,6 @@
|
||||
#define glGetDebugMessageLogARB glGetDebugMessageLog // ES 3.2
|
||||
#define glDepthRange glDepthRangef // ES 3.0
|
||||
|
||||
/*
|
||||
Pixel Conversion for unsupported uncompressed formats
|
||||
*/
|
||||
|
||||
// BGRA 1_5_5_5_REV -> RGBA 5_5_5_1
|
||||
static inline void convert_BGRA1555_REV_to_RGBA5551(const uint16_t* __restrict src, uint16_t* __restrict dst, size_t npx)
|
||||
{
|
||||
for (size_t i = 0; i < npx; i++) {
|
||||
const uint16_t s = src[i];
|
||||
uint16_t a = (s >> 15) & 0x1;
|
||||
uint16_t r = (s >> 10) & 0x1F;
|
||||
uint16_t g = (s >> 5) & 0x1F;
|
||||
uint16_t b = (s >> 0) & 0x1F;
|
||||
dst[i] = static_cast<uint16_t>((r << 11) | (g << 6) | (b << 1) | a);
|
||||
}
|
||||
}
|
||||
|
||||
// BGRA1555_REV -> RGBA8888
|
||||
static inline void convert_BGRA1555_REV_to_RGBA8888(const uint16_t* __restrict src, uint8_t* __restrict dstRGBA8, size_t npx)
|
||||
{
|
||||
for (size_t i = 0; i < npx; ++i) {
|
||||
uint16_t s = src[i];
|
||||
uint8_t A = (s >> 15) ? 255 : 0;
|
||||
uint8_t R5 = (s >> 10) & 0x1F;
|
||||
uint8_t G5 = (s >> 5) & 0x1F;
|
||||
uint8_t B5 = s & 0x1F;
|
||||
// expand 5 to 8 bits
|
||||
uint8_t R = (R5 << 3) | (R5 >> 2);
|
||||
uint8_t G = (G5 << 3) | (G5 >> 2);
|
||||
uint8_t B = (B5 << 3) | (B5 >> 2);
|
||||
size_t o = 4 * i;
|
||||
dstRGBA8[o + 0] = R;
|
||||
dstRGBA8[o + 1] = G;
|
||||
dstRGBA8[o + 2] = B;
|
||||
dstRGBA8[o + 3] = A;
|
||||
}
|
||||
}
|
||||
|
||||
// BGR -> RGB
|
||||
static inline void convert_BGR_to_RGB(const uint8_t* __restrict src, uint8_t* __restrict dst, size_t npx)
|
||||
{
|
||||
for (size_t i = 0, s = 0, t = 0; i < npx; ++i, s += 3, t += 3) {
|
||||
uint8_t b = src[s + 0];
|
||||
uint8_t g = src[s + 1];
|
||||
uint8_t r = src[s + 2];
|
||||
dst[t + 0] = r;
|
||||
dst[t + 1] = g;
|
||||
dst[t + 2] = b;
|
||||
}
|
||||
}
|
||||
|
||||
// BGRA 8888 -> RGBA 8888
|
||||
static inline void convert_BGRA8888_to_RGBA8888(const uint8_t* __restrict src, uint8_t* __restrict dst, size_t npx)
|
||||
{
|
||||
for (size_t i = 0; i < npx; i++) {
|
||||
const uint8_t b = src[4 * i + 0];
|
||||
const uint8_t g = src[4 * i + 1];
|
||||
const uint8_t r = src[4 * i + 2];
|
||||
const uint8_t a = src[4 * i + 3];
|
||||
dst[4 * i + 0] = r;
|
||||
dst[4 * i + 1] = g;
|
||||
dst[4 * i + 2] = b;
|
||||
dst[4 * i + 3] = a;
|
||||
}
|
||||
}
|
||||
|
||||
// BGR 3B -> RGBA 4B
|
||||
static inline void convert_BGR_to_RGBA(const uint8_t* __restrict src, uint8_t* __restrict dst, size_t npx)
|
||||
{
|
||||
for (size_t i = 0; i < npx; ++i) {
|
||||
const size_t s = i * 3;
|
||||
const size_t t = i * 4;
|
||||
dst[t + 0] = src[s + 2]; // R <- B
|
||||
dst[t + 1] = src[s + 1]; // G
|
||||
dst[t + 2] = src[s + 0]; // B <- R
|
||||
dst[t + 3] = 255; // A
|
||||
}
|
||||
}
|
||||
|
||||
// BGRA1555_REV -> RGB888
|
||||
static inline void convert_BGRA1555_REV_to_RGB888(const uint16_t* __restrict src, uint8_t* __restrict dstRGB8, size_t npx)
|
||||
{
|
||||
for (size_t i = 0; i < npx; ++i) {
|
||||
uint16_t s = src[i];
|
||||
uint8_t R5 = (s >> 10) & 0x1F;
|
||||
uint8_t G5 = (s >> 5) & 0x1F;
|
||||
uint8_t B5 = s & 0x1F;
|
||||
|
||||
// expand 5 to 8 bits
|
||||
uint8_t R = (R5 << 3) | (R5 >> 2);
|
||||
uint8_t G = (G5 << 3) | (G5 >> 2);
|
||||
uint8_t B = (B5 << 3) | (B5 >> 2);
|
||||
|
||||
size_t o = 3 * i;
|
||||
dstRGB8[o + 0] = R;
|
||||
dstRGB8[o + 1] = G;
|
||||
dstRGB8[o + 2] = B;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Intercept calls to do pixel conversion and format adjustments to something the driver can work with
|
||||
Note: This is only needed for uncompressed texture formats
|
||||
@@ -187,7 +88,7 @@ static inline void glTexSubImage3D(GLenum target, GLint level, GLint xoff, GLint
|
||||
if (data != nullptr)
|
||||
{
|
||||
std::vector<uint8_t> scratch(npx * 4); // RGBA8888 = 4 BPP
|
||||
convert_BGRA1555_REV_to_RGBA8888(reinterpret_cast<const uint16_t*>(data), scratch.data(), npx);
|
||||
graphics::util::convert_BGRA1555_REV_to_RGBA8888(reinterpret_cast<const uint16_t*>(data), scratch.data(), npx);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glad_glTexSubImage3D(target, level, xoff, yoff, zoff, w, h, d, format, type, scratch.data());
|
||||
return;
|
||||
@@ -198,7 +99,7 @@ static inline void glTexSubImage3D(GLenum target, GLint level, GLint xoff, GLint
|
||||
if (data != nullptr)
|
||||
{
|
||||
std::vector<uint8_t> scratch(npx * 3); // RGB888 = 3 BPP
|
||||
convert_BGRA1555_REV_to_RGB888(reinterpret_cast<const uint16_t*>(data), scratch.data(), npx);
|
||||
graphics::util::convert_BGRA1555_REV_to_RGB888(reinterpret_cast<const uint16_t*>(data), scratch.data(), npx);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glad_glTexSubImage3D(target, level, xoff, yoff, zoff, w, h, d, format, type, scratch.data());
|
||||
return;
|
||||
@@ -208,7 +109,7 @@ static inline void glTexSubImage3D(GLenum target, GLint level, GLint xoff, GLint
|
||||
type = GL_UNSIGNED_SHORT_5_5_5_1;
|
||||
if (data != nullptr) {
|
||||
std::vector<uint8_t> scratch(npx * 2); // RGBA5551 = 2 BPP
|
||||
convert_BGRA1555_REV_to_RGBA5551(reinterpret_cast<const uint16_t*>(data),
|
||||
graphics::util::convert_BGRA1555_REV_to_RGBA5551(reinterpret_cast<const uint16_t*>(data),
|
||||
reinterpret_cast<uint16_t*>(scratch.data()),
|
||||
npx);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
@@ -226,7 +127,7 @@ static inline void glTexSubImage3D(GLenum target, GLint level, GLint xoff, GLint
|
||||
format = GL_RGBA;
|
||||
if (data != nullptr) {
|
||||
std::vector<uint8_t> scratch(npx * 4); // RGBA8888 = 4 BPP
|
||||
convert_BGR_to_RGBA(static_cast<const uint8_t*>(data), scratch.data(), npx);
|
||||
graphics::util::convert_BGR_to_RGBA(static_cast<const uint8_t*>(data), scratch.data(), npx);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glad_glTexSubImage3D(target, level, xoff, yoff, zoff, w, h, d, format, type, scratch.data());
|
||||
return;
|
||||
@@ -237,7 +138,7 @@ static inline void glTexSubImage3D(GLenum target, GLint level, GLint xoff, GLint
|
||||
format = GL_RGB;
|
||||
if (data != nullptr) {
|
||||
std::vector<uint8_t> scratch(npx * 3); // RGB888 = 3 BPP
|
||||
convert_BGR_to_RGB(static_cast<const uint8_t*>(data), scratch.data(), npx);
|
||||
graphics::util::convert_BGR_to_RGB(static_cast<const uint8_t*>(data), scratch.data(), npx);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glad_glTexSubImage3D(target, level, xoff, yoff, zoff, w, h, d, format, type, scratch.data());
|
||||
return;
|
||||
@@ -251,7 +152,7 @@ static inline void glTexSubImage3D(GLenum target, GLint level, GLint xoff, GLint
|
||||
if (data != nullptr /* && !GLAD_GL_EXT_texture_format_BGRA8888*/) {
|
||||
// Conversion forced on because the check either does not work or buggy impl on Mali
|
||||
std::vector<uint8_t> scratch(npx * 4);
|
||||
convert_BGRA8888_to_RGBA8888(reinterpret_cast<const uint8_t*>(data), scratch.data(), npx);
|
||||
graphics::util::convert_BGRA8888_to_RGBA8888(reinterpret_cast<const uint8_t*>(data), scratch.data(), npx);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glad_glTexSubImage3D(target, level, xoff, yoff, zoff, w, h, d, GL_RGBA, type, scratch.data());
|
||||
return;
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
#include "es_compatibility.h"
|
||||
#endif
|
||||
|
||||
#include "backends/imgui_impl_opengl3.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
// minimum GL / GLES version we can reliably support is 3.2
|
||||
@@ -148,8 +150,8 @@ void gr_opengl_flip()
|
||||
GL_state.ColorMask(true, true, true, true);
|
||||
GL_state.StencilTest(GL_FALSE);
|
||||
|
||||
opengl_set_generic_uniform_data<graphics::generic_data::gamma_blit_data>(
|
||||
[gamma](graphics::generic_data::gamma_blit_data* data) {
|
||||
opengl_set_generic_uniform_data<graphics::generic_data::gamma_encode_data>(
|
||||
[gamma](graphics::generic_data::gamma_encode_data* data) {
|
||||
data->gamma = gamma;
|
||||
});
|
||||
|
||||
@@ -1040,6 +1042,16 @@ int opengl_init_display_device()
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gr_opengl_imgui_new_frame()
|
||||
{
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
}
|
||||
|
||||
static void gr_opengl_imgui_render_draw_data()
|
||||
{
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
|
||||
void gr_opengl_init_function_pointers()
|
||||
{
|
||||
gr_screen.gf_flip = gr_opengl_flip;
|
||||
@@ -1173,6 +1185,9 @@ void gr_opengl_init_function_pointers()
|
||||
|
||||
gr_screen.gf_override_fog = gr_opengl_override_fog;
|
||||
|
||||
gr_screen.gf_imgui_new_frame = gr_opengl_imgui_new_frame;
|
||||
gr_screen.gf_imgui_render_draw_data = gr_opengl_imgui_render_draw_data;
|
||||
|
||||
gr_screen.gf_openxr_get_extensions = gr_opengl_openxr_get_extensions;
|
||||
gr_screen.gf_openxr_test_capabilities = gr_opengl_openxr_test_capabilities;
|
||||
gr_screen.gf_openxr_create_session = gr_opengl_openxr_create_session;
|
||||
@@ -1600,12 +1615,19 @@ bool gr_opengl_is_capable(gr_capability capability)
|
||||
return GLAD_GL_ARB_buffer_storage != 0;
|
||||
case gr_capability::CAPABILITY_BPTC:
|
||||
return GLAD_GL_ARB_texture_compression_bptc != 0;
|
||||
case gr_capability::CAPABILITY_S3TC:
|
||||
return GLAD_GL_EXT_texture_compression_s3tc != 0;
|
||||
case gr_capability::CAPABILITY_LARGE_SHADER:
|
||||
return !Cmdline_no_large_shaders;
|
||||
case gr_capability::CAPABILITY_INSTANCED_RENDERING:
|
||||
return GLAD_GL_ARB_vertex_attrib_binding;
|
||||
case gr_capability::CAPABILITY_FAST_SHADOWS:
|
||||
return GLAD_GL_ARB_vertex_attrib_binding && GLAD_GL_ARB_shader_viewport_layer_array && GLAD_GL_ARB_gpu_shader5;
|
||||
case gr_capability::CAPABILITY_QUERIES_REUSABLE:
|
||||
return true;
|
||||
case gr_capability::CAPABILITY_RAYTRACED_SHADOWS:
|
||||
// Raytraced shadows are only implemented for the Vulkan backend.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1676,7 +1698,7 @@ DCF(ogl_anisotropy, "toggles anisotropic filtering")
|
||||
bool process = true;
|
||||
int value;
|
||||
|
||||
if ( gr_screen.mode != GR_OPENGL ) {
|
||||
if ( gr_screen.mode != GraphicsAPI::OpenGL ) {
|
||||
dc_printf("Can only set anisotropic filter in OpenGL mode.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
#include "gropengldeferred.h"
|
||||
#include "globalincs/vmallocator.h"
|
||||
#include "graphics/util/primitives.h"
|
||||
|
||||
#include "ShaderProgram.h"
|
||||
#include "gropengldraw.h"
|
||||
@@ -375,7 +375,7 @@ void gr_opengl_deferred_lighting_finish()
|
||||
auto light_data = prepare_light_uniforms(l, light_uniform_aligner, lp);
|
||||
|
||||
if (l.type == Light_Type::Cone) {
|
||||
light_data->dualCone = (l.flags & LF_DUAL_CONE) ? 1.0f : 0.0f;
|
||||
light_data->dualCone = (l.flags & LF_DUAL_CONE) ? 1 : 0;
|
||||
light_data->coneAngle = l.cone_angle;
|
||||
light_data->coneInnerAngle = l.cone_inner_angle;
|
||||
light_data->coneDir = l.vec2;
|
||||
@@ -703,69 +703,12 @@ void gr_opengl_draw_deferred_light_sphere(const vec3d *position)
|
||||
}
|
||||
|
||||
|
||||
void gr_opengl_deferred_light_cylinder_init(int segments) // Generate a VBO of a cylinder of radius and height 1.0f, based on code at http://www.ogre3d.org/tikiwiki/ManualSphereMeshes
|
||||
void gr_opengl_deferred_light_cylinder_init(int segments)
|
||||
{
|
||||
unsigned int nVertex = (segments + 1) * 2 * 3 + 6; // Can someone verify this?
|
||||
unsigned int nIndex = deferred_light_cylinder_icount = 12 * (segments + 1) - 6; //This too
|
||||
float *Vertices = (float*)vm_malloc(sizeof(float) * nVertex);
|
||||
float *pVertex = Vertices;
|
||||
ushort *Indices = (ushort*)vm_malloc(sizeof(ushort) * nIndex);
|
||||
ushort *pIndex = Indices;
|
||||
auto mesh = graphics::util::generate_cylinder_mesh(segments);
|
||||
|
||||
float fDeltaSegAngle = (2.0f * PI / segments);
|
||||
unsigned short wVerticeIndex = 0 ;
|
||||
|
||||
*pVertex++ = 0.0f;
|
||||
*pVertex++ = 0.0f;
|
||||
*pVertex++ = 0.0f;
|
||||
wVerticeIndex ++;
|
||||
*pVertex++ = 0.0f;
|
||||
*pVertex++ = 0.0f;
|
||||
*pVertex++ = 1.0f;
|
||||
wVerticeIndex ++;
|
||||
|
||||
for( int ring = 0; ring <= 1; ring++ ) {
|
||||
float z0 = (float)ring;
|
||||
|
||||
// Generate the group of segments for the current ring
|
||||
for(int seg = 0; seg <= segments; seg++) {
|
||||
float x0 = sinf(seg * fDeltaSegAngle);
|
||||
float y0 = cosf(seg * fDeltaSegAngle);
|
||||
|
||||
// Add one vertex to the strip which makes up the cylinder
|
||||
*pVertex++ = x0;
|
||||
*pVertex++ = y0;
|
||||
*pVertex++ = z0;
|
||||
|
||||
if (!ring) {
|
||||
*pIndex++ = wVerticeIndex + (ushort)segments + 1;
|
||||
*pIndex++ = wVerticeIndex;
|
||||
*pIndex++ = wVerticeIndex + (ushort)segments;
|
||||
*pIndex++ = wVerticeIndex + (ushort)segments + 1;
|
||||
*pIndex++ = wVerticeIndex + 1;
|
||||
*pIndex++ = wVerticeIndex;
|
||||
if(seg != segments)
|
||||
{
|
||||
*pIndex++ = wVerticeIndex + 1;
|
||||
*pIndex++ = wVerticeIndex;
|
||||
*pIndex++ = 0;
|
||||
}
|
||||
wVerticeIndex ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(seg != segments)
|
||||
{
|
||||
*pIndex++ = wVerticeIndex + 1;
|
||||
*pIndex++ = wVerticeIndex;
|
||||
*pIndex++ = 1;
|
||||
wVerticeIndex ++;
|
||||
}
|
||||
}
|
||||
}; // end for seg
|
||||
} // end for ring
|
||||
|
||||
deferred_light_cylinder_vcount = wVerticeIndex;
|
||||
deferred_light_cylinder_vcount = static_cast<GLushort>(mesh.vertex_count);
|
||||
deferred_light_cylinder_icount = mesh.index_count;
|
||||
|
||||
glGetError();
|
||||
|
||||
@@ -774,17 +717,12 @@ void gr_opengl_deferred_light_cylinder_init(int segments) // Generate a VBO of a
|
||||
// make sure we have one
|
||||
if (deferred_light_cylinder_vbo) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, deferred_light_cylinder_vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, nVertex * sizeof(float), Vertices, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.vertices.size() * sizeof(float), mesh.vertices.data(), GL_STATIC_DRAW);
|
||||
|
||||
// just in case
|
||||
if ( opengl_check_for_errors() ) {
|
||||
glDeleteBuffers(1, &deferred_light_cylinder_vbo);
|
||||
deferred_light_cylinder_vbo = 0;
|
||||
|
||||
vm_free(Indices);
|
||||
Indices = nullptr;
|
||||
vm_free(Vertices);
|
||||
Vertices = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -796,71 +734,25 @@ void gr_opengl_deferred_light_cylinder_init(int segments) // Generate a VBO of a
|
||||
// make sure we have one
|
||||
if (deferred_light_cylinder_ibo) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, deferred_light_cylinder_ibo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, nIndex * sizeof(ushort), Indices, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.indices.size() * sizeof(ushort), mesh.indices.data(), GL_STATIC_DRAW);
|
||||
|
||||
// just in case
|
||||
if ( opengl_check_for_errors() ) {
|
||||
glDeleteBuffers(1, &deferred_light_cylinder_ibo);
|
||||
deferred_light_cylinder_ibo = 0;
|
||||
|
||||
vm_free(Indices);
|
||||
Indices = nullptr;
|
||||
vm_free(Vertices);
|
||||
Vertices = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
vm_free(Indices);
|
||||
Indices = nullptr;
|
||||
vm_free(Vertices);
|
||||
Vertices = nullptr;
|
||||
}
|
||||
|
||||
void gr_opengl_deferred_light_sphere_init(int rings, int segments) // Generate a VBO of a sphere of radius 1.0f, based on code at http://www.ogre3d.org/tikiwiki/ManualSphereMeshes
|
||||
void gr_opengl_deferred_light_sphere_init(int rings, int segments)
|
||||
{
|
||||
unsigned int nVertex = (rings + 1) * (segments+1) * 3;
|
||||
unsigned int nIndex = deferred_light_sphere_icount = 6 * rings * (segments + 1);
|
||||
float *Vertices = (float*)vm_malloc(sizeof(float) * nVertex);
|
||||
float *pVertex = Vertices;
|
||||
ushort *Indices = (ushort*)vm_malloc(sizeof(ushort) * nIndex);
|
||||
ushort *pIndex = Indices;
|
||||
auto mesh = graphics::util::generate_sphere_mesh(rings, segments);
|
||||
|
||||
float fDeltaRingAngle = (PI / rings);
|
||||
float fDeltaSegAngle = (2.0f * PI / segments);
|
||||
unsigned short wVerticeIndex = 0 ;
|
||||
|
||||
// Generate the group of rings for the sphere
|
||||
for( int ring = 0; ring <= rings; ring++ ) {
|
||||
float r0 = sinf (ring * fDeltaRingAngle);
|
||||
float y0 = cosf (ring * fDeltaRingAngle);
|
||||
|
||||
// Generate the group of segments for the current ring
|
||||
for(int seg = 0; seg <= segments; seg++) {
|
||||
float x0 = r0 * sinf(seg * fDeltaSegAngle);
|
||||
float z0 = r0 * cosf(seg * fDeltaSegAngle);
|
||||
|
||||
// Add one vertex to the strip which makes up the sphere
|
||||
*pVertex++ = x0;
|
||||
*pVertex++ = y0;
|
||||
*pVertex++ = z0;
|
||||
|
||||
if (ring != rings) {
|
||||
// each vertex (except the last) has six indices pointing to it
|
||||
*pIndex++ = wVerticeIndex + (ushort)segments + 1;
|
||||
*pIndex++ = wVerticeIndex;
|
||||
*pIndex++ = wVerticeIndex + (ushort)segments;
|
||||
*pIndex++ = wVerticeIndex + (ushort)segments + 1;
|
||||
*pIndex++ = wVerticeIndex + 1;
|
||||
*pIndex++ = wVerticeIndex;
|
||||
wVerticeIndex ++;
|
||||
}
|
||||
}; // end for seg
|
||||
} // end for ring
|
||||
|
||||
deferred_light_sphere_vcount = wVerticeIndex;
|
||||
deferred_light_sphere_vcount = static_cast<GLushort>(mesh.vertex_count);
|
||||
deferred_light_sphere_icount = mesh.index_count;
|
||||
|
||||
glGetError();
|
||||
|
||||
@@ -869,17 +761,12 @@ void gr_opengl_deferred_light_sphere_init(int rings, int segments) // Generate a
|
||||
// make sure we have one
|
||||
if (deferred_light_sphere_vbo) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, deferred_light_sphere_vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, nVertex * sizeof(float), Vertices, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.vertices.size() * sizeof(float), mesh.vertices.data(), GL_STATIC_DRAW);
|
||||
|
||||
// just in case
|
||||
if ( opengl_check_for_errors() ) {
|
||||
glDeleteBuffers(1, &deferred_light_sphere_vbo);
|
||||
deferred_light_sphere_vbo = 0;
|
||||
|
||||
vm_free(Vertices);
|
||||
Vertices = nullptr;
|
||||
vm_free(Indices);
|
||||
Indices = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -891,27 +778,17 @@ void gr_opengl_deferred_light_sphere_init(int rings, int segments) // Generate a
|
||||
// make sure we have one
|
||||
if (deferred_light_sphere_ibo) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, deferred_light_sphere_ibo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, nIndex * sizeof(ushort), Indices, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.indices.size() * sizeof(ushort), mesh.indices.data(), GL_STATIC_DRAW);
|
||||
|
||||
// just in case
|
||||
if ( opengl_check_for_errors() ) {
|
||||
glDeleteBuffers(1, &deferred_light_sphere_ibo);
|
||||
deferred_light_sphere_ibo = 0;
|
||||
|
||||
vm_free(Vertices);
|
||||
Vertices = nullptr;
|
||||
vm_free(Indices);
|
||||
Indices = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
vm_free(Vertices);
|
||||
Vertices = nullptr;
|
||||
vm_free(Indices);
|
||||
Indices = nullptr;
|
||||
}
|
||||
|
||||
void opengl_draw_sphere()
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// the other platforms do not go before the #includes because this will cause conflicts from symbols defined in XLib,
|
||||
// specifically None and Always; see https://stackoverflow.com/questions/22476110/c-compiling-error-including-x11-x-h-x11-xlib-h
|
||||
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "io/cursor.h"
|
||||
#include "io/mouse.h"
|
||||
#include "graphics/matrix.h"
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "def_files/def_files.h"
|
||||
#include "graphics/shader_types.h"
|
||||
#include "graphics/grinternal.h"
|
||||
#include "graphics/openxr.h"
|
||||
#include "graphics/util/uniform_structs.h"
|
||||
@@ -88,7 +89,11 @@ void opengl_post_pass_tonemap()
|
||||
data->x0 = ppc.x0;
|
||||
data->x1 = ppc.x1;
|
||||
data->y0 = ppc.y0;
|
||||
data->exposure = ltp::current_exposure(); });
|
||||
data->exposure = ltp::current_exposure();
|
||||
// OpenGL never negotiates HDR10 output, so Gr_hdr_output_active is
|
||||
// always false here and current_tonemapper() never returns HdrScene.
|
||||
data->hdr_paperwhite_nits = 0.0f;
|
||||
data->hdr_peak_nits = 0.0f; });
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Scene_ldr_texture, 0);
|
||||
|
||||
@@ -785,71 +790,9 @@ void gr_opengl_post_process_restore_zbuffer()
|
||||
}
|
||||
}
|
||||
|
||||
static void set_fxaa_defines(SCP_stringstream& sflags)
|
||||
{
|
||||
// Since we require OpenGL 3.2 we always have support for GLSL 130
|
||||
sflags << "#define FXAA_GLSL_120 0\n";
|
||||
sflags << "#define FXAA_GLSL_130 1\n";
|
||||
|
||||
if (GLSL_version >= 400) {
|
||||
// The gather function became part of the standard with GLSL 4.00
|
||||
sflags << "#define FXAA_GATHER4_ALPHA 1\n";
|
||||
}
|
||||
|
||||
switch (Gr_aa_mode) {
|
||||
case AntiAliasMode::None:
|
||||
sflags << "#define FXAA_QUALITY_PRESET 10\n";
|
||||
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/6.0)\n";
|
||||
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/12.0)\n";
|
||||
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
|
||||
break;
|
||||
case AntiAliasMode::FXAA_Low:
|
||||
sflags << "#define FXAA_QUALITY_PRESET 12\n";
|
||||
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/8.0)\n";
|
||||
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/16.0)\n";
|
||||
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
|
||||
break;
|
||||
case AntiAliasMode::FXAA_Medium:
|
||||
sflags << "#define FXAA_QUALITY_PRESET 26\n";
|
||||
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/12.0)\n";
|
||||
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/24.0)\n";
|
||||
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
|
||||
break;
|
||||
case AntiAliasMode::FXAA_High:
|
||||
sflags << "#define FXAA_QUALITY_PRESET 39\n";
|
||||
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/15.0)\n";
|
||||
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/32.0)\n";
|
||||
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Unhandled FXAA mode %d!", static_cast<int>(Gr_aa_mode));
|
||||
}
|
||||
}
|
||||
void set_smaa_defines(SCP_stringstream& sflags)
|
||||
{
|
||||
// Define what GLSL version we use
|
||||
if (GLSL_version >= 400) {
|
||||
sflags << "#define SMAA_GLSL_4\n";
|
||||
} else {
|
||||
sflags << "#define SMAA_GLSL_3\n";
|
||||
}
|
||||
|
||||
switch (Gr_aa_mode) {
|
||||
case AntiAliasMode::SMAA_Low:
|
||||
sflags << "#define SMAA_PRESET_LOW\n";
|
||||
break;
|
||||
case AntiAliasMode::SMAA_Medium:
|
||||
sflags << "#define SMAA_PRESET_MEDIUM\n";
|
||||
break;
|
||||
case AntiAliasMode::SMAA_High:
|
||||
sflags << "#define SMAA_PRESET_HIGH\n";
|
||||
break;
|
||||
case AntiAliasMode::SMAA_Ultra:
|
||||
sflags << "#define SMAA_PRESET_ULTRA\n";
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Unhandled SMAA mode %d!", static_cast<int>(Gr_aa_mode));
|
||||
}
|
||||
sflags << shader_get_smaa_defines(Gr_aa_mode, GLSL_version >= 400).c_str();
|
||||
}
|
||||
void opengl_post_shader_header(SCP_stringstream& sflags, shader_type shader_t, int flags)
|
||||
{
|
||||
@@ -868,7 +811,7 @@ void opengl_post_shader_header(SCP_stringstream& sflags, shader_type shader_t, i
|
||||
snprintf(temp, 64, "#define SAMPLE_NUM %d\n", ls_params.samplenum);
|
||||
sflags << temp;
|
||||
} else if (shader_t == SDR_TYPE_POST_PROCESS_FXAA) {
|
||||
set_fxaa_defines(sflags);
|
||||
sflags << shader_get_fxaa_defines(Gr_aa_mode, GLSL_version >= 400);
|
||||
} else if (shader_t == SDR_TYPE_POST_PROCESS_SMAA_EDGE || shader_t == SDR_TYPE_POST_PROCESS_SMAA_BLENDING_WEIGHT ||
|
||||
shader_t == SDR_TYPE_POST_PROCESS_SMAA_NEIGHBORHOOD_BLENDING) {
|
||||
set_smaa_defines(sflags);
|
||||
@@ -1217,4 +1160,4 @@ void opengl_post_process_shutdown()
|
||||
Post_active_shader_index = 0;
|
||||
|
||||
Post_initialized = 0;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "ShaderProgram.h"
|
||||
|
||||
#include "cfile/cfile.h"
|
||||
#include "graphics/shader_preprocess.h"
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "def_files/def_files.h"
|
||||
#include "graphics/2d.h"
|
||||
@@ -22,6 +23,7 @@
|
||||
#include "graphics/opengl/gropenglstate.h"
|
||||
#include "graphics/opengl/gropengltexture.h"
|
||||
#include "graphics/opengl/gropengltnl.h"
|
||||
#include "graphics/shader_types.h"
|
||||
#include "graphics/util/uniform_structs.h"
|
||||
#include "lighting/lighting.h"
|
||||
#include "math/vecmat.h"
|
||||
@@ -86,150 +88,6 @@ opengl_uniform_block_binding GL_uniform_blocks[] = {
|
||||
* Static lookup reference for shader uniforms
|
||||
* When adding a new shader, list all associated uniforms and attributes here
|
||||
*/
|
||||
// clang-format off
|
||||
static opengl_shader_type_t GL_shader_types[] = {
|
||||
{ SDR_TYPE_MODEL, "main-v.sdr", "main-f.sdr", "main-g.sdr",
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::NORMAL, opengl_vert_attrib::TANGENT, opengl_vert_attrib::MODEL_ID }, "Model Rendering", false },
|
||||
|
||||
{ SDR_TYPE_EFFECT_PARTICLE, "effect-v.sdr", "effect-f.sdr", "effect-g.sdr",
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::RADIUS, opengl_vert_attrib::COLOR }, "Particle Effects", false },
|
||||
|
||||
{ SDR_TYPE_EFFECT_DISTORTION, "effect-distort-v.sdr", "effect-distort-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::RADIUS, opengl_vert_attrib::COLOR }, "Distortion Effects", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_MAIN, "post-v.sdr", "post-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Post Processing", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_BLUR, "post-v.sdr", "blur-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Gaussian Blur", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_BLOOM_COMP, "post-v.sdr", "bloom-comp-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Bloom Compositing", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_BRIGHTPASS, "post-v.sdr", "brightpass-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Bloom Brightpass", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_FXAA, "fxaa-v.sdr", "fxaa-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION }, "FXAA", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_FXAA_PREPASS, "post-v.sdr", "fxaapre-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "FXAA Prepass", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_LIGHTSHAFTS, "post-v.sdr", "ls-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Lightshafts", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_TONEMAPPING, "post-v.sdr", "tonemapping-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Tonemapping", false },
|
||||
|
||||
{ SDR_TYPE_DEFERRED_LIGHTING, "deferred-v.sdr", "deferred-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION }, "Deferred Lighting", false },
|
||||
|
||||
{ SDR_TYPE_DEFERRED_CLEAR, "deferred-clear-v.sdr", "deferred-clear-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION }, "Clear Deferred Lighting Buffer", false },
|
||||
|
||||
{ SDR_TYPE_VIDEO_PROCESS, "video-v.sdr", "video-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Video Playback", false },
|
||||
|
||||
{ SDR_TYPE_PASSTHROUGH_RENDER, "passthrough-v.sdr", "passthrough-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::COLOR }, "Passthrough", false },
|
||||
|
||||
{ SDR_TYPE_SHIELD_DECAL, "shield-impact-v.sdr", "shield-impact-f.sdr", 0,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::NORMAL }, "Shield Decals", false },
|
||||
|
||||
{ SDR_TYPE_BATCHED_BITMAP, "batched-v.sdr", "batched-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::COLOR }, "Batched bitmaps", false },
|
||||
|
||||
{ SDR_TYPE_DEFAULT_MATERIAL, "default-material.vert.spv.glsl", "default-material.frag.spv.glsl", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::COLOR }, "Default material", true },
|
||||
|
||||
{ SDR_TYPE_NANOVG, "nanovg-v.sdr", "nanovg-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "NanoVG shader", false },
|
||||
|
||||
{ SDR_TYPE_DECAL, "decal-v.sdr", "decal-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::MODEL_MATRIX }, "Decal rendering", false },
|
||||
|
||||
{ SDR_TYPE_SCENE_FOG, "post-v.sdr", "fog-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Scene fogging", false },
|
||||
|
||||
{ SDR_TYPE_VOLUMETRIC_FOG, "post-v.sdr", "volumetric-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Volumetric fogging", false },
|
||||
|
||||
{ SDR_TYPE_ROCKET_UI, "rocketui-v.sdr", "rocketui-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::COLOR, opengl_vert_attrib::TEXCOORD }, "libRocket UI", false },
|
||||
|
||||
{ SDR_TYPE_COPY, "post-v.sdr", "copy-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Texture copy", false },
|
||||
|
||||
{ SDR_TYPE_COPY_WORLD, "passthrough-v.sdr", "copy-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Texture copy world space", false },
|
||||
|
||||
{ SDR_TYPE_MSAA_RESOLVE, "post-v.sdr", "msaa-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "MSAA resolve shader", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_SMAA_EDGE, "smaa-edge-v.sdr", "smaa-edge-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "SMAA Edge detection", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_SMAA_BLENDING_WEIGHT, "smaa-blend-v.sdr", "smaa-blend-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "SMAA Blending weight calculation", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_SMAA_NEIGHBORHOOD_BLENDING, "smaa-neighbour-v.sdr", "smaa-neighbour-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "SMAA Neighborhood Blending", false },
|
||||
|
||||
{ SDR_TYPE_ENVMAP_SPHERE_WARP, "post-v.sdr", "envmap-sphere-warp-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Environment Map Export", false },
|
||||
|
||||
{ SDR_TYPE_IRRADIANCE_MAP_GEN, "post-v.sdr", "irrmap-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Irradiance Map Generation", false },
|
||||
|
||||
{ SDR_TYPE_SHADOW_MAP_GEN, "shadow_map-v.sdr", "shadow_map-f.sdr", "shadow_map-g.sdr",
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::NORMAL, opengl_vert_attrib::TANGENT, opengl_vert_attrib::MODEL_ID }, "Shadow Map Generation", false },
|
||||
|
||||
{ SDR_TYPE_GAMMA_BLIT, "post-v.sdr", "gamma-correct-f.sdr", nullptr,
|
||||
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Gamma correct blit", false },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* Static lookup reference for shader variant uniforms
|
||||
* When adding a new shader variant for a shader, list all associated uniforms and attributes here
|
||||
*/
|
||||
static opengl_shader_variant_t GL_shader_variants[] = {
|
||||
//Model shader flags, both those set always as a compile flag as well as those that are usually runtime checks, need to be defined in this file
|
||||
#define MODEL_SDR_FLAG_MODE_CPP_ARRAY
|
||||
#include "def_files/data/effects/model_shader_flags.h"
|
||||
#undef MODEL_SDR_FLAG_MODE_CPP_ARRAY
|
||||
|
||||
{SDR_TYPE_EFFECT_PARTICLE, true, SDR_FLAG_PARTICLE_POINT_GEN, "FLAG_EFFECT_GEOMETRY", {opengl_vert_attrib::UVEC}, "Geometry shader point-based particles"},
|
||||
|
||||
{SDR_TYPE_DEFERRED_LIGHTING, false, SDR_FLAG_ENV_MAP, "ENV_MAP", {}, "Render ambient light with env and irrmaps"},
|
||||
|
||||
{SDR_TYPE_POST_PROCESS_BLUR, false, SDR_FLAG_BLUR_HORIZONTAL, "PASS_0", {}, "Horizontal blur pass"},
|
||||
|
||||
{SDR_TYPE_POST_PROCESS_BLUR, false, SDR_FLAG_BLUR_VERTICAL, "PASS_1", {}, "Vertical blur pass"},
|
||||
|
||||
{SDR_TYPE_NANOVG, false, SDR_FLAG_NANOVG_EDGE_AA, "EDGE_AA", {}, "NanoVG edge anti-alias"},
|
||||
|
||||
{SDR_TYPE_DECAL, false, SDR_FLAG_DECAL_USE_NORMAL_MAP, "USE_NORMAL_MAP", {}, "Decal use scene normal map"},
|
||||
|
||||
{SDR_TYPE_MSAA_RESOLVE, false, SDR_FLAG_MSAA_SAMPLES_4, "SAMPLES_4", {}, "Sets the MSAA resolve shader to 4 samples"},
|
||||
|
||||
{SDR_TYPE_MSAA_RESOLVE, false, SDR_FLAG_MSAA_SAMPLES_8, "SAMPLES_8", {}, "Sets the MSAA resolve shader to 8 samples"},
|
||||
|
||||
{SDR_TYPE_MSAA_RESOLVE, false, SDR_FLAG_MSAA_SAMPLES_16, "SAMPLES_16", {}, "Sets the MSAA resolve shader to 16 samples"},
|
||||
|
||||
{SDR_TYPE_VOLUMETRIC_FOG, false, SDR_FLAG_VOLUMETRICS_DO_EDGE_SMOOTHING, "DO_EDGE_SMOOTHING", {}, "Perform costly edge smoothing lookups"},
|
||||
|
||||
{SDR_TYPE_VOLUMETRIC_FOG, false, SDR_FLAG_VOLUMETRICS_NOISE, "NOISE", {}, "Add noise to volumetrics"},
|
||||
|
||||
{SDR_TYPE_COPY_WORLD, false, SDR_FLAG_COPY_FROM_ARRAY, "COPY_ARRAY", {}, "Expects to copy from an array texture"},
|
||||
|
||||
{SDR_TYPE_POST_PROCESS_TONEMAPPING, false, SDR_FLAG_TONEMAPPING_LINEAR_OUT, "LINEAR_OUT", {}, "Will make the tonemapper output in linear color space and not in sRGB"},
|
||||
|
||||
{SDR_TYPE_SHADOW_MAP_GEN, true, SDR_FLAG_SHADOW_FALLBACK, "GEOMETRY_FALLBACK", {}, "Will make the shadow map generation shader fall back on geometry shaders if multi viewports are not avilable"}
|
||||
|
||||
};
|
||||
|
||||
static const int GL_num_shader_variants = sizeof(GL_shader_variants) / sizeof(opengl_shader_variant_t);
|
||||
|
||||
opengl_shader_t *Current_shader = NULL;
|
||||
|
||||
@@ -323,6 +181,10 @@ static SCP_string opengl_shader_get_header(shader_type type_id, int flags, bool
|
||||
#else
|
||||
sflags << "#version " << GLSL_version << " es\n";
|
||||
#endif
|
||||
sflags << "#define OPENGL\n";
|
||||
sflags << shader_get_shadow_cascade_defines();
|
||||
sflags << shader_get_rt_shadow_light_limit_define();
|
||||
|
||||
if (Detail.lighting < 3) {
|
||||
sflags << "#define FLAG_LIGHT_MODEL_BLINN_PHONG\n";
|
||||
}
|
||||
@@ -339,13 +201,7 @@ static SCP_string opengl_shader_get_header(shader_type type_id, int flags, bool
|
||||
// ignore looking for variants. main post process, lightshafts, and FXAA shaders need special headers to be hacked in
|
||||
opengl_post_shader_header(sflags, type_id, flags);
|
||||
} else {
|
||||
for (int i = 0; i < GL_num_shader_variants; ++i) {
|
||||
opengl_shader_variant_t &variant = GL_shader_variants[i];
|
||||
|
||||
if (type_id == variant.type_id && flags & variant.flag) {
|
||||
sflags << "#define " << variant.flag_text << "\n";
|
||||
}
|
||||
}
|
||||
sflags << shader_build_variant_defines(type_id, flags);
|
||||
}
|
||||
|
||||
return sflags.str();
|
||||
@@ -361,258 +217,17 @@ static SCP_string opengl_shader_get_header(shader_type type_id, int flags, bool
|
||||
* @param flags integer variable holding a combination of SDR_* flags
|
||||
* @return C-string holding the complete shader source code
|
||||
*/
|
||||
static SCP_string opengl_load_shader(const char* filename) {
|
||||
SCP_string content;
|
||||
if (Enable_external_shaders) {
|
||||
CFILE* cf_shader = cfopen(filename, "rt", CF_TYPE_EFFECTS);
|
||||
|
||||
if (cf_shader != NULL) {
|
||||
int len = cfilelength(cf_shader);
|
||||
content.resize(len);
|
||||
|
||||
cfread(&content[0], len + 1, 1, cf_shader);
|
||||
cfclose(cf_shader);
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
//If we're still here, proceed with internals
|
||||
nprintf(("shaders"," Loading built-in default shader for: %s\n", filename));
|
||||
auto def_shader = defaults_get_file(filename);
|
||||
content.assign(reinterpret_cast<const char*>(def_shader.data), def_shader.size);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
static void handle_includes_impl(SCP_vector<SCP_string>& include_stack,
|
||||
SCP_stringstream& output,
|
||||
int& include_counter,
|
||||
const SCP_string& filename,
|
||||
const SCP_string& original) {
|
||||
include_stack.emplace_back(filename);
|
||||
auto current_source_number = include_counter + 1;
|
||||
|
||||
const char* INCLUDE_STRING = "#include";
|
||||
const char* CONDITIONAL_INCLUDE_STRING = "#conditional_include";
|
||||
SCP_stringstream input(original);
|
||||
|
||||
int line_num = 1;
|
||||
for (SCP_string line; std::getline(input, line);) {
|
||||
auto include_start = line.find(CONDITIONAL_INCLUDE_STRING);
|
||||
|
||||
if (include_start != SCP_string::npos) {
|
||||
//This is a conditional include. Figure out whether to include, or whether not to.
|
||||
// Conditional include syntax: #conditional_include (+|-)"capability" "filename"
|
||||
// On +, include if capability is available, on -, include if not available
|
||||
include_start += strlen(CONDITIONAL_INCLUDE_STRING) + 1;
|
||||
bool require_capability = true;
|
||||
|
||||
switch(line.at(include_start)) {
|
||||
case '+':
|
||||
require_capability = true;
|
||||
break;
|
||||
case '-':
|
||||
require_capability = false;
|
||||
break;
|
||||
default:
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed conditional_include line. Expected + or -, got %c.",
|
||||
filename.c_str(),
|
||||
line_num,
|
||||
line.at(include_start));
|
||||
break;
|
||||
}
|
||||
|
||||
auto first_quote = line.find('"', include_start);
|
||||
auto second_quote = line.find('"', first_quote + 1);
|
||||
|
||||
if (first_quote == SCP_string::npos || second_quote == SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed conditional_include line. Could not find both quote characters for capability.",
|
||||
filename.c_str(),
|
||||
line_num);
|
||||
}
|
||||
auto condition = line.substr(first_quote + 1, second_quote - first_quote - 1);
|
||||
auto capability = std::find_if(&gr_capabilities[0], &gr_capabilities[gr_capabilities_num],
|
||||
[condition](const gr_capability_def &ext_pair) { return !stricmp(ext_pair.parse_name, condition.c_str()); });
|
||||
if (capability == &gr_capabilities[gr_capabilities_num]) {
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed conditional_include line. Capability %s does not exist.",
|
||||
filename.c_str(),
|
||||
line_num,
|
||||
condition.c_str());
|
||||
}
|
||||
|
||||
//Prepare for including if capability is correct, skip otherwise.
|
||||
if(gr_is_capable(capability->capability) == require_capability)
|
||||
include_start = second_quote + 1 - strlen(INCLUDE_STRING);
|
||||
else
|
||||
include_start = SCP_string::npos - 1;
|
||||
}
|
||||
else {
|
||||
//Only search for normal includes if it's not a conditional include.
|
||||
include_start = line.find(INCLUDE_STRING);
|
||||
}
|
||||
|
||||
if (include_start != SCP_string::npos && include_start != SCP_string::npos - 1) {
|
||||
auto first_quote = line.find('"', include_start + strlen(INCLUDE_STRING));
|
||||
auto second_quote = line.find('"', first_quote + 1);
|
||||
|
||||
if (first_quote == SCP_string::npos || second_quote == SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed include line. Could not find both quote characters.",
|
||||
filename.c_str(),
|
||||
line_num);
|
||||
}
|
||||
|
||||
auto file_name = line.substr(first_quote + 1, second_quote - first_quote - 1);
|
||||
auto existing_name = std::find_if(include_stack.begin(), include_stack.end(), [&file_name](const SCP_string& str) {
|
||||
return str == file_name;
|
||||
});
|
||||
if (existing_name != include_stack.end()) {
|
||||
SCP_stringstream stack_string;
|
||||
for (auto& name : include_stack) {
|
||||
stack_string << "\t" << name << "\n";
|
||||
}
|
||||
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Detected cyclic include! Previous includes (top level file first):\n%s",
|
||||
filename.c_str(),
|
||||
line_num,
|
||||
stack_string.str().c_str());
|
||||
}
|
||||
|
||||
++include_counter;
|
||||
// The second parameter defines which source string we are currently working with. We keep track of how many
|
||||
// excludes have been in the file so far to specify this
|
||||
output << "#line 1 " << include_counter + 1 << "\n";
|
||||
|
||||
handle_includes_impl(include_stack,
|
||||
output,
|
||||
include_counter,
|
||||
file_name,
|
||||
opengl_load_shader(file_name.c_str()));
|
||||
|
||||
// We are done with the include file so now we can return to the original file
|
||||
output << "#line " << line_num + 1 << " " << current_source_number << "\n";
|
||||
} else if (include_start != SCP_string::npos - 1) {
|
||||
output << line << "\n";
|
||||
}
|
||||
|
||||
++line_num;
|
||||
}
|
||||
|
||||
include_stack.pop_back();
|
||||
}
|
||||
|
||||
static SCP_string handle_includes(const char* filename, const SCP_string& original) {
|
||||
SCP_stringstream output;
|
||||
SCP_vector<SCP_string> include_stack;
|
||||
auto include_counter = 0;
|
||||
|
||||
handle_includes_impl(include_stack, output, include_counter, filename, original);
|
||||
|
||||
return output.str();
|
||||
}
|
||||
|
||||
static SCP_string handle_predefines(const char* filename, const SCP_string& original){
|
||||
SCP_stringstream output;
|
||||
SCP_unordered_map<SCP_string, SCP_string> defines;
|
||||
|
||||
output << "#define GLOBAL_FAR_Z " << std::fixed << std::setprecision(2) << Max_draw_distance << std::defaultfloat << '\n';
|
||||
output << "#define NUM_SHADOW_CASCADES " << (Num_shadow_cascades + Num_cockpit_shadow_cascades) << '\n';
|
||||
|
||||
const char* PREDEFINE_STRING = "#predefine";
|
||||
const char* PREREPLACE_STRING = "#prereplace";
|
||||
|
||||
SCP_stringstream input(original);
|
||||
for (SCP_string line; std::getline(input, line);) {
|
||||
auto predefine_start = line.find(PREDEFINE_STRING);
|
||||
auto prereplace_start = line.find(PREREPLACE_STRING);
|
||||
|
||||
if (predefine_start != SCP_string::npos){
|
||||
predefine_start += strlen(PREDEFINE_STRING);
|
||||
|
||||
auto token_start = line.find(' ', predefine_start);
|
||||
auto token_end = line.find(' ', token_start + 1);
|
||||
|
||||
if (token_start == SCP_string::npos || token_end == SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed predefine line. Could not find define token.",
|
||||
filename);
|
||||
}
|
||||
|
||||
auto token = line.substr(token_start + 1, token_end - token_start - 1);
|
||||
auto replaceWith = line.substr(token_end + 1);
|
||||
|
||||
auto replaceStrToken = replaceWith.find("%s");
|
||||
if (replaceStrToken == SCP_string::npos || replaceWith.find("%s", replaceStrToken + 1) != SCP_string::npos){
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed predefine line. Replacing string must have exactly one %%s.",
|
||||
filename);
|
||||
}
|
||||
if (defines.find(token) != defines.end()) {
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed predefine line. Token %s is already defined.",
|
||||
filename,
|
||||
token.c_str());
|
||||
}
|
||||
|
||||
defines.emplace(std::move(token), std::move(replaceWith));
|
||||
|
||||
output << "\n"; //At this point, don't mess with the linecount
|
||||
}
|
||||
else if (prereplace_start != SCP_string::npos){
|
||||
prereplace_start += strlen(PREREPLACE_STRING);
|
||||
|
||||
auto token_start = line.find(' ', prereplace_start);
|
||||
auto token_end = line.find(' ', token_start + 1);
|
||||
|
||||
if (token_start == SCP_string::npos || token_end == SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed prereplace line. Could not find define token.",
|
||||
filename);
|
||||
}
|
||||
|
||||
auto token = line.substr(token_start + 1, token_end - token_start - 1);
|
||||
auto replaceArg = line.substr(token_end + 1);
|
||||
|
||||
auto replaceWithIt = defines.find(token);
|
||||
if (replaceWithIt == defines.end()) {
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed prereplace line. Could not find token %s.",
|
||||
filename,
|
||||
token.c_str());
|
||||
}
|
||||
|
||||
size_t size = replaceWithIt->second.length() - 1 + replaceArg.size();
|
||||
std::unique_ptr<char[]> buffer = make_unique<char[]>(size);
|
||||
|
||||
snprintf(buffer.get(), size, replaceWithIt->second.c_str(), replaceArg.c_str());
|
||||
buffer[size - 1] = '\0';
|
||||
|
||||
output << buffer.get() << "\n";
|
||||
}
|
||||
else {
|
||||
output << line << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return output.str();
|
||||
}
|
||||
|
||||
static SCP_vector<SCP_string>
|
||||
opengl_get_shader_content(shader_type type_id, const char* filename, int flags, bool has_geo_shader, bool spirv_shader)
|
||||
{
|
||||
SCP_vector<SCP_string> parts;
|
||||
if (spirv_shader) {
|
||||
// No need to add a header here or handle includes since the original compiler did that
|
||||
parts.push_back(opengl_load_shader(filename));
|
||||
parts.push_back(shader_load_source(filename));
|
||||
} else {
|
||||
parts.push_back(opengl_shader_get_header(type_id, flags, has_geo_shader));
|
||||
|
||||
parts.push_back(handle_predefines(filename, handle_includes(filename, opengl_load_shader(filename))));
|
||||
parts.push_back(shader_preprocess_defines(filename, shader_preprocess_includes(filename, shader_load_source(filename))));
|
||||
}
|
||||
|
||||
return parts;
|
||||
@@ -823,9 +438,9 @@ static void opengl_set_default_uniforms(const opengl_shader_t& sdr) {
|
||||
|
||||
void opengl_compile_shader_actual(shader_type sdr, const uint &flags, opengl_shader_t &new_shader)
|
||||
{
|
||||
opengl_shader_type_t *sdr_info = &GL_shader_types[sdr];
|
||||
const ShaderTypeInfo *sdr_info = shader_get_type_info(sdr);
|
||||
|
||||
Assert(sdr_info->type_id == sdr);
|
||||
Assert(sdr_info != nullptr);
|
||||
nprintf(("shaders","Compiling new shader:\n"));
|
||||
nprintf(("shaders"," %s\n", sdr_info->description));
|
||||
|
||||
@@ -833,27 +448,24 @@ void opengl_compile_shader_actual(shader_type sdr, const uint &flags, opengl_sha
|
||||
bool use_geo_sdr = false;
|
||||
|
||||
// do we even have a geometry shader?
|
||||
if (sdr_info->geo != NULL) {
|
||||
for (int i = 0; i < GL_num_shader_variants; ++i) {
|
||||
opengl_shader_variant_t *variant = &GL_shader_variants[i];
|
||||
|
||||
if (variant->type_id == sdr && flags & variant->flag && variant->use_geometry_sdr) {
|
||||
if (sdr_info->geo != nullptr) {
|
||||
shader_for_each_active_variant(sdr, flags, [&](const ShaderVariantInfo& variant) {
|
||||
if (variant.use_geometry_sdr) {
|
||||
use_geo_sdr = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto vert_content =
|
||||
opengl_get_shader_content(sdr_info->type_id, sdr_info->vert, flags, use_geo_sdr, sdr_info->spirv_shader);
|
||||
opengl_get_shader_content(sdr, sdr_info->vert, flags, use_geo_sdr, sdr_info->spirv_shader);
|
||||
auto frag_content =
|
||||
opengl_get_shader_content(sdr_info->type_id, sdr_info->frag, flags, use_geo_sdr, sdr_info->spirv_shader);
|
||||
opengl_get_shader_content(sdr, sdr_info->frag, flags, use_geo_sdr, sdr_info->spirv_shader);
|
||||
SCP_vector<SCP_string> geom_content;
|
||||
|
||||
if (use_geo_sdr) {
|
||||
// read geometry shader
|
||||
geom_content =
|
||||
opengl_get_shader_content(sdr_info->type_id, sdr_info->geo, flags, use_geo_sdr, sdr_info->spirv_shader);
|
||||
opengl_get_shader_content(sdr, sdr_info->geo, flags, use_geo_sdr, sdr_info->spirv_shader);
|
||||
}
|
||||
|
||||
auto shader_hash = get_shader_hash(vert_content, geom_content, frag_content);
|
||||
@@ -870,7 +482,7 @@ void opengl_compile_shader_actual(shader_type sdr, const uint &flags, opengl_sha
|
||||
|
||||
for (size_t i = 0; i < GL_vertex_attrib_info.size(); ++i) {
|
||||
// Check that the enum values match the position in the vector to make accessing that information more efficient
|
||||
Assertion(GL_vertex_attrib_info[i].attribute_id == (int)i, "Mistmatch between enum values and attribute vector detected!");
|
||||
Assertion(GL_vertex_attrib_info[i].attribute_id == i, "Mistmatch between enum values and attribute vector detected!");
|
||||
|
||||
// assign vert attribute binding locations before we link the shader
|
||||
glBindAttribLocation(program->getShaderHandle(), (GLint)i, GL_vertex_attrib_info[i].name.c_str());
|
||||
@@ -898,7 +510,7 @@ void opengl_compile_shader_actual(shader_type sdr, const uint &flags, opengl_sha
|
||||
cache_program_binary(program->getShaderHandle(), shader_hash);
|
||||
}
|
||||
|
||||
new_shader.shader = sdr_info->type_id;
|
||||
new_shader.shader = sdr;
|
||||
new_shader.flags = flags;
|
||||
new_shader.program = std::move(program);
|
||||
|
||||
@@ -919,19 +531,13 @@ void opengl_compile_shader_actual(shader_type sdr, const uint &flags, opengl_sha
|
||||
|
||||
nprintf(("shaders","Shader Variant Features:\n"));
|
||||
|
||||
// initialize all uniforms and attributes that are specific to this variant
|
||||
for (int i = 0; i < GL_num_shader_variants; ++i) {
|
||||
opengl_shader_variant_t &variant = GL_shader_variants[i];
|
||||
|
||||
if (sdr_info->type_id == variant.type_id && variant.flag & flags) {
|
||||
for (auto& attr : variant.attributes) {
|
||||
auto& attr_info = GL_vertex_attrib_info[attr];
|
||||
new_shader.program->initAttribute(attr_info.name, attr_info.default_value);
|
||||
}
|
||||
|
||||
nprintf(("shaders"," %s\n", variant.description));
|
||||
// initialize extra attributes from active variants
|
||||
shader_for_each_active_variant(sdr, flags, [&](const ShaderVariantInfo& v) {
|
||||
for (auto& attr : v.attributes) {
|
||||
new_shader.program->initAttribute(GL_vertex_attrib_info[attr].name, GL_vertex_attrib_info[attr].default_value);
|
||||
}
|
||||
}
|
||||
nprintf(("shaders"," %s\n", v.description));
|
||||
});
|
||||
|
||||
opengl_set_default_uniforms(new_shader);
|
||||
}
|
||||
@@ -1116,8 +722,8 @@ void opengl_shader_set_default_material(bool textured, bool alpha, vec4* clr, fl
|
||||
{
|
||||
Current_shader->program->Uniforms.setTextureUniform("baseMap", 0);
|
||||
|
||||
opengl_set_generic_uniform_data<genericData_default_material_vert>(
|
||||
[=](genericData_default_material_vert* data) {
|
||||
opengl_set_generic_uniform_data<genericData_default_material_v_sdr>(
|
||||
[=](genericData_default_material_v_sdr* data) {
|
||||
if (textured) {
|
||||
data->noTexturing = 0;
|
||||
data->baseMapIndex = array_index;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/shader_types.h"
|
||||
#include "graphics/material.h"
|
||||
#include "graphics/opengl/gropengl.h"
|
||||
#include "graphics/util/UniformBuffer.h"
|
||||
@@ -26,18 +27,19 @@ class ShaderProgram;
|
||||
enum shader_stage { SDR_STAGE_VERTEX, SDR_STAGE_FRAGMENT, SDR_STAGE_GEOMETRY };
|
||||
|
||||
struct opengl_vert_attrib {
|
||||
enum attrib_id {
|
||||
POSITION,
|
||||
COLOR,
|
||||
TEXCOORD,
|
||||
NORMAL,
|
||||
TANGENT,
|
||||
MODEL_ID,
|
||||
RADIUS,
|
||||
UVEC,
|
||||
MODEL_MATRIX,
|
||||
NUM_ATTRIBS,
|
||||
};
|
||||
// Attribute location enum — aliases the shared VertexAttributeLocation enum
|
||||
// from shader_types.h.
|
||||
using attrib_id = VertexAttributeLocation;
|
||||
static constexpr attrib_id POSITION = VATTRIB_POSITION;
|
||||
static constexpr attrib_id COLOR = VATTRIB_COLOR;
|
||||
static constexpr attrib_id TEXCOORD = VATTRIB_TEXCOORD;
|
||||
static constexpr attrib_id NORMAL = VATTRIB_NORMAL;
|
||||
static constexpr attrib_id TANGENT = VATTRIB_TANGENT;
|
||||
static constexpr attrib_id MODEL_ID = VATTRIB_MODELID;
|
||||
static constexpr attrib_id RADIUS = VATTRIB_RADIUS;
|
||||
static constexpr attrib_id UVEC = VATTRIB_UVEC;
|
||||
static constexpr attrib_id MODEL_MATRIX = VATTRIB_MODEL_MATRIX;
|
||||
static constexpr attrib_id NUM_ATTRIBS = NUM_VERTEX_ATTRIBS;
|
||||
|
||||
attrib_id attribute_id;
|
||||
SCP_string name;
|
||||
@@ -60,33 +62,6 @@ struct geometry_sdr_params
|
||||
int vertices_out;
|
||||
};
|
||||
|
||||
struct opengl_shader_type_t {
|
||||
shader_type type_id;
|
||||
|
||||
const char *vert;
|
||||
const char *frag;
|
||||
const char *geo;
|
||||
|
||||
SCP_vector<opengl_vert_attrib::attrib_id> attributes;
|
||||
|
||||
const char* description;
|
||||
|
||||
bool spirv_shader; // Specified if this shader was generated from SPIR-V
|
||||
};
|
||||
|
||||
struct opengl_shader_variant_t {
|
||||
shader_type type_id;
|
||||
|
||||
bool use_geometry_sdr;
|
||||
|
||||
int flag;
|
||||
SCP_string flag_text;
|
||||
|
||||
SCP_vector<opengl_vert_attrib::attrib_id> attributes;
|
||||
|
||||
const char* description;
|
||||
};
|
||||
|
||||
struct opengl_shader_file_t {
|
||||
const char *vert;
|
||||
const char *frag;
|
||||
|
||||
@@ -421,30 +421,26 @@ static int opengl_texture_set_level(int bitmap_handle, int bitmap_type, int bmap
|
||||
}
|
||||
|
||||
// check for compressed image types
|
||||
auto block_size = 0;
|
||||
auto bm_handle = bm_is_compressed(bitmap_handle);
|
||||
switch (bm_handle) {
|
||||
auto bm_type = bm_is_compressed(bitmap_handle);
|
||||
auto block_size = dds_block_size(bm_type);
|
||||
switch (bm_type) {
|
||||
case DDS_DXT1:
|
||||
case DDS_CUBEMAP_DXT1:
|
||||
intFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||||
block_size = 8;
|
||||
break;
|
||||
|
||||
case DDS_DXT3:
|
||||
case DDS_CUBEMAP_DXT3:
|
||||
intFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
block_size = 16;
|
||||
break;
|
||||
|
||||
case DDS_DXT5:
|
||||
case DDS_CUBEMAP_DXT5:
|
||||
intFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
block_size = 16;
|
||||
break;
|
||||
|
||||
case DDS_BC7:
|
||||
intFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
|
||||
block_size = 16;
|
||||
break;
|
||||
|
||||
case KTX_ETC2_RGB:
|
||||
@@ -453,7 +449,7 @@ static int opengl_texture_set_level(int bitmap_handle, int bitmap_type, int bmap
|
||||
case KTX_ETC2_SRGBA_EAC:
|
||||
case KTX_ETC2_RGB_A1:
|
||||
case KTX_ETC2_SRGB_A1:
|
||||
intFormat = ktx_map_ktx_format_to_gl_internal(bm_handle);
|
||||
intFormat = ktx_map_ktx_format_to_gl_internal(bm_type);
|
||||
block_size = ktx_etc_block_size(intFormat);
|
||||
break;
|
||||
}
|
||||
@@ -474,8 +470,7 @@ static int opengl_texture_set_level(int bitmap_handle, int bitmap_type, int bmap
|
||||
auto mipmap_h = bmap_h;
|
||||
|
||||
for (auto i = 0; i < mipmap_levels + base_level; i++) {
|
||||
// size of data block (4x4)
|
||||
dsize = ((mipmap_h + 3) / 4) * ((mipmap_w + 3) / 4) * block_size;
|
||||
dsize = static_cast<GLsizei>(dds_compressed_mip_size(mipmap_w, mipmap_h, block_size));
|
||||
|
||||
if (i >= base_level) {
|
||||
glCompressedTexSubImage3D(tSlot->texture_target, i - base_level, 0, 0, tSlot->array_index, mipmap_w,
|
||||
@@ -601,8 +596,7 @@ static int opengl_texture_set_level(int bitmap_handle, int bitmap_type, int bmap
|
||||
// check if it's a compressed cubemap first
|
||||
if (block_size > 0) {
|
||||
for (auto level = 0; level < mipmap_levels + base_level; level++) {
|
||||
// size of data block (4x4)
|
||||
dsize = ((mipmap_h + 3) / 4) * ((mipmap_w + 3) / 4) * block_size;
|
||||
dsize = static_cast<GLsizei>(dds_compressed_mip_size(mipmap_w, mipmap_h, block_size));
|
||||
|
||||
if (level >= base_level) {
|
||||
// We skipped ahead to the base level so we can start uploading frames now
|
||||
@@ -1240,7 +1234,7 @@ int gr_opengl_tcache_set(int bitmap_handle, int bitmap_type, float *u_scale, flo
|
||||
|
||||
void opengl_preload_init()
|
||||
{
|
||||
if (gr_screen.mode != GR_OPENGL)
|
||||
if (gr_screen.mode != GraphicsAPI::OpenGL)
|
||||
return;
|
||||
|
||||
// opengl_tcache_flush ();
|
||||
@@ -1251,7 +1245,7 @@ int gr_opengl_preload(int bitmap_num, int is_aabitmap)
|
||||
float u_scale, v_scale;
|
||||
int retval;
|
||||
|
||||
Assert( gr_screen.mode == GR_OPENGL );
|
||||
Assert( gr_screen.mode == GraphicsAPI::OpenGL );
|
||||
|
||||
if ( !GL_should_preload ) {
|
||||
return 0;
|
||||
|
||||
@@ -77,7 +77,6 @@ static opengl_vertex_bind GL_array_binding_data[] =
|
||||
{ vertex_format_data::POSITION4, 4, GL_FLOAT, GL_FALSE, opengl_vert_attrib::POSITION },
|
||||
{ vertex_format_data::POSITION3, 3, GL_FLOAT, GL_FALSE, opengl_vert_attrib::POSITION },
|
||||
{ vertex_format_data::POSITION2, 2, GL_FLOAT, GL_FALSE, opengl_vert_attrib::POSITION },
|
||||
{ vertex_format_data::SCREEN_POS, 2, GL_INT, GL_FALSE, opengl_vert_attrib::POSITION },
|
||||
{ vertex_format_data::COLOR3, 3, GL_UNSIGNED_BYTE, GL_TRUE, opengl_vert_attrib::COLOR },
|
||||
{ vertex_format_data::COLOR4, 4, GL_UNSIGNED_BYTE, GL_TRUE, opengl_vert_attrib::COLOR },
|
||||
{ vertex_format_data::COLOR4F, 4, GL_FLOAT, GL_FALSE, opengl_vert_attrib::COLOR },
|
||||
@@ -371,8 +370,10 @@ void gr_opengl_delete_buffer(gr_buffer_handle handle)
|
||||
glDeleteBuffers(1, &buffer_obj.buffer_id);
|
||||
}
|
||||
|
||||
gr_buffer_handle gr_opengl_create_buffer(BufferType type, BufferUsageHint usage)
|
||||
gr_buffer_handle gr_opengl_create_buffer(BufferType type, BufferUsageHint usage, bool /*rt_capable*/)
|
||||
{
|
||||
// rt_capable is a Vulkan-only concept (acceleration structure build input
|
||||
// usage flags); OpenGL has no raytracing backend, so it is ignored here.
|
||||
return opengl_create_buffer_object(convertBufferType(type), convertUsageHint(usage), usage);
|
||||
}
|
||||
|
||||
@@ -1003,11 +1004,6 @@ void opengl_tnl_set_model_material(model_material *material_info)
|
||||
if ( material_info->is_batched() ) {
|
||||
GL_state.Texture.Enable(10, GL_TEXTURE_BUFFER, opengl_get_transform_buffer_texture());
|
||||
}
|
||||
|
||||
if ( Deferred_lighting ) {
|
||||
// don't blend if we're drawing to the g-buffers
|
||||
GL_state.SetAlphaBlendMode(ALPHA_BLEND_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void opengl_tnl_set_material_particle(particle_material * material_info)
|
||||
@@ -1332,4 +1328,4 @@ void opengl_bind_vertex_layout_multiple(vertex_layout &layout, const SCP_vector<
|
||||
i++;
|
||||
}
|
||||
GL_state.Array.BindElementBuffer(indexBuffer);
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ struct opengl_vertex_bind {
|
||||
opengl_vert_attrib::attrib_id attribute_id;
|
||||
};
|
||||
|
||||
gr_buffer_handle gr_opengl_create_buffer(BufferType type, BufferUsageHint usage);
|
||||
gr_buffer_handle gr_opengl_create_buffer(BufferType type, BufferUsageHint usage, bool rt_capable);
|
||||
|
||||
void opengl_bind_buffer_object(gr_buffer_handle handle);
|
||||
void gr_opengl_update_buffer_data(gr_buffer_handle handle, size_t size, const void* data);
|
||||
|
||||
@@ -260,7 +260,7 @@ void PostProcessingManager::setBloomShadersOk(bool ok)
|
||||
|
||||
bool gr_lightshafts_enabled()
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ bool gr_lightshafts_enabled()
|
||||
|
||||
bool gr_sunglare_enabled()
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ bool gr_sunglare_enabled()
|
||||
|
||||
int gr_bloom_intensity()
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ int gr_bloom_intensity()
|
||||
|
||||
void gr_set_bloom_intensity(int intensity)
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+28
-27
@@ -36,17 +36,18 @@ static void gr_flash_internal(int r, int g, int b, int a, bool alpha_flash)
|
||||
render_material.set_blend_mode(ALPHA_BLEND_ALPHA_ADDITIVE);
|
||||
}
|
||||
|
||||
int glVertices[8] = { x1, y1, x1, y2, x2, y1, x2, y2 };
|
||||
float glVertices[8] = { (float)x1, (float)y1, (float)x1, (float)y2,
|
||||
(float)x2, (float)y1, (float)x2, (float)y2 };
|
||||
|
||||
vertex_layout vert_def;
|
||||
|
||||
vert_def.add_vertex_component(vertex_format_data::SCREEN_POS, sizeof(int) * 2, 0);
|
||||
vert_def.add_vertex_component(vertex_format_data::POSITION2, sizeof(float) * 2, 0);
|
||||
|
||||
gr_render_primitives_2d_immediate(&render_material, PRIM_TYPE_TRISTRIP, &vert_def, 4, glVertices, sizeof(int) * 8);
|
||||
gr_render_primitives_2d_immediate(&render_material, PRIM_TYPE_TRISTRIP, &vert_def, 4, glVertices, sizeof(float) * 8);
|
||||
}
|
||||
|
||||
void gr_flash(int r, int g, int b) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,7 +59,7 @@ void gr_flash(int r, int g, int b) {
|
||||
}
|
||||
|
||||
void gr_flash_alpha(int r, int g, int b, int a) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -166,7 +167,7 @@ static void bitmap_ex_internal(int x,
|
||||
}
|
||||
|
||||
void gr_aabitmap(int x, int y, int resize_mode, bool mirror, float scale_factor) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -253,7 +254,7 @@ void gr_aabitmap(int x, int y, int resize_mode, bool mirror, float scale_factor)
|
||||
scale_factor);
|
||||
}
|
||||
void gr_aabitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode, bool mirror, float scale_factor) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -405,7 +406,7 @@ void gr_aabitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode,
|
||||
}
|
||||
//these are penguins bitmap functions
|
||||
void gr_bitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode, bool mirror, float scale_factor) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -792,7 +793,7 @@ void endDrawing(graphics::paths::PathRenderer* path) {
|
||||
|
||||
void gr_string(float sx, float sy, const char* s, int resize_mode, float scaleMultiplier, size_t in_length)
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -995,7 +996,7 @@ static void gr_line(float x1, float y1, float x2, float y2, int resize_mode) {
|
||||
}
|
||||
|
||||
void gr_line(int x1, int y1, int x2, int y2, int resize_mode) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1003,7 +1004,7 @@ void gr_line(int x1, int y1, int x2, int y2, int resize_mode) {
|
||||
}
|
||||
|
||||
void gr_aaline(vertex* v1, vertex* v2) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1017,7 +1018,7 @@ void gr_aaline(vertex* v1, vertex* v2) {
|
||||
}
|
||||
|
||||
void gr_gradient(int x1, int y1, int x2, int y2, int resize_mode) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1043,7 +1044,7 @@ void gr_gradient(int x1, int y1, int x2, int y2, int resize_mode) {
|
||||
endDrawing(path);
|
||||
}
|
||||
void gr_pixel(int x, int y, int resize_mode) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1051,7 +1052,7 @@ void gr_pixel(int x, int y, int resize_mode) {
|
||||
}
|
||||
|
||||
void gr_circle(int xc, int yc, int d, int resize_mode) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1064,7 +1065,7 @@ void gr_circle(int xc, int yc, int d, int resize_mode) {
|
||||
endDrawing(path);
|
||||
}
|
||||
void gr_unfilled_circle(int xc, int yc, int d, int resize_mode) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1077,7 +1078,7 @@ void gr_unfilled_circle(int xc, int yc, int d, int resize_mode) {
|
||||
endDrawing(path);
|
||||
}
|
||||
void gr_arc(int xc, int yc, float r, float angle_start, float angle_end, bool fill, int resize_mode) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1107,7 +1108,7 @@ void gr_arc(int xc, int yc, float r, float angle_start, float angle_end, bool fi
|
||||
endDrawing(path);
|
||||
}
|
||||
void gr_curve(int xc, int yc, int r, int direction, int resize_mode) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1158,7 +1159,7 @@ void gr_curve(int xc, int yc, int r, int direction, int resize_mode) {
|
||||
}
|
||||
|
||||
void gr_rect(int x, int y, int w, int h, int resize_mode, float angle) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1179,7 +1180,7 @@ void gr_rect(int x, int y, int w, int h, int resize_mode, float angle) {
|
||||
}
|
||||
|
||||
void gr_shade(int x, int y, int w, int h, int resize_mode) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1201,7 +1202,7 @@ void gr_shade(int x, int y, int w, int h, int resize_mode) {
|
||||
}
|
||||
|
||||
void gr_2d_start_buffer() {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1214,7 +1215,7 @@ void gr_2d_start_buffer() {
|
||||
}
|
||||
|
||||
void gr_2d_stop_buffer() {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1232,7 +1233,7 @@ static size_t immediate_buffer_size = 0;
|
||||
static const size_t IMMEDIATE_BUFFER_RESIZE_BLOCK_SIZE = 2048;
|
||||
|
||||
size_t gr_add_to_immediate_buffer(size_t size, void* data) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1262,7 +1263,7 @@ size_t gr_add_to_immediate_buffer(size_t size, void* data) {
|
||||
return old_offset;
|
||||
}
|
||||
void gr_reset_immediate_buffer() {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1284,7 +1285,7 @@ void gr_render_primitives_immediate(material* material_info,
|
||||
int n_verts,
|
||||
void* data,
|
||||
size_t size) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1300,7 +1301,7 @@ void gr_render_primitives_2d_immediate(material* material_info,
|
||||
void* data,
|
||||
size_t size)
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1457,7 +1458,7 @@ static void draw_bitmap_list(bitmap_rect_list* list, int n_bm, int resize_mode,
|
||||
|
||||
void gr_bitmap_list(bitmap_rect_list* list, int n_bm, int resize_mode, float angle)
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1472,7 +1473,7 @@ void gr_bitmap_list(bitmap_rect_list* list, int n_bm, int resize_mode, float ang
|
||||
|
||||
void gr_aabitmap_list(bitmap_rect_list* list, int n_bm, int resize_mode, float angle)
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
if (gr_screen.mode == GraphicsAPI::Stub) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
#include "graphics/shader_preprocess.h"
|
||||
|
||||
#include "cfile/cfile.h"
|
||||
#include "def_files/def_files.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
|
||||
static void handle_includes_impl(SCP_vector<SCP_string>& include_stack,
|
||||
SCP_stringstream& output,
|
||||
int& include_counter,
|
||||
const SCP_string& filename,
|
||||
const SCP_string& original)
|
||||
{
|
||||
include_stack.emplace_back(filename);
|
||||
auto current_source_number = include_counter + 1;
|
||||
|
||||
const char* INCLUDE_STRING = "#include";
|
||||
const char* CONDITIONAL_INCLUDE_STRING = "#conditional_include";
|
||||
SCP_stringstream input(original);
|
||||
|
||||
int line_num = 1;
|
||||
for (SCP_string line; std::getline(input, line);) {
|
||||
auto include_start = line.find(CONDITIONAL_INCLUDE_STRING);
|
||||
|
||||
if (include_start != SCP_string::npos) {
|
||||
include_start += strlen(CONDITIONAL_INCLUDE_STRING) + 1;
|
||||
bool require_capability = true;
|
||||
|
||||
switch (line.at(include_start)) {
|
||||
case '+':
|
||||
require_capability = true;
|
||||
break;
|
||||
case '-':
|
||||
require_capability = false;
|
||||
break;
|
||||
default:
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed conditional_include line. Expected + or -, got %c.",
|
||||
filename.c_str(), line_num, line.at(include_start));
|
||||
break;
|
||||
}
|
||||
|
||||
auto first_quote = line.find('"', include_start);
|
||||
auto second_quote = line.find('"', first_quote + 1);
|
||||
|
||||
if (first_quote == SCP_string::npos || second_quote == SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed conditional_include line. Could not find both quote characters for capability.",
|
||||
filename.c_str(), line_num);
|
||||
}
|
||||
auto condition = line.substr(first_quote + 1, second_quote - first_quote - 1);
|
||||
auto capability = std::find_if(&gr_capabilities[0], &gr_capabilities[gr_capabilities_num],
|
||||
[condition](const gr_capability_def& ext_pair) {
|
||||
return !stricmp(ext_pair.parse_name, condition.c_str());
|
||||
});
|
||||
if (capability == &gr_capabilities[gr_capabilities_num]) {
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed conditional_include line. Capability %s does not exist.",
|
||||
filename.c_str(), line_num, condition.c_str());
|
||||
}
|
||||
|
||||
if (gr_is_capable(capability->capability) == require_capability)
|
||||
include_start = second_quote + 1 - strlen(INCLUDE_STRING);
|
||||
else
|
||||
include_start = SCP_string::npos - 1;
|
||||
} else {
|
||||
include_start = line.find(INCLUDE_STRING);
|
||||
}
|
||||
|
||||
if (include_start != SCP_string::npos && include_start != SCP_string::npos - 1) {
|
||||
auto first_quote = line.find('"', include_start + strlen(INCLUDE_STRING));
|
||||
auto second_quote = line.find('"', first_quote + 1);
|
||||
|
||||
if (first_quote == SCP_string::npos || second_quote == SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed include line. Could not find both quote characters.",
|
||||
filename.c_str(), line_num);
|
||||
}
|
||||
|
||||
auto file_name = line.substr(first_quote + 1, second_quote - first_quote - 1);
|
||||
auto existing_name =
|
||||
std::find_if(include_stack.begin(), include_stack.end(),
|
||||
[&file_name](const SCP_string& str) { return str == file_name; });
|
||||
if (existing_name != include_stack.end()) {
|
||||
SCP_stringstream stack_string;
|
||||
for (auto& name : include_stack) {
|
||||
stack_string << "\t" << name << "\n";
|
||||
}
|
||||
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Detected cyclic include! Previous includes (top level file first):\n%s",
|
||||
filename.c_str(), line_num, stack_string.str().c_str());
|
||||
}
|
||||
|
||||
++include_counter;
|
||||
output << "#line 1 " << include_counter + 1 << "\n";
|
||||
|
||||
handle_includes_impl(include_stack, output, include_counter, file_name,
|
||||
shader_load_source(file_name));
|
||||
|
||||
output << "#line " << line_num + 1 << " " << current_source_number << "\n";
|
||||
} else if (include_start != SCP_string::npos - 1) {
|
||||
output << line << "\n";
|
||||
}
|
||||
|
||||
++line_num;
|
||||
}
|
||||
|
||||
include_stack.pop_back();
|
||||
}
|
||||
|
||||
SCP_string shader_load_source(const SCP_string& filename)
|
||||
{
|
||||
SCP_string content;
|
||||
|
||||
// Check external shaders first (modding support)
|
||||
if (Enable_external_shaders) {
|
||||
CFILE* cf_shader = cfopen(filename.c_str(), "rt", CF_TYPE_EFFECTS);
|
||||
if (cf_shader != nullptr) {
|
||||
int len = cfilelength(cf_shader);
|
||||
content.resize(len);
|
||||
cfread(content.data(), len + 1, 1, cf_shader);
|
||||
cfclose(cf_shader);
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to embedded defaults
|
||||
auto def_shader = defaults_get_file(filename.c_str());
|
||||
if (def_shader.data != nullptr && def_shader.size > 0) {
|
||||
content.assign(reinterpret_cast<const char*>(def_shader.data), def_shader.size);
|
||||
} else {
|
||||
mprintf(("shader_load_source: Could not load shader source: %s\n", filename.c_str()));
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
SCP_string shader_preprocess_includes(const SCP_string& filename, const SCP_string& source)
|
||||
{
|
||||
SCP_stringstream output;
|
||||
SCP_vector<SCP_string> include_stack;
|
||||
auto include_counter = 0;
|
||||
|
||||
handle_includes_impl(include_stack, output, include_counter, filename, source);
|
||||
|
||||
return output.str();
|
||||
}
|
||||
|
||||
SCP_string shader_preprocess_defines(const SCP_string& filename, const SCP_string& source)
|
||||
{
|
||||
SCP_stringstream output;
|
||||
SCP_unordered_map<SCP_string, SCP_string> defines;
|
||||
|
||||
//In any shader, define GLOBAL_FAR_Z
|
||||
output << "#define GLOBAL_FAR_Z " << std::fixed << std::setprecision(2) << Max_draw_distance << std::defaultfloat << '\n';
|
||||
|
||||
const char* PREDEFINE_STRING = "#predefine";
|
||||
const char* PREREPLACE_STRING = "#prereplace";
|
||||
|
||||
SCP_stringstream input(source);
|
||||
for (SCP_string line; std::getline(input, line);) {
|
||||
auto predefine_start = line.find(PREDEFINE_STRING);
|
||||
auto prereplace_start = line.find(PREREPLACE_STRING);
|
||||
|
||||
if (predefine_start != SCP_string::npos) {
|
||||
predefine_start += strlen(PREDEFINE_STRING);
|
||||
|
||||
auto token_start = line.find(' ', predefine_start);
|
||||
auto token_end = line.find(' ', token_start + 1);
|
||||
|
||||
if (token_start == SCP_string::npos || token_end == SCP_string::npos) {
|
||||
Error(LOCATION, "Shader %s: Malformed predefine line. Could not find define token.",
|
||||
filename.c_str());
|
||||
}
|
||||
|
||||
auto token = line.substr(token_start + 1, token_end - token_start - 1);
|
||||
auto replaceWith = line.substr(token_end + 1);
|
||||
|
||||
auto replaceStrToken = replaceWith.find("%s");
|
||||
if (replaceStrToken == SCP_string::npos ||
|
||||
replaceWith.find("%s", replaceStrToken + 1) != SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed predefine line. Replacing string must have exactly one %%s.",
|
||||
filename.c_str());
|
||||
}
|
||||
if (defines.find(token) != defines.end()) {
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed predefine line. Token %s is already defined.",
|
||||
filename.c_str(), token.c_str());
|
||||
}
|
||||
|
||||
defines.emplace(std::move(token), std::move(replaceWith));
|
||||
|
||||
output << "\n"; // Preserve line count
|
||||
} else if (prereplace_start != SCP_string::npos) {
|
||||
prereplace_start += strlen(PREREPLACE_STRING);
|
||||
|
||||
auto token_start = line.find(' ', prereplace_start);
|
||||
auto token_end = line.find(' ', token_start + 1);
|
||||
|
||||
if (token_start == SCP_string::npos || token_end == SCP_string::npos) {
|
||||
Error(LOCATION, "Shader %s: Malformed prereplace line. Could not find define token.",
|
||||
filename.c_str());
|
||||
}
|
||||
|
||||
auto token = line.substr(token_start + 1, token_end - token_start - 1);
|
||||
auto replaceArg = line.substr(token_end + 1);
|
||||
|
||||
auto replaceWithIt = defines.find(token);
|
||||
if (replaceWithIt == defines.end()) {
|
||||
Error(LOCATION, "Shader %s: Malformed prereplace line. Could not find token %s.",
|
||||
filename.c_str(), token.c_str());
|
||||
}
|
||||
|
||||
size_t size = replaceWithIt->second.length() - 1 + replaceArg.size();
|
||||
std::unique_ptr<char[]> buffer = make_unique<char[]>(size);
|
||||
|
||||
snprintf(buffer.get(), size, replaceWithIt->second.c_str(), replaceArg.c_str());
|
||||
buffer[size - 1] = '\0';
|
||||
|
||||
output << buffer.get() << "\n";
|
||||
} else {
|
||||
output << line << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return output.str();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
SCP_string shader_load_source(const SCP_string& filename);
|
||||
SCP_string shader_preprocess_includes(const SCP_string& filename, const SCP_string& source);
|
||||
SCP_string shader_preprocess_defines(const SCP_string& filename, const SCP_string& source);
|
||||
@@ -0,0 +1,304 @@
|
||||
#include "graphics/shader_types.h"
|
||||
|
||||
#include "graphics/shadows.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
|
||||
// Pull in MODEL_SDR_FLAG_* constants for the variant table
|
||||
#define MODEL_SDR_FLAG_MODE_CPP
|
||||
#include "def_files/data/effects/model_shader_flags.h"
|
||||
#undef MODEL_SDR_FLAG_MODE_CPP
|
||||
#undef SDR_FLAG
|
||||
|
||||
// ========== Shared shader type table ==========
|
||||
// Moved from gropenglshader.cpp — single source of truth for both backends.
|
||||
// clang-format off
|
||||
static ShaderTypeInfo SHADER_TYPES[] = {
|
||||
{ SDR_TYPE_MODEL, "main-v.sdr", "main-f.sdr", "main-g.sdr",
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD, VATTRIB_NORMAL, VATTRIB_TANGENT, VATTRIB_MODELID }, "Model Rendering", false },
|
||||
|
||||
{ SDR_TYPE_EFFECT_PARTICLE, "effect-v.sdr", "effect-f.sdr", "effect-g.sdr",
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD, VATTRIB_RADIUS, VATTRIB_COLOR }, "Particle Effects", false },
|
||||
|
||||
{ SDR_TYPE_EFFECT_DISTORTION, "effect-distort-v.sdr", "effect-distort-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD, VATTRIB_RADIUS, VATTRIB_COLOR }, "Distortion Effects", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_MAIN, "post-v.sdr", "post-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Post Processing", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_BLUR, "post-v.sdr", "blur-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Gaussian Blur", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_BLOOM_COMP, "post-v.sdr", "bloom-comp-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Bloom Compositing", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_BRIGHTPASS, "post-v.sdr", "brightpass-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Bloom Brightpass", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_FXAA, "fxaa-v.sdr", "fxaa-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION }, "FXAA", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_FXAA_PREPASS, "post-v.sdr", "fxaapre-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "FXAA Prepass", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_LIGHTSHAFTS, "post-v.sdr", "ls-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Lightshafts", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_TONEMAPPING, "post-v.sdr", "tonemapping-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Tonemapping", false },
|
||||
|
||||
{ SDR_TYPE_DEFERRED_LIGHTING, "deferred-v.sdr", "deferred-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION }, "Deferred Lighting", false },
|
||||
|
||||
{ SDR_TYPE_DEFERRED_CLEAR, "deferred-clear-v.sdr", "deferred-clear-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION }, "Clear Deferred Lighting Buffer", false },
|
||||
|
||||
{ SDR_TYPE_VIDEO_PROCESS, "video-v.sdr", "video-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Video Playback", false },
|
||||
|
||||
{ SDR_TYPE_PASSTHROUGH_RENDER, "passthrough-v.sdr", "passthrough-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD, VATTRIB_COLOR }, "Passthrough", false },
|
||||
|
||||
{ SDR_TYPE_SHIELD_DECAL, "shield-impact-v.sdr", "shield-impact-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_NORMAL }, "Shield Decals", false },
|
||||
|
||||
{ SDR_TYPE_BATCHED_BITMAP, "batched-v.sdr", "batched-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD, VATTRIB_COLOR }, "Batched bitmaps", false },
|
||||
|
||||
{ SDR_TYPE_DEFAULT_MATERIAL, "default-material-v.sdr", "default-material-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD, VATTRIB_COLOR }, "Default material", false },
|
||||
|
||||
{ SDR_TYPE_NANOVG, "nanovg-v.sdr", "nanovg-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "NanoVG shader", false },
|
||||
|
||||
{ SDR_TYPE_DECAL, "decal-v.sdr", "decal-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_MODEL_MATRIX }, "Decal rendering", false },
|
||||
|
||||
{ SDR_TYPE_SCENE_FOG, "post-v.sdr", "fog-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Scene fogging", false },
|
||||
|
||||
{ SDR_TYPE_VOLUMETRIC_FOG, "post-v.sdr", "volumetric-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Volumetric fogging", false },
|
||||
|
||||
{ SDR_TYPE_ROCKET_UI, "rocketui-v.sdr", "rocketui-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_COLOR, VATTRIB_TEXCOORD }, "libRocket UI", false },
|
||||
|
||||
{ SDR_TYPE_COPY, "post-v.sdr", "copy-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Texture copy", false },
|
||||
|
||||
{ SDR_TYPE_COPY_WORLD, "passthrough-v.sdr", "copy-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Texture copy world space", false },
|
||||
|
||||
{ SDR_TYPE_MSAA_RESOLVE, "post-v.sdr", "msaa-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "MSAA resolve shader", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_SMAA_EDGE, "smaa-edge-v.sdr", "smaa-edge-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "SMAA Edge detection", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_SMAA_BLENDING_WEIGHT, "smaa-blend-v.sdr", "smaa-blend-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "SMAA Blending weight calculation", false },
|
||||
|
||||
{ SDR_TYPE_POST_PROCESS_SMAA_NEIGHBORHOOD_BLENDING, "smaa-neighbour-v.sdr", "smaa-neighbour-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "SMAA Neighborhood Blending", false },
|
||||
|
||||
// Vulkan-only: copies the SMAA neighborhood-blend result back into Scene_ldr
|
||||
// (OpenGL does the equivalent copy directly via opengl_shader_set_passthrough).
|
||||
{ SDR_TYPE_POST_PROCESS_SMAA_RESOLVE, "post-v.sdr", "smaa-resolve-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "SMAA Resolve", false },
|
||||
|
||||
{ SDR_TYPE_ENVMAP_SPHERE_WARP, "post-v.sdr", "envmap-sphere-warp-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Environment Map Export", false },
|
||||
|
||||
{ SDR_TYPE_IRRADIANCE_MAP_GEN, "post-v.sdr", "irrmap-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Irradiance Map Generation", false },
|
||||
|
||||
{ SDR_TYPE_SHADOW_MAP_GEN, "shadow_map-v.sdr", "shadow_map-f.sdr", "shadow_map-g.sdr",
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD, VATTRIB_NORMAL, VATTRIB_TANGENT, VATTRIB_MODELID }, "Shadow Map Generation", false },
|
||||
|
||||
{ SDR_TYPE_GAMMA_BLIT, "post-v.sdr", "gamma-correct-f.sdr", nullptr,
|
||||
{ VATTRIB_POSITION, VATTRIB_TEXCOORD }, "Gamma correct blit", false },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// ========== Shared shader variant table ==========
|
||||
// Moved from gropenglshader.cpp — single source of truth for both backends.
|
||||
// MODEL flags come from model_shader_flags.h; others from 2d.h defines.
|
||||
static ShaderVariantInfo SHADER_VARIANTS[] = {
|
||||
#define MODEL_SDR_FLAG_MODE_CPP_ARRAY
|
||||
#include "def_files/data/effects/model_shader_flags.h"
|
||||
#undef MODEL_SDR_FLAG_MODE_CPP_ARRAY
|
||||
|
||||
{SDR_TYPE_EFFECT_PARTICLE, true, SDR_FLAG_PARTICLE_POINT_GEN, "FLAG_EFFECT_GEOMETRY", {VATTRIB_UVEC}, "Geometry shader point-based particles"},
|
||||
|
||||
{SDR_TYPE_DEFERRED_LIGHTING, false, SDR_FLAG_ENV_MAP, "ENV_MAP", {}, "Render ambient light with env and irrmaps"},
|
||||
|
||||
{SDR_TYPE_DEFERRED_LIGHTING, false, SDR_FLAG_DEFERRED_RT_SHADOWS, "RT_SHADOWS", {}, "Use raytraced (TLAS ray query) shadows instead of cascaded shadow maps"},
|
||||
|
||||
{SDR_TYPE_POST_PROCESS_BLUR, false, SDR_FLAG_BLUR_HORIZONTAL, "PASS_0", {}, "Horizontal blur pass"},
|
||||
|
||||
{SDR_TYPE_POST_PROCESS_BLUR, false, SDR_FLAG_BLUR_VERTICAL, "PASS_1", {}, "Vertical blur pass"},
|
||||
|
||||
{SDR_TYPE_NANOVG, false, SDR_FLAG_NANOVG_EDGE_AA, "EDGE_AA", {}, "NanoVG edge anti-alias"},
|
||||
|
||||
{SDR_TYPE_DECAL, false, SDR_FLAG_DECAL_USE_NORMAL_MAP, "USE_NORMAL_MAP", {}, "Decal use scene normal map"},
|
||||
|
||||
{SDR_TYPE_MSAA_RESOLVE, false, SDR_FLAG_MSAA_SAMPLES_4, "SAMPLES_4", {}, "Sets the MSAA resolve shader to 4 samples"},
|
||||
|
||||
{SDR_TYPE_MSAA_RESOLVE, false, SDR_FLAG_MSAA_SAMPLES_8, "SAMPLES_8", {}, "Sets the MSAA resolve shader to 8 samples"},
|
||||
|
||||
{SDR_TYPE_MSAA_RESOLVE, false, SDR_FLAG_MSAA_SAMPLES_16, "SAMPLES_16", {}, "Sets the MSAA resolve shader to 16 samples"},
|
||||
|
||||
{SDR_TYPE_VOLUMETRIC_FOG, false, SDR_FLAG_VOLUMETRICS_DO_EDGE_SMOOTHING, "DO_EDGE_SMOOTHING", {}, "Perform costly edge smoothing lookups"},
|
||||
|
||||
{SDR_TYPE_VOLUMETRIC_FOG, false, SDR_FLAG_VOLUMETRICS_NOISE, "NOISE", {}, "Add noise to volumetrics"},
|
||||
|
||||
{SDR_TYPE_COPY_WORLD, false, SDR_FLAG_COPY_FROM_ARRAY, "COPY_ARRAY", {}, "Expects to copy from an array texture"},
|
||||
|
||||
{SDR_TYPE_COPY, false, SDR_FLAG_COPY_CLAMP01, "CLAMP01", {}, "Clamp copy to [0,1] (HDR edge-detection proxy)"},
|
||||
|
||||
{SDR_TYPE_POST_PROCESS_TONEMAPPING, false, SDR_FLAG_TONEMAPPING_LINEAR_OUT, "LINEAR_OUT", {}, "Will make the tonemapper output in linear color space and not in sRGB"},
|
||||
|
||||
{SDR_TYPE_GAMMA_BLIT, false, SDR_FLAG_GAMMA_HDR10, "HDR10_OUTPUT", {}, "Encode the gamma-corrected frame for HDR10 (PQ / BT.2020) output instead of SDR"},
|
||||
|
||||
{SDR_TYPE_SHADOW_MAP_GEN, true, SDR_FLAG_SHADOW_FALLBACK, "GEOMETRY_FALLBACK", {}, "Use a geometry shader to select the cascade layer instead of writing gl_Layer from the vertex shader"}
|
||||
};
|
||||
|
||||
const ShaderTypeInfo* shader_get_type_info(shader_type type)
|
||||
{
|
||||
for (auto & i : SHADER_TYPES) {
|
||||
if (i.type_id == type) {
|
||||
return &i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ShaderVariantInfo* shader_get_variant_info(shader_type type, int flag)
|
||||
{
|
||||
for (auto & i : SHADER_VARIANTS) {
|
||||
if (i.type_id == type && i.flag == flag) {
|
||||
return &i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void shader_for_each_active_variant(shader_type type, unsigned int flags, const std::function<void(const ShaderVariantInfo&)>& fn)
|
||||
{
|
||||
for (auto & i : SHADER_VARIANTS) {
|
||||
if (i.type_id == type && (flags & i.flag)) {
|
||||
fn(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCP_string shader_build_variant_defines(shader_type type, unsigned int flags)
|
||||
{
|
||||
SCP_string header;
|
||||
shader_for_each_active_variant(type, flags, [&](const ShaderVariantInfo& v) {
|
||||
header += "#define ";
|
||||
header += v.flag_text;
|
||||
header += "\n";
|
||||
});
|
||||
return header;
|
||||
}
|
||||
|
||||
bool shader_variant_requires_raytracing(shader_type type, unsigned int flags)
|
||||
{
|
||||
switch (type) {
|
||||
case SDR_TYPE_MODEL:
|
||||
return (flags & MODEL_SDR_FLAG_RT_SHADOWS) != 0;
|
||||
case SDR_TYPE_DEFERRED_LIGHTING:
|
||||
return (flags & SDR_FLAG_DEFERRED_RT_SHADOWS) != 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SCP_string shader_get_fxaa_defines(AntiAliasMode aa_mode, bool gather4_alpha)
|
||||
{
|
||||
SCP_string defines;
|
||||
defines.reserve(256);
|
||||
|
||||
defines += "#define FXAA_GLSL_120 0\n";
|
||||
defines += "#define FXAA_GLSL_130 1\n";
|
||||
|
||||
if (gather4_alpha) {
|
||||
defines += "#define FXAA_GATHER4_ALPHA 1\n";
|
||||
}
|
||||
|
||||
switch (aa_mode) {
|
||||
case AntiAliasMode::None:
|
||||
defines += "#define FXAA_QUALITY_PRESET 10\n";
|
||||
defines += "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/6.0)\n";
|
||||
defines += "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/12.0)\n";
|
||||
defines += "#define FXAA_QUALITY_SUBPIX 0.33\n";
|
||||
break;
|
||||
case AntiAliasMode::FXAA_Low:
|
||||
defines += "#define FXAA_QUALITY_PRESET 12\n";
|
||||
defines += "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/8.0)\n";
|
||||
defines += "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/16.0)\n";
|
||||
defines += "#define FXAA_QUALITY_SUBPIX 0.33\n";
|
||||
break;
|
||||
case AntiAliasMode::FXAA_Medium:
|
||||
defines += "#define FXAA_QUALITY_PRESET 26\n";
|
||||
defines += "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/12.0)\n";
|
||||
defines += "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/24.0)\n";
|
||||
defines += "#define FXAA_QUALITY_SUBPIX 0.33\n";
|
||||
break;
|
||||
case AntiAliasMode::FXAA_High:
|
||||
defines += "#define FXAA_QUALITY_PRESET 39\n";
|
||||
defines += "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/15.0)\n";
|
||||
defines += "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/32.0)\n";
|
||||
defines += "#define FXAA_QUALITY_SUBPIX 0.33\n";
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Unhandled FXAA mode!");
|
||||
}
|
||||
|
||||
return defines;
|
||||
}
|
||||
|
||||
SCP_string shader_get_smaa_defines(AntiAliasMode aa_mode, bool glsl4)
|
||||
{
|
||||
SCP_string defines;
|
||||
defines.reserve(64);
|
||||
|
||||
defines += glsl4 ? "#define SMAA_GLSL_4\n" : "#define SMAA_GLSL_3\n";
|
||||
|
||||
switch (aa_mode) {
|
||||
case AntiAliasMode::SMAA_Low:
|
||||
defines += "#define SMAA_PRESET_LOW\n";
|
||||
break;
|
||||
case AntiAliasMode::SMAA_Medium:
|
||||
defines += "#define SMAA_PRESET_MEDIUM\n";
|
||||
break;
|
||||
case AntiAliasMode::SMAA_High:
|
||||
defines += "#define SMAA_PRESET_HIGH\n";
|
||||
break;
|
||||
case AntiAliasMode::SMAA_Ultra:
|
||||
defines += "#define SMAA_PRESET_ULTRA\n";
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Unhandled SMAA mode!");
|
||||
}
|
||||
|
||||
return defines;
|
||||
}
|
||||
|
||||
SCP_string shader_get_shadow_cascade_defines()
|
||||
{
|
||||
SCP_string header;
|
||||
header += "#define NUM_SHADOW_CASCADES ";
|
||||
header += std::to_string(Num_shadow_cascades + Num_cockpit_shadow_cascades);
|
||||
header += "\n";
|
||||
return header;
|
||||
}
|
||||
|
||||
SCP_string shader_get_rt_shadow_light_limit_define()
|
||||
{
|
||||
SCP_string header;
|
||||
header += "#define MAX_RT_SHADOW_LIGHTS ";
|
||||
header += std::to_string(Max_rt_shadow_lights);
|
||||
header += "\n";
|
||||
return header;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "graphics/2d.h"
|
||||
|
||||
// Shared vertex attribute locations.
|
||||
// Both backends (OpenGL and Vulkan) use these same location numbers
|
||||
// for vertex shader inputs.
|
||||
enum VertexAttributeLocation : uint32_t {
|
||||
VATTRIB_POSITION = 0, // vec2, vec3, or vec4
|
||||
VATTRIB_COLOR = 1, // vec3/vec4 (normalized u8 or float)
|
||||
VATTRIB_TEXCOORD = 2, // vec2 or vec4
|
||||
VATTRIB_NORMAL = 3, // vec3
|
||||
VATTRIB_TANGENT = 4, // vec4
|
||||
VATTRIB_MODELID = 5, // float
|
||||
VATTRIB_RADIUS = 6, // float
|
||||
VATTRIB_UVEC = 7, // vec3
|
||||
VATTRIB_MODEL_MATRIX = 8, // Occupies locations 8-11
|
||||
|
||||
NUM_VERTEX_ATTRIBS = 9,
|
||||
};
|
||||
|
||||
// Shared shader type info — matches the original opengl_shader_type_t layout.
|
||||
struct ShaderTypeInfo {
|
||||
shader_type type_id;
|
||||
|
||||
const char *vert;
|
||||
const char *frag;
|
||||
const char *geo;
|
||||
|
||||
SCP_vector<VertexAttributeLocation> attributes;
|
||||
|
||||
const char* description;
|
||||
|
||||
bool spirv_shader;
|
||||
};
|
||||
|
||||
// Shared shader variant info — matches the original opengl_shader_variant_t layout.
|
||||
struct ShaderVariantInfo {
|
||||
shader_type type_id;
|
||||
|
||||
bool use_geometry_sdr;
|
||||
|
||||
int flag;
|
||||
SCP_string flag_text;
|
||||
|
||||
SCP_vector<VertexAttributeLocation> attributes;
|
||||
|
||||
const char* description;
|
||||
};
|
||||
|
||||
// Lookup helper: find type info by shader_type. Returns nullptr if not found.
|
||||
const ShaderTypeInfo* shader_get_type_info(shader_type type);
|
||||
|
||||
// Lookup helper: find variant info by (type, flag). Returns nullptr if not found.
|
||||
const ShaderVariantInfo* shader_get_variant_info(shader_type type, int flag);
|
||||
|
||||
// Iterate all variants matching type whose flag bit is set in flags.
|
||||
void shader_for_each_active_variant(shader_type type, unsigned int flags, const std::function<void(const ShaderVariantInfo&)>& fn);
|
||||
|
||||
// Build the variant #define header for a shader given type+flags.
|
||||
SCP_string shader_build_variant_defines(shader_type type, unsigned int flags);
|
||||
|
||||
// Returns FXAA preprocessor defines for the given AA mode.
|
||||
// gather4_alpha: whether the backend supports textureGather.
|
||||
SCP_string shader_get_fxaa_defines(AntiAliasMode aa_mode, bool gather4_alpha);
|
||||
|
||||
// Returns SMAA preprocessor defines (shading language + quality preset) for the given AA mode.
|
||||
// glsl4: whether to target the SMAA_GLSL_4 codepath (textureGather-based diagonal search).
|
||||
SCP_string shader_get_smaa_defines(AntiAliasMode aa_mode, bool glsl4);
|
||||
|
||||
// Returns the "#define NUM_SHADOW_CASCADES <n>\n" preprocessor define, sized to
|
||||
// the current total cascade count (Num_shadow_cascades + Num_cockpit_shadow_cascades).
|
||||
// Needed by any shader that references shadow cascade arrays (model, deferred
|
||||
// lighting, shadow map generation), for both backends.
|
||||
SCP_string shader_get_shadow_cascade_defines();
|
||||
|
||||
// Returns the "#define MAX_RT_SHADOW_LIGHTS <n>\n" preprocessor define, sized to
|
||||
// Max_rt_shadow_lights. Needed by the MODEL shader's raytraced-shadow code path
|
||||
// (main-f.sdr), for both backends -- harmless on OpenGL/non-raytraced builds since
|
||||
// that code path only compiles in under MODEL_SDR_FLAG_RT_SHADOWS.
|
||||
SCP_string shader_get_rt_shadow_light_limit_define();
|
||||
|
||||
// Whether this (type, flags) combination requires the GL_EXT_ray_query extension,
|
||||
// and therefore a SPIR-V target-env new enough to support it (see
|
||||
// VulkanShaderCompiler::compile()'s requiresRaytracing parameter). Centralized here
|
||||
// since the two shader types that can request it (model materials, deferred
|
||||
// lighting) each encode the raytraced-shadow bit differently.
|
||||
bool shader_variant_requires_raytracing(shader_type type, unsigned int flags);
|
||||
Binary file not shown.
@@ -1,51 +0,0 @@
|
||||
#version 150
|
||||
|
||||
layout(std140) uniform genericData
|
||||
{
|
||||
mat4 modelMatrix;
|
||||
vec4 color;
|
||||
vec4 clipEquation;
|
||||
int baseMapIndex;
|
||||
int alphaTexture;
|
||||
int noTexturing;
|
||||
int srgb;
|
||||
float intensity;
|
||||
float alphaThreshold;
|
||||
uint clipEnabled;
|
||||
} _39;
|
||||
|
||||
uniform sampler2DArray baseMap;
|
||||
|
||||
in vec4 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
out vec4 fragOut0;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 _48 = texture(baseMap, vec3(fragTexCoord.xy, float(_39.baseMapIndex)));
|
||||
if (_39.alphaThreshold > _48.w)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
bool _66 = _39.srgb == 1;
|
||||
vec3 _146;
|
||||
if (_66)
|
||||
{
|
||||
_146 = pow(_48.xyz, vec3(2.2000000476837158203125));
|
||||
}
|
||||
else
|
||||
{
|
||||
_146 = _48.xyz;
|
||||
}
|
||||
vec4 _148;
|
||||
if (_66)
|
||||
{
|
||||
_148 = vec4(pow(fragColor.xyz, vec3(2.2000000476837158203125)), fragColor.w);
|
||||
}
|
||||
else
|
||||
{
|
||||
_148 = fragColor;
|
||||
}
|
||||
fragOut0 = mix(mix(vec4(_146.x, _146.y, _146.z, _48.w) * _148, vec4(_148.xyz, _146.x * _148.w), vec4(float(_39.alphaTexture))), _148, vec4(float(_39.noTexturing))) * _39.intensity;
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -1,41 +0,0 @@
|
||||
#version 150
|
||||
|
||||
out float gl_ClipDistance[1];
|
||||
|
||||
layout(std140) uniform genericData
|
||||
{
|
||||
mat4 modelMatrix;
|
||||
vec4 color;
|
||||
vec4 clipEquation;
|
||||
int baseMapIndex;
|
||||
int alphaTexture;
|
||||
int noTexturing;
|
||||
int srgb;
|
||||
float intensity;
|
||||
float alphaThreshold;
|
||||
uint clipEnabled;
|
||||
} _22;
|
||||
|
||||
layout(std140) uniform matrixData
|
||||
{
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
} _36;
|
||||
|
||||
out vec4 fragTexCoord;
|
||||
in vec4 vertTexCoord;
|
||||
out vec4 fragColor;
|
||||
in vec4 vertColor;
|
||||
in vec4 vertPosition;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragTexCoord = vertTexCoord;
|
||||
fragColor = vertColor * _22.color;
|
||||
gl_Position = (_36.projMatrix * _36.modelViewMatrix) * vertPosition;
|
||||
if (_22.clipEnabled != 0u)
|
||||
{
|
||||
gl_ClipDistance[0] = dot(_22.clipEquation, _22.modelMatrix * vertPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
|
||||
struct genericData_default_material_frag {
|
||||
struct genericData_default_material_f_sdr {
|
||||
SPIRV_FLOAT_MAT_4x4 modelMatrix;
|
||||
SPIRV_FLOAT_VEC4 color;
|
||||
SPIRV_FLOAT_VEC4 clipEquation;
|
||||
@@ -16,14 +16,14 @@ struct genericData_default_material_frag {
|
||||
float alphaThreshold;
|
||||
std::uint32_t clipEnabled;
|
||||
};
|
||||
static_assert(sizeof(genericData_default_material_frag) == 124, "Size of struct genericData_default_material_frag does not match what is expected for the uniform block!");
|
||||
static_assert(offsetof(genericData_default_material_frag, modelMatrix) == 0, "Offset of member modelMatrix does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_frag, color) == 64, "Offset of member color does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_frag, clipEquation) == 80, "Offset of member clipEquation does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_frag, baseMapIndex) == 96, "Offset of member baseMapIndex does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_frag, alphaTexture) == 100, "Offset of member alphaTexture does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_frag, noTexturing) == 104, "Offset of member noTexturing does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_frag, srgb) == 108, "Offset of member srgb does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_frag, intensity) == 112, "Offset of member intensity does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_frag, alphaThreshold) == 116, "Offset of member alphaThreshold does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_frag, clipEnabled) == 120, "Offset of member clipEnabled does not match the uniform buffer offset!");
|
||||
static_assert(sizeof(genericData_default_material_f_sdr) == 124, "Size of struct genericData_default_material_f_sdr does not match what is expected for the uniform block!");
|
||||
static_assert(offsetof(genericData_default_material_f_sdr, modelMatrix) == 0, "Offset of member modelMatrix does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_f_sdr, color) == 64, "Offset of member color does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_f_sdr, clipEquation) == 80, "Offset of member clipEquation does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_f_sdr, baseMapIndex) == 96, "Offset of member baseMapIndex does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_f_sdr, alphaTexture) == 100, "Offset of member alphaTexture does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_f_sdr, noTexturing) == 104, "Offset of member noTexturing does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_f_sdr, srgb) == 108, "Offset of member srgb does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_f_sdr, intensity) == 112, "Offset of member intensity does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_f_sdr, alphaThreshold) == 116, "Offset of member alphaThreshold does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_f_sdr, clipEnabled) == 120, "Offset of member clipEnabled does not match the uniform buffer offset!");
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
|
||||
struct genericData_default_material_vert {
|
||||
struct genericData_default_material_v_sdr {
|
||||
SPIRV_FLOAT_MAT_4x4 modelMatrix;
|
||||
SPIRV_FLOAT_VEC4 color;
|
||||
SPIRV_FLOAT_VEC4 clipEquation;
|
||||
@@ -16,21 +16,21 @@ struct genericData_default_material_vert {
|
||||
float alphaThreshold;
|
||||
std::uint32_t clipEnabled;
|
||||
};
|
||||
static_assert(sizeof(genericData_default_material_vert) == 124, "Size of struct genericData_default_material_vert does not match what is expected for the uniform block!");
|
||||
static_assert(offsetof(genericData_default_material_vert, modelMatrix) == 0, "Offset of member modelMatrix does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_vert, color) == 64, "Offset of member color does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_vert, clipEquation) == 80, "Offset of member clipEquation does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_vert, baseMapIndex) == 96, "Offset of member baseMapIndex does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_vert, alphaTexture) == 100, "Offset of member alphaTexture does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_vert, noTexturing) == 104, "Offset of member noTexturing does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_vert, srgb) == 108, "Offset of member srgb does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_vert, intensity) == 112, "Offset of member intensity does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_vert, alphaThreshold) == 116, "Offset of member alphaThreshold does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_vert, clipEnabled) == 120, "Offset of member clipEnabled does not match the uniform buffer offset!");
|
||||
struct matrixData_default_material_vert {
|
||||
static_assert(sizeof(genericData_default_material_v_sdr) == 124, "Size of struct genericData_default_material_v_sdr does not match what is expected for the uniform block!");
|
||||
static_assert(offsetof(genericData_default_material_v_sdr, modelMatrix) == 0, "Offset of member modelMatrix does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_v_sdr, color) == 64, "Offset of member color does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_v_sdr, clipEquation) == 80, "Offset of member clipEquation does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_v_sdr, baseMapIndex) == 96, "Offset of member baseMapIndex does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_v_sdr, alphaTexture) == 100, "Offset of member alphaTexture does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_v_sdr, noTexturing) == 104, "Offset of member noTexturing does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_v_sdr, srgb) == 108, "Offset of member srgb does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_v_sdr, intensity) == 112, "Offset of member intensity does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_v_sdr, alphaThreshold) == 116, "Offset of member alphaThreshold does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(genericData_default_material_v_sdr, clipEnabled) == 120, "Offset of member clipEnabled does not match the uniform buffer offset!");
|
||||
struct matrixData_default_material_v_sdr {
|
||||
SPIRV_FLOAT_MAT_4x4 modelViewMatrix;
|
||||
SPIRV_FLOAT_MAT_4x4 projMatrix;
|
||||
};
|
||||
static_assert(sizeof(matrixData_default_material_vert) == 128, "Size of struct matrixData_default_material_vert does not match what is expected for the uniform block!");
|
||||
static_assert(offsetof(matrixData_default_material_vert, modelViewMatrix) == 0, "Offset of member modelViewMatrix does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(matrixData_default_material_vert, projMatrix) == 64, "Offset of member projMatrix does not match the uniform buffer offset!");
|
||||
static_assert(sizeof(matrixData_default_material_v_sdr) == 128, "Size of struct matrixData_default_material_v_sdr does not match what is expected for the uniform block!");
|
||||
static_assert(offsetof(matrixData_default_material_v_sdr, modelViewMatrix) == 0, "Offset of member modelViewMatrix does not match the uniform buffer offset!");
|
||||
static_assert(offsetof(matrixData_default_material_v_sdr, projMatrix) == 64, "Offset of member projMatrix does not match the uniform buffer offset!");
|
||||
Binary file not shown.
@@ -1,10 +0,0 @@
|
||||
#version 150
|
||||
|
||||
out vec4 outColor;
|
||||
in vec3 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
outColor = vec4(fragColor, 1.0);
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -1,13 +0,0 @@
|
||||
#version 150
|
||||
|
||||
const vec2 _20[3] = vec2[](vec2(0.0, -0.5), vec2(0.5), vec2(-0.5, 0.5));
|
||||
const vec3 _29[3] = vec3[](vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0));
|
||||
|
||||
out vec3 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(_20[gl_VertexID], 0.0, 1.0);
|
||||
fragColor = _29[gl_VertexID];
|
||||
}
|
||||
|
||||
Loaded 100 of 228 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user