Merge branch 'master' into sdl-joykeys

This commit is contained in:
Robert Beckebans 2025-01-23 14:34:49 +01:00
commit 201485eb37
59 changed files with 1756 additions and 1079 deletions

3
.gitignore vendored
View file

@ -41,6 +41,8 @@ base/renderprogs2/
base/generated/
base/env/
base/screenshots/
base/_tb/*.obj
base/_tb/*.mtl
GPATH
GRTAGS
@ -52,3 +54,4 @@ neo/neo.kdev4
neo/.idea/
neo/cmake-build-*/
neo/bin/
tools/

View file

@ -24,20 +24,19 @@ This file contains the following sections:
1. [About the Port](#about)
2. [".plan"](#plan)
3. [May or may not ".plan"](#plan2)
4. [Renderer Features Explained](#render)
5. [TrenchBroom Mapping Support](#trenchbroom)
6. [General Notes](#notes)
7. [License](#license)
8. [Getting the Source Code ](#source)
9. [Compiling on Windows](#compile_windows)
10. [Compiling on Linux](#compile_linux)
11. [Compiling on macOS](#compile_macos)
12. [Installation](#installation)
13. [New Console Variables](#console)
14. [Known Issues](#issues)
15. [Bug Reports](#reports)
16. [FAQ](#faq)
3. [Renderer Features Explained](#render)
4. [TrenchBroom Mapping Support](#trenchbroom)
5. [General Notes](#notes)
6. [License](#license)
7. [Getting the Source Code ](#source)
8. [Compiling on Windows](#compile_windows)
9. [Compiling on Linux](#compile_linux)
10. [Compiling on macOS](#compile_macos)
11. [Installation](#installation)
12. [New Console Variables](#console)
13. [Known Issues](#issues)
14. [Bug Reports](#reports)
15. [FAQ](#faq)
@ -47,7 +46,7 @@ This file contains the following sections:
`RBDOOM-3-BFG is a modernization effort of DOOM-3-BFG.`
RBDOOM-3-BFG is based on DOOM-3-BFG and the goal of this port is to bring DOOM-3-BFG up to latest technology in 2024 making it closer to Doom 2016 while still remaining a DOOM 3 port regarding the gameplay.
RBDOOM-3-BFG is based on DOOM-3-BFG and the goal of this port is to bring DOOM-3-BFG up to latest technology in 2025 making it closer to Doom 2016 while still remaining a DOOM 3 port regarding the gameplay.
I started this project in 2012 and focused on making this code being future proof so other cool projects can build interesting things on top of it without the need to fix a lot of stuff first. Over 40 people all over the world contributed cool patches. Some results are:
@ -59,7 +58,7 @@ I started this project in 2012 and focused on making this code being future proo
* All 3 light types (point, spot, parallel/sun) are supported which means parallel lights (sun) use
scene independent cascaded shadow mapping.
* True internal 64 bit HDR lighting with filmic ACES tone mapping and gamma-correct rendering in linear RGB space
* Temporal Antialiasing (TAA) as a cheap alternative for MSAA and that works well with HDR and also improves PBR lighting
* SMAA and Temporal Antialiasing (TAA) as cheap alternatives for MSAA
* Filmic post process effects like Chromatic Aberration and Dithering
* Retro Rendering modes for the nostalgia of the 8-bit and 16-bit eras including the Commodore 64, Amstrad CPC 6128, Sega Genesis and Sony PSX
* Screen Space Ambient Occlusion used to only dim down the Global Illumination contribution like in the Frostbite engine
@ -115,18 +114,6 @@ You can fork RBDOOM-3-BFG and create a new renamed binary that includes all requ
If you want to see what is planned or in progress in a Trello/Kanban style manner look here: [RBDOOM-3-BFG projects](https://github.com/RobertBeckebans/RBDOOM-3-BFG/projects)
Short term goals:
* Node based Imgui particle editor
* Flash support through Adobe Animate or Blender
* Raytracing for accelerating the probe baking and optionally adding realtime global illumination
---
# May or may not ".plan" <a name="plan2"></a>
* Replace traditional multipass forward shading with a faster forward+ solution
* [Volumetric Lighting](http://www.alexandre-pestana.com/volumetric-lights/)
* ReSTIR or some other realtime path tracing
* Optional alternative collision detection and physics with PhysX 5 or Jolt
---
# Renderer Features Explained <a name="render"></a>
@ -328,7 +315,7 @@ r_useSSAO 1 darkens the corners of the scene and also removes too much ambient a
"""
-->
## Filmic Post Processing
If you enable it with r_useFilmicPostProcessing 1 then you play DOOM 3 BFG the optics of a Zack Snyder movie.
If you enable it with r_useFilmicPostFX 1 then you play DOOM 3 BFG the optics of a Zack Snyder movie.
It adds chromatic abberation and filmic dithering using Blue Noise.
The effect is heavy and is usually aimed in Film production to mix real camera footage with CG generated content.
@ -375,11 +362,11 @@ Directory | Description
RBDOOM-3-BFG/base/ | Doom 3 BFG media directory ( models, textures, sounds, maps, etc. )
RBDOOM-3-BFG/neo/ | RBDOOM-3-BFG source code ( renderer, game code for multiple games, OS layer, etc. )
RBDOOM-3-BFG/build/ | Build folder for CMake
RBDOOM-3-BFG/tools/runtimedeps | Visual Studio C++ Redistributables if you have problems to start the engine or the tools
RBDOOM-3-BFG/tools/trenchbroom | TrenchBroomBFG level editor customized for DOOM 3 and RBDOOM-3-BFG
RBDOOM-3-BFG/tools/darkradiant | DarkRadiant level editor with an additional config for RBDOOM-3-BFG
RBDOOM-3-BFG/tools/bfgpakexlorer | BFG Resource File Manager by George Kalampokis aka Mr.GK
RBDOOM-3-BFG/tools/optick-profiler | Optick is a super-lightweight C++ profiler for Games
RBDOOM-3-BFG/tools/runtimedeps | Visual Studio C++ Redistributables if you have problems to start the engine or the tools
The GPL release does not contain any game data, the game data is still
covered by the original EULA and must be obeyed as usual.
@ -629,15 +616,16 @@ Name | Description
r_graphicsAPI | Default DX12, can be either DX12 or Vulkan on Windows
r_antiAliasing | Different Anti-Aliasing modes
r_exposure [0 .. 1] | Default 0.5, controls brightness and affects HDR -> sRGB Rec. 709 exposure key. This is what you change in the video brightness options
r_useSSAO [0 .. 1] | Use Screen Space Ambient Occlusion to darken the corners in the scene and give it more depth
r_useSSAO [0, 1] | Use Screen Space Ambient Occlusion to darken the corners in the scene and give it more depth
r_forceAmbient | Default 0.5, controls additional brightness by Global Illumination
r_useFilmicPostFX [0, 1] | Apply several post process effects to mimic a filmic look
r_useCRTPostFX [0 .. 2] | CRT monitor/TV filter
r_renderMode [0 .. 7] | Default 0 = Doom, 1 = CGA, 2 = CGA Highres, 3 = Commodore 64, 4 = Commodore 64 Highres, 5 = Amstrad CPC 6128, 6 = Amstrad CPC 6128 Highres, 7 = NES, 8 = NES Highres, 9 = Sega Genesis, 10 = Sega Genesis Highres, 11 = Sony PSX
r_renderMode [0 .. 9] | Default 0 = Doom, 1 = CGA, 2 = CGA Highres, 3 = Commodore 64, 4 = Commodore 64 Highres, 5 = Amstrad CPC 6128, 6 = Amstrad CPC 6128 Highres, 7 = Sega Genesis, 8 = Sega Genesis Highres, 9 = Sony PSX
## Modding Support
Name | Description
:--------------------------------------| :------------------------------------------------
listCvars `[new]` | Option that lists all cvars that have been added to this sourceport
dmap mapfile | Command: Compiles a .map to its corresponding BSP .proc, Collision .cm files and Area Awareness System (AI navigation) .aas files. Just type dmap to list all options
dmap `[glview]` mapfile | DMap option that exports the BSP areas and portals to .obj for debugging purposes
bakeEnvironmentProbes | Command after loading a map. Captures all env_probe entities and stores them to disc
@ -648,11 +636,11 @@ exportImagesToTrenchBroom | Command: Decompresses and saves all TB
exportModelsToTrenchBroom | Command: Saves all binarized models to base/_tb/*.obj files
convertMapToValve220 `<map>` | Command: Saves *_valve220.map version of the given map. This makes it editable with TrenchBroomBFG.
convertMapQuakeToDoom `<map>` | Command: Expects a Quake 1 .map in the Valve220 format and does some Doom 3 specific fixes
makeZooMapForModels | Command: Makes a Source engine style zoo map with mapobject/models like .blwo, .base et cetera and saves it to maps/zoomaps/zoo_models.map. This helps mappers to get a good overview of the trememdous amount of custom models available in Doom 3 BFG by sorting them into categories and arranging them in 3D. It also filters models so that only modular models are picked that can be reused in new maps.
exportEntityDefsToBlender | Command: Exports all entity and model defs to base/_bl/entities.json for usage in Blender before loading a map.
exportMapToOBJ | Command: Convert .map file to .obj/.mtl
swf_show | Cvar: Draws the bounding box of instanced Flash sprites in red and their names
makeMaterials `<folder>` | Command: Make a .mtr file based on PBR naming conventions
makeZooMapForModels | Command: Makes a Source engine style zoo map with mapobject/models like .blwo, .base et cetera and saves it to maps/zoomaps/zoo_models.map. This helps mappers to get a good overview of the trememdous amount of custom models available in Doom 3 BFG by sorting them into categories and arranging them in 3D. It also filters models so that only modular models are picked that can be reused in new maps.
---
@ -682,14 +670,18 @@ You can find your qconsole.log on Windows in C:\Users\<your user name>\Saved Gam
---
# FAQ <a name="faq"></a>
**Q**: Why bother with DOOM-3-BFG in 2021?
**Q**: Why bother with DOOM-3-BFG in 2025?
**A**: It is fun, period. Doom 3 is from 2004 but it is still an impressive and entertaining game. In 2011 id Software added many results from the development of Rage like its own Flash SWF and ActionScript 2 interpreter, proper support for gamepads and widescreens. It also combines the gamecode for Doom 3 and its missionpacks and runs it in a seperate thread and it has many multithreaded rendering optimizations.
DOOM-3 and DOOM-3-BFG are some of the most transparent games available where you can open all files and inspect how the game was built.
Unlike Quake 1-3, DOOM-3-BFG shipped with all level .map sources for 47 single player maps.
There is plenty of stuff you can learn from it like solid run & gun core gameplay, AI, animations, client/server multiplayer, level design or simple and elegant engine design.
**Q**: Why bother with DOOM-3-BFG in 2023?
**A**: The engine compiles faster than opening a project in Unity. Maybe you just appreciate that it doesn't require more than 300 MB of RAM and 1024 MB of VRAM while running a complex game like Doom 3.
**Q**: Why bother with the DOOM-3-BFG engine in 2025?
**A**: The engine compiles faster than opening a project in Unity or Unreal. Maybe you just appreciate that it doesn't require more than 300 MB of RAM and 3072 MB of VRAM while running a complex game like Doom 3. Maybe it is just nice that it can run Epic's Sun Temple demo with over 230 fps @ 1080p on a Geforce 2070 Super unlike UE4.
<!--
<img src="https://i.imgur.com/cwwr4z5.png" width="800">
-->
**Q**: Can I use this engine to make a commercial game?
**A**: You can but don't bother me to give you free support and you probably should use Unreal Engine 4/5. I am a full time game developer and usually don't have time for any free support. I recommend that you have moderate C++ skills even if you are an artist. Technical designers (coders who became artists) might benefit most from this engine. Keep in mind that the GPL license will lock you out of the console markets because you can't use proprietary APIs covered by NDAs. However you can sell your game on Steam without problems.

View file

@ -18,6 +18,74 @@ _______________________________________
TBD - RBDOOM-3-BFG 1.6.0
_______________________________
## .plan - January 16, 2025
This test build comes with HDRI support and a few critical bugfixes that save video memory and avoid unnessessary duplicated .bimage files.
Changelog:
* Fixed bad lightgrid lookups if models span multiple areas. close #965
* Fixed several bugs in the .bimage lookup logic
* Added HDRI extension to the material system
* Added default loading screen for custom maps
* Simplified image loading code
* Fixed potential memleaks in R_LoadEXR and R_WriteEXR
* Added cacheGlobalIlluminationData cmd to turn env/maps/*.exr into .bimage files
* Apply invertGreen( normalmap ) with DX normalmaps and makeMaterials
* Added some docs by Mr.Elusive about the BFG architecture
## .plan - January 02, 2025
This test build comes with a new TrenchBroomBFG build that drastically reduces the load time of maps that use custom models with higher polycounts than the typical Doom 3 models. This reduces the load time to seconds instead of minutes and makes the editor feasible to work with more modern models like Epic's Sun Temple demo or Crytek's Sponza level.
Besides that RBDoom has a new binary model format that was necessary to avoid crashes when reloading custom maps.
This will also regenerate all models like .glb -> .bglb, .obj -> .bobj and so on.
Changelog:
* Reduced peter panning effect and shadow acne with Nvidia cards
* Added new .bproc format to avoid crashes with custom maps
* Replaced in the ingame light editor 'Save as .map' button with 'Apply' button. Use Ctrl+S instead to save the map.
* Optimized retro shaders by precomputing deviation
* Deleted NES shader
* Disabled scrolling scanlines in Newpixie CRT shader
* Replaced Sega retro shader quant with a fixed 64 color palette
* Don't quit rbdmap quietly if running in imtui mode
* Quadruppled vertex cache limits like before in RBDoom 1.4
* Extended makeMaterials to handle UE4 specular maps
* Added textures/common/black material to block light behind walls
* glTF culling bugfix caused by uninitialized variable
* Fixed menu button controller mappings with SDL
* Use correct controller button->joystick event mapping for SDL joystick polling
Changelog TrenchBroomBFG:
* Replaced ray traced model picker code using TinyBVH which allows to load bigger glTF 2 maps almost instantly instead of minutes
## .plan - December 6, 2024
This is a first test build for the new blood effects.
@ -124,7 +192,7 @@ Immerse yourself in the authentic Commodore 64 mode, faithfully replicating the
The retro rendering modes transport you back to the golden age of gaming, with a resolution that mimics the beloved 320x240 display, now extended to a widescreen 480x270 format. To enhance the arcade feel, two new CRT filters are included that overlay the entire game, including Doom 1 & 2.
To access these retro rendering modes, simply navigate to the menu options and select your desired mode. Alternatively, you can control the rendering mode by modifying the `r_renderMode` variable. The available values for `r_renderMode` are as follows: Default (0) for Doom 3, 2-bit CGA (1), 2-bit CGA Highres(2), Commodore 64 (3), Commodore 64 Highres (4), Amstrad CPC (5), Amstrad CPC Highres (6), NES (7), NES Highres (8), Sega Genesis (9), Sega Genesis Highres (10) and Sony PSX (11).
To access these retro rendering modes, simply navigate to the menu options and select your desired mode. Alternatively, you can control the rendering mode by modifying the `r_renderMode` variable. The available values for `r_renderMode` are as follows: Default (0) for Doom 3, 2-bit CGA (1), 2-bit CGA Highres(2), Commodore 64 (3), Commodore 64 Highres (4), Amstrad CPC (5), Amstrad CPC Highres (6), Sega Genesis (7), Sega Genesis Highres (8) and Sony PSX (9).
<img src="https://i.imgur.com/W8umJ3a.png" width="800">

View file

@ -72,5 +72,4 @@ bind y "clientMessageMode 1"
//
bind MOUSE1 _attack
bind MOUSE2 _moveup

View file

@ -12,9 +12,9 @@ bind "F2" "toggle r_showTris 1 2 0"
bind "F3" "toggle r_forceAmbient 0.3 0.5 1.0 0"
bind "F4" "toggle r_skipInteractions"
bind "F5" "savegame quick"
// bind "F6" "toggle r_showLightGrid 1 3 4 0"
bind "F6" "toggle r_renderMode 0 1 3 5 7 9 11"
bind "F7" "toggle r_renderMode 0 1 2 3 4 5 6 7 8 9 10 11"
bind "F6" "toggle r_showLightGrid 1 3 4 0"
//bind "F6" "toggle r_renderMode 0 1 3 5 7 9 11"
bind "F7" "toggle r_renderMode 0 1 2 3 4 5 6 7 8 9"
bind "F8" "toggle r_useCRTPostFX 0 1 2 3"
bind "F9" "loadgame quick"
// bind "F10" "toggle com_fixedTic"

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

View file

@ -442,4 +442,17 @@ textures/common/occlusion
noshadows
occlusion
}
// this one is not invisible and like textures/sfx/black but will also cast shadows
// so it works as a blocker for the lightgrid
textures/common/black
{
qer_editorimage textures/common/black.tga
nonsolid
forceshadows
forceOpaque
noselfshadow
basecolormap _blackDiffuse
}
// RB end

View file

@ -295,7 +295,7 @@ scriptEvent entity getEntity( string name );
scriptEvent entity spawn( string classname );
// Respawn
scriptEvent void respawn();
scriptEvent void respawn( );
// copies the spawn args from an entity
scriptEvent void copySpawnArgs( entity ent );

View file

@ -1,126 +0,0 @@
/*
Alternate Quake Tracks
----------------------
This is a compilation of alternate tracks.
They are to be used for streamers/YouTubers
as well as for those who lack the OST.
02. Often not Their Right Time Verbum Mentis
03. EoE intermission Markie Music
04. Yss Éskiuth Immorpher
05. Gwam Swolíst Immorpher
06. Feedback AlekswithaK
07. Thia Whythdyi Immorpher
08. Deeper Outside, pt 1 Verbum Mentis
09. Lingering Repetitive Agony Verbum Mentis
10. Architects of Enmity AlekswithaK
11. Scratch my surface Verbum Mentis
All music is either open source or permitted
to be used, when playing the game, by the
composer. Enjoy!
- Greenwood
*/
music/aqm/track02
{
description "Often not Their Right Time Verbum Mentis"
volume -5
global
looping
music/aqm/track02.ogg
}
music/aqm/track03
{
description "EoE intermission"
volume -5
global
looping
music/aqm/track03.ogg
}
music/aqm/track04
{
description "Yss Éskiuth"
volume -2
global
looping
music/aqm/track04.ogg
}
music/aqm/track05
{
description "Gwam Swolíst"
volume -2
global
looping
music/aqm/track05.ogg
}
music/aqm/track06
{
description "Feedback"
volume -3
global
looping
music/aqm/track06.ogg
}
music/aqm/track07
{
description "Thia Whythdyi"
volume -2
global
looping
music/aqm/track07.ogg
}
music/aqm/track08
{
description "Deeper Outside, pt 1"
volume -4
global
looping
music/aqm/track08.ogg
}
music/aqm/track09
{
description "Lingering Repetitive Agony"
volume -5
global
looping
music/aqm/track09.ogg
}
music/aqm/track10
{
description "Architects of Enmity"
volume -2
global
looping
music/aqm/track10.ogg
}
music/aqm/track11
{
description "Scratch my surface"
volume -2
global
looping
music/aqm/track11.ogg
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

BIN
docs/flash/avm2overview.pdf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1715,6 +1715,18 @@ void idGameLocal::MapShutdown()
gameRenderWorld->DebugClearPolygons( 0 );
}
// RB: kill ingame editors to prevent crashes during shutdown
if( com_editors != 0 )
{
com_editors = 0;
g_editEntityMode.SetInteger( 0 );
// turn off light debug drawing in the render backend
r_singleLight.SetInteger( -1 );
r_showLights.SetInteger( 0 );
}
// RB end
// clear out camera if we're in a cinematic
if( inCinematic )
{

View file

@ -2747,6 +2747,9 @@ void Cmd_EditLights_f( const idCmdArgs& args )
r_singleLight.SetInteger( -1 );
r_showLights.SetInteger( 0 );
}
// put player into fly mode
Cmd_Noclip_f( args );
}
// RB end

View file

@ -614,8 +614,8 @@ void idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings::AdjustFi
// RB begin
case SYSTEM_FIELD_RENDERMODE:
{
static const int numValues = 12;
static const int values[numValues] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
static const int numValues = 10;
static const int values[numValues] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
r_renderMode.SetInteger( AdjustOption( r_renderMode.GetInteger(), values, numValues, adjustAmount ) );
break;
}
@ -795,7 +795,7 @@ idSWFScriptVar idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings
}
case SYSTEM_FIELD_RENDERMODE:
{
static const int numValues = 12;
static const int numValues = 10;
static const char* values[numValues] =
{
"Doom 3",
@ -805,8 +805,6 @@ idSWFScriptVar idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings
"Commodore 64 Hi",
"Amstrad CPC 6128",
"Amstrad CPC 6128 Hi",
"NES",
"NES Hi",
"Sega Genesis",
"Sega Genesis Highres",
"Sony PSX",

View file

@ -444,7 +444,7 @@ float idConsoleLocal::DrawFPS( float y )
aaMode = aaValues[ r_antiAliasing.GetInteger() ];
}
static const int rrNumValues = 12;
static const int rrNumValues = 10;
static const char* rrValues[rrNumValues] =
{
"Doom",
@ -454,10 +454,8 @@ float idConsoleLocal::DrawFPS( float y )
"C64 Hi",
"CPC",
"CPC Hi",
"NES",
"NES Hi",
"Sega MD",
"Sega MD Hi",
"Sega",
"Sega Hi",
"Sony PSX",
};

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 2022 Harrie van Ginneken
Copyright (C) 2022 Robert Beckebans
Copyright (C) 2022-2025 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -32,7 +32,6 @@ If you have questions concerning this license or the applicable additional terms
// files import as y-up. Use this transform to change the model to z-up.
static const idMat4 blenderToDoomTransform( idAngles( 0.0f, 0.0f, 90 ).ToMat3(), vec3_origin );
//static const idMat4 blenderToDoomTransform = mat4_identity;
MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* prim, gltfData* _data , const idMat4& transform )
{
@ -409,7 +408,7 @@ static void AddMeshesToWorldspawn_r( idMapEntity* entity, gltfNode* node, const
}
};
void ResolveLight( gltfData* data, idMapEntity* newEntity, gltfNode* node )
static void ResolveLight( gltfData* data, idMapEntity* newEntity, gltfNode* node )
{
assert( node && node->extensions.KHR_lights_punctual );
@ -493,7 +492,7 @@ void ResolveLight( gltfData* data, idMapEntity* newEntity, gltfNode* node )
}
void ResolveEntity( gltfData* data, idMapEntity* newEntity, gltfNode* node )
static void ResolveEntity( gltfData* data, idMapEntity* newEntity, gltfNode* node )
{
const char* classname = node->extras.strPairs.GetString( "classname" );
@ -533,9 +532,11 @@ void ResolveEntity( gltfData* data, idMapEntity* newEntity, gltfNode* node )
if( node->extensions.KHR_lights_punctual != nullptr )
{
ResolveLight( data, newEntity, node );
return;
}
// HarrievG: TODO cleanup this was done by try & error until it worked
#if 0
if( node->camera >= 0 && !newEntity->epairs.FindKey( "rotation" ) )
{
idQuat q = entityToWorldTransform.ToMat3().ToQuat();
@ -545,7 +546,7 @@ void ResolveEntity( gltfData* data, idMapEntity* newEntity, gltfNode* node )
else if( idStr::Icmp( classname, "info_player_start" ) == 0 && !newEntity->epairs.FindKey( "rotation" ) )
{
idQuat q = entityToWorldTransform.ToMat3().ToQuat();
q = idAngles( -90.0f, 0.0, -90.0f ).ToQuat() * q * blenderToDoomTransform.ToMat3().ToQuat();
q = idAngles( 90.0f, 0.0, -90.0f ).ToQuat() * q * blenderToDoomTransform.ToMat3().ToQuat();
newEntity->epairs.SetMatrix( "rotation", q.ToMat3() );
}
else if( node->extras.strPairs.GetBool( "useNodeOrientation", false ) )
@ -561,6 +562,24 @@ void ResolveEntity( gltfData* data, idMapEntity* newEntity, gltfNode* node )
//idMat3 rot = ( blenderToDoomTransform * entityToWorldTransform ).ToMat3();
newEntity->epairs.SetMatrix( "rotation", rot );
}
#else
if( node->camera >= 0 && !newEntity->epairs.FindKey( "rotation" ) )
{
idQuat q = entityToWorldTransform.ToMat3().ToQuat();
q = idAngles( 90.0f, 0.0, -90.0f ).ToQuat() * q * blenderToDoomTransform.ToMat3().ToQuat();
newEntity->epairs.SetMatrix( "rotation", q.ToMat3() );
}
else
{
idQuat q = entityToWorldTransform.ToMat3().ToQuat();
q = idAngles( 0.0f, 0.0f, -90.0f ).ToQuat() * q * blenderToDoomTransform.ToMat3().ToQuat();
newEntity->epairs.SetMatrix( "rotation", q.ToMat3() );
// FIXME this should be
//idMat3 rot = ( blenderToDoomTransform * entityToWorldTransform ).ToMat3();
//newEntity->epairs.SetMatrix( "rotation", rot );
}
#endif
#if 0
for( int i = 0; i < newEntity->epairs.GetNumKeyVals(); i++ )
@ -572,20 +591,23 @@ void ResolveEntity( gltfData* data, idMapEntity* newEntity, gltfNode* node )
#endif
}
int FindEntities( gltfData* data, idMapEntity::EntityListRef entities, gltfNode* node , idDict epairs , idMapEntity* worldspawn )
static int FindEntities_r( gltfData* data, idMapEntity::EntityListRef entities, gltfNode* node , idDict epairs , idMapEntity* worldspawn )
{
int entityCount = 0;
const char* classname = node->extras.strPairs.GetString( "classname" );
// skip all nodes with "worldspawn." or "BSP" in the name
if( idStr::Icmpn( node->name, "BSP", 3 ) != 0
&& idStr::Icmpn( node->name, "worldspawn.", 11 ) != 0 )
if( idStr::Icmpn( node->name, "BSP", 3 ) == 0 || idStr::Icmpn( node->name, "worldspawn.", 11 ) == 0 )
{
AddMeshesToWorldspawn_r( worldspawn, node, mat4_identity, data );
}
else
{
idStr classnameStr = node->extras.strPairs.GetString( "classname" );
// skip everything that is not an entity
if( !classnameStr.IsEmpty() )
// skip everything that is not an entity except lights
if( !classnameStr.IsEmpty() || node->extensions.KHR_lights_punctual )
{
auto* newEntity = new( TAG_IDLIB_GLTF ) idMapEntity();
entities.Append( newEntity );
@ -604,14 +626,10 @@ int FindEntities( gltfData* data, idMapEntity::EntityListRef entities, gltfNode*
}
}
}
else
{
AddMeshesToWorldspawn_r( worldspawn, node, mat4_identity, data );
}
for( auto& child : node->children )
{
entityCount += FindEntities( data, entities, data->NodeList()[child], epairs , worldspawn );
entityCount += FindEntities_r( data, entities, data->NodeList()[child], epairs , worldspawn );
}
return entityCount;
@ -648,7 +666,14 @@ int idMapEntity::GetEntities( gltfData* data, EntityListRef entities, int sceneI
else
{
idStr classnameStr = node->extras.strPairs.GetString( "classname" );
bool skipInline = !node->extras.strPairs.GetBool( "inline", true );
idStr model = node->extras.strPairs.GetString( "model" );
// inline should be false by default because drag n drop in the asset browser in Blender is Append by default
// however it would break previous maps
// in Doom 3 maps inline entities have as model key the same name as the entity name
const bool defaultInline = ( idStr::Icmp( model.c_str(), node->name.c_str() ) == 0 );
bool skipInline = !node->extras.strPairs.GetBool( "inline", defaultInline );
idDict epairs;
// skip everything that is not an entity except lights
@ -678,10 +703,11 @@ int idMapEntity::GetEntities( gltfData* data, EntityListRef entities, int sceneI
epairs.Copy( node->extras.strPairs );
}
}
// add entities from all subnodes
for( auto& child : node->children )
{
entityCount += FindEntities( data, entities, data->NodeList()[child] , epairs, worldspawn );
entityCount += FindEntities_r( data, entities, data->NodeList()[child] , epairs, worldspawn );
}
}
}

View file

@ -117,6 +117,26 @@ bool HandleKeyEvent( const sysEvent_t& keyEvent )
ImGuiIO& io = ImGui::GetIO();
if( keyNum == K_MOUSE2 )
{
// RB: allow navigation like in a level editor
g_MousePressed[1] = pressed;
if( ImGuiTools::AreEditorsActive() )
{
ImGuiTools::SetReleaseToolMouse( !pressed );
}
//common->Printf( "mouse2 pressed %d\n", int( pressed ) );
return true;
}
if( g_MousePressed[1] )
{
// RB: ignore everything as long right mouse button is pressed
return false;
}
if( keyNum < K_JOY1 )
{
// keyboard input as direct input scancodes
@ -230,7 +250,7 @@ bool ShowWindows()
bool UseInput()
{
return ImGuiTools::ReleaseMouseForTools() || imgui_showDemoWindow.GetBool();
return ( ImGuiTools::ReleaseMouseForTools() || imgui_showDemoWindow.GetBool() );
}
void StyleGruvboxDark()
@ -752,7 +772,7 @@ void NotifyDisplaySizeChanged( int width, int height )
// inject a sys event
bool InjectSysEvent( const sysEvent_t* event )
{
if( IsInitialized() && UseInput() )
if( IsInitialized() && ( UseInput() || RightMouseActive() ) )
{
if( event == NULL )
{
@ -795,6 +815,11 @@ bool InjectSysEvent( const sysEvent_t* event )
return false;
}
bool RightMouseActive()
{
return g_MousePressed[1];
}
bool InjectMouseWheel( int delta )
{
if( IsInitialized() && UseInput() && delta != 0 )

View file

@ -61,6 +61,8 @@ void Render();
void Destroy();
bool RightMouseActive();
} //namespace ImGuiHook

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2014-2024 Robert Beckebans
Copyright (C) 2014-2025 Robert Beckebans
Copyright (C) 2014-2016 Kot in Action Creative Artel
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -260,14 +260,6 @@ void idBinaryImage::Load2DFromMemory( int width, int height, const byte* pic_con
img.data[ i ] = pic[ i ];
}
}
else if( textureFormat == FMT_RGBA16F )
{
img.Alloc( scaledWidth * scaledHeight * 8 );
for( int i = 0; i < img.dataSize; i++ )
{
img.data[ i ] = pic[ i ];
}
}
else
{
fileData.format = textureFormat = FMT_RGBA8;
@ -287,7 +279,11 @@ void idBinaryImage::Load2DFromMemory( int width, int height, const byte* pic_con
// downsample for the next level
byte* shrunk = NULL;
if( gammaMips )
if( textureFormat == FMT_R11G11B10F )
{
shrunk = R_MipMapR11G11B10F( pic, scaledWidth, scaledHeight );
}
else if( gammaMips )
{
shrunk = R_MipMapWithGamma( pic, scaledWidth, scaledHeight );
}
@ -556,15 +552,6 @@ void idBinaryImage::Load2DAtlasMipchainFromMemory( int width, int height, const
img.data[ i * 2 + 1 ] = color & 0xFF;
}
}
else if( textureFormat == FMT_RG16F )
{
// RB: copy it as it was a RGBA8 because of the same size
img.Alloc( scaledWidth * scaledHeight * 4 );
for( int i = 0; i < img.dataSize; i++ )
{
img.data[ i ] = pic[ i ];
}
}
else if( textureFormat == FMT_R11G11B10F )
{
// RB: copy it as it was a RGBA8 because of the same size
@ -574,14 +561,6 @@ void idBinaryImage::Load2DAtlasMipchainFromMemory( int width, int height, const
img.data[ i ] = pic[ i ];
}
}
else if( textureFormat == FMT_RGBA16F )
{
img.Alloc( scaledWidth * scaledHeight * 8 );
for( int i = 0; i < img.dataSize; i++ )
{
img.data[ i ] = pic[ i ];
}
}
else
{
fileData.format = textureFormat = FMT_RGBA8;
@ -599,21 +578,6 @@ void idBinaryImage::Load2DAtlasMipchainFromMemory( int width, int height, const
dxtPic = NULL;
}
// downsample for the next level
/*
byte* shrunk = NULL;
if( gammaMips )
{
shrunk = R_MipMapWithGamma( pic, scaledWidth, scaledHeight );
}
else
{
shrunk = R_MipMap( pic, scaledWidth, scaledHeight );
}
Mem_Free( pic );
pic = shrunk;
*/
Mem_Free( pic );
}
@ -735,6 +699,15 @@ void idBinaryImage::LoadCubeFromMemory( int width, const byte* pics[6], int numL
dxt.CompressImageDXT5Fast( padSrc, img.data, padSize, padSize );
}
}
else if( textureFormat == FMT_R11G11B10F )
{
// RB: copy it as it was a RGBA8 because of the same size
img.Alloc( padSize * padSize * 4 );
for( int i = 0; i < img.dataSize; i++ )
{
img.data[ i ] = pic[ i ];
}
}
else
{
fileData.format = textureFormat = FMT_RGBA8;
@ -744,7 +717,11 @@ void idBinaryImage::LoadCubeFromMemory( int width, const byte* pics[6], int numL
// downsample for the next level
byte* shrunk = NULL;
if( gammaMips )
if( textureFormat == FMT_R11G11B10F )
{
shrunk = R_MipMapR11G11B10F( pic, scaledWidth, scaledWidth );
}
else if( gammaMips )
{
shrunk = R_MipMapWithGamma( pic, scaledWidth, scaledWidth );
}
@ -785,7 +762,7 @@ ID_TIME_T idBinaryImage::WriteGeneratedFile( ID_TIME_T sourceFileTime )
idLib::Warning( "idBinaryImage: Could not open file '%s'", binaryFileName.c_str() );
return FILE_NOT_FOUND_TIMESTAMP;
}
idLib::Printf( "Writing %s: %ix%i\n", binaryFileName.c_str(), fileData.width, fileData.height );
//idLib::Printf( "Writing %s: %ix%i\n", binaryFileName.c_str(), fileData.width, fileData.height );
fileData.headerMagic = BIMAGE_MAGIC;
fileData.sourceFileTime = sourceFileTime;

View file

@ -97,7 +97,7 @@ enum textureFormat_t
FMT_Y16_X16, // 32 bpp
FMT_RGB565, // 16 bpp
// RB: don't change above for .bimage compatibility up until RBDOOM-3-BFG 1.1
// ^-- used in BFG edition, don't change above for .bimage compatibility
FMT_ETC1_RGB8_OES, // 4 bpp
FMT_SHADOW_ARRAY, // 32 bpp * 6
FMT_RG16F, // 32 bpp
@ -127,10 +127,6 @@ enum textureColor_t
CFM_NORMAL_DXT5, // XY format and use the fast DXT5 compressor
CFM_YCOCG_DXT5, // convert RGBA to CoCg_Y format
CFM_GREEN_ALPHA, // Copy the alpha channel to green
// RB: don't change above for legacy .bimage compatibility
CFM_YCOCG_RGBA8,
// RB end
};
/*
@ -207,6 +203,8 @@ No texture is ever used that does not have a corresponding idImage.
static const int MAX_TEXTURE_LEVELS = 14;
// How is this texture used? Determines the storage and color format
// NOTE: be very careful when editing these because it might break older .bimage files or the lookup name
// Only add new entries at the bottom
typedef enum
{
TD_SPECULAR, // may be compressed, and always zeros the alpha channel
@ -227,28 +225,33 @@ typedef enum
TD_HIGHQUALITY_CUBE, // motorsep - Uncompressed cubemap texture (RGB colorspace)
TD_LOWQUALITY_CUBE, // motorsep - Compressed cubemap texture (RGB colorspace DXT5)
TD_SHADOW_ARRAY, // 2D depth buffer array for shadow mapping
TD_RG16F,
TD_RGBA16F,
TD_RGBA16S,
TD_RGBA32F,
TD_R32F,
TD_RG16F, // BRDF lookup table
TD_RGBA16F, // RT = render target format only, not written to disk
TD_RGBA16S, // RT only
TD_RGBA32F, // RT only
TD_R11G11B10F, // memory efficient HDR RGB format with only 32bpp
// ^-- used up until RBDOOM-3-BFG 1.3
TD_HDRI, // RB: R11G11B10F or BC6
// RB end
TD_R8F, // Stephen: Added for ambient occlusion render target.
TD_LDR, // Stephen: Added for SRGB render target when tonemapping.
TD_DEPTH_STENCIL, // depth buffer and stencil buffer
TD_R32F, // RT only
TD_R8F, // SP: RT only, added for ambient occlusion
TD_LDR, // SP: RT only, added for SRGB render target when tonemapping
TD_DEPTH_STENCIL, // SP: RT only, depth buffer and stencil buffer
} textureUsage_t;
// NOTE: be very careful when editing these because it might break older .bimage files or the lookup name
// Only add new entries at the bottom
typedef enum
{
CF_2D, // not a cube map
CF_NATIVE, // _px, _nx, _py, etc, directly sent to GL
CF_CAMERA, // _forward, _back, etc, rotated and flipped as needed before sending to GL
CF_QUAKE1, // _ft, _bk, etc, rotated and flipped as needed before sending to GL
CF_PANORAMA, // TODO latlong encoded HDRI panorama typically used by Substance or Blender
CF_PANORAMA, // RB: latlong encoded HDRI panorama typically used by Substance or Blender
CF_2D_ARRAY, // not a cube map but not a single 2d texture either
CF_2D_PACKED_MIPCHAIN, // usually 2d but can be an octahedron, packed mipmaps into single 2d texture atlas and limited to dim^2
// ^-- used up until RBDOOM-3-BFG 1.3
CF_SINGLE, // SP: A single texture cubemap. All six sides in one image.
CF_QUAKE1, // RB: _ft, _bk, etc, rotated and flipped as needed before sending to GL
} cubeFiles_t;
typedef void ( *ImageGeneratorFunction )( idImage* image, nvrhi::ICommandList* commandList );
@ -505,12 +508,15 @@ void R_WriteEXR( const char* filename, const void* data, int channelsPerPixel, i
class idImageManager
{
friend class idImage;
public:
idImageManager()
{
insideLevelLoad = false;
preloadingMapImages = false;
cacheImages = false;
commandList = nullptr;
}
@ -593,10 +599,6 @@ public:
idImage* taaFeedback1Image;
idImage* taaFeedback2Image;
idImage* bloomRenderImage[2];
//idImage* glowImage[2]; // contains any glowable surface information.
//idImage* glowDepthImage[2];
//idImage* accumTransparencyImage;
//idImage* revealTransparencyImage;
idImage* envprobeHDRImage;
idImage* envprobeDepthImage;
idImage* heatmap5Image;
@ -636,13 +638,18 @@ public:
bool ExcludePreloadImage( const char* name );
idList<idImage*, TAG_IDLIB_LIST_IMAGE> images;
private:
idHashIndex imageHash;
static void CacheGlobalIlluminationData_f( const idCmdArgs& args ); // RB
static void R_ListImages_f( const idCmdArgs& args );
// Transient list of images to load on the main thread to the gpu. Freed after images are loaded.
idList<idImage*, TAG_IDLIB_LIST_IMAGE> imagesToLoad;
bool insideLevelLoad; // don't actually load images now
bool preloadingMapImages; // unless this is set
bool cacheImages; // similar to preload but surpresses prints
nvrhi::CommandListHandle commandList;
};
@ -663,6 +670,7 @@ byte* R_ResampleTexture( const byte* in, int inwidth, int inheight, int outwidth
byte* R_MipMapWithAlphaSpecularity( const byte* in, int width, int height );
byte* R_MipMapWithGamma( const byte* in, int width, int height );
byte* R_MipMap( const byte* in, int width, int height );
byte* R_MipMapR11G11B10F( const byte* in, int width, int height );
// these operate in-place on the provided pixels
void R_BlendOverTexture( byte* data, int pixelCount, const byte blend[4] );
@ -674,8 +682,10 @@ void R_ApplyCubeMapTransforms( int i, byte* data, int size );
// SP begin
// This method takes in a cubemap from a single image. Depending on the side (0-5),
// the image will be extracted from data and returned. The dimensions will be size x size.
byte* R_GenerateCubeMapSideFromSingleImage( byte* data, int srcWidth, int srcHeight, int size, int side );
byte* R_GenerateCubeMapSideFromSingleImage( const byte* in, int srcWidth, int srcHeight, int size, int side );
// SP end
// RB
byte* R_GenerateCubeMapSideFromPanoramaImage( const byte* in, int srcWidth, int srcHeight, int size, int side );
idVec4 R_CalculateMipRect( uint dimensions, uint mip );
int R_CalculateUsedAtlasPixels( int dimensions );

View file

@ -137,7 +137,7 @@ static int R_QsortImageName( const void* a, const void* b )
R_ListImages_f
===============
*/
void R_ListImages_f( const idCmdArgs& args )
void idImageManager::R_ListImages_f( const idCmdArgs& args )
{
int i, partialSize;
idImage* image;
@ -356,7 +356,11 @@ idImage* idImageManager::ImageFromFunction( const char* _name, ImageGeneratorFun
{
// strip any .tga file extensions from anywhere in the _name
idStr name = _name;
name.Replace( ".tga", "" );
idStrList imageFormats = { ".tga", ".jpg", ".png", ".exr", ".hdr" };
for( auto& ext : imageFormats )
{
name.Replace( ext, "" );
}
name.BackSlashesToSlashes();
// see if the image already exists
@ -413,7 +417,11 @@ idImage* idImageManager::ImageFromFile( const char* _name, textureFilter_t filte
// strip any .tga file extensions from anywhere in the _name, including image program parameters
idStrStatic< MAX_OSPATH > name = _name;
name.Replace( ".tga", "" );
idStrList imageFormats = { ".tga", ".jpg", ".png", ".exr", ".hdr" };
for( auto& ext : imageFormats )
{
name.Replace( ext, "" );
}
name.BackSlashesToSlashes();
//
@ -598,7 +606,6 @@ idImageManager::GetImage
*/
idImage* idImageManager::GetImage( const char* _name ) const
{
if( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 )
{
declManager->MediaPrint( "DEFAULTED\n" );
@ -607,7 +614,11 @@ idImage* idImageManager::GetImage( const char* _name ) const
// strip any .tga file extensions from anywhere in the _name, including image program parameters
idStr name = _name;
name.Replace( ".tga", "" );
idStrList imageFormats = { ".tga", ".jpg", ".png", ".exr", ".hdr" };
for( auto& ext : imageFormats )
{
name.Replace( ext, "" );
}
name.BackSlashesToSlashes();
//
@ -759,6 +770,7 @@ void idImageManager::Init()
CreateIntrinsicImages();
cmdSystem->AddCommand( "reloadImages", R_ReloadImages_f, CMD_FL_RENDERER, "reloads images" );
cmdSystem->AddCommand( "cacheGlobalIlluminationData", CacheGlobalIlluminationData_f, CMD_FL_RENDERER, "turn env/maps/*.exr files into .bimage files" );
#endif
cmdSystem->AddCommand( "listImages", R_ListImages_f, CMD_FL_RENDERER, "lists images" );
cmdSystem->AddCommand( "combineCubeImages", R_CombineCubeImages_f, CMD_FL_RENDERER, "combines six images for roq compression" );
@ -1097,3 +1109,52 @@ void idImageManager::LoadDeferredImages( nvrhi::ICommandList* _commandList )
globalImages->imagesToLoad.Clear();
}
#include "CmdlineProgressbar.h"
#if !defined( DMAP )
void idImageManager::CacheGlobalIlluminationData_f( const idCmdArgs& args )
{
common->Printf( "Caching images to bimage files...\n" );
int start = Sys_Milliseconds();
globalImages->preloadingMapImages = true;
globalImages->cacheImages = true;
idFileList* files = fileSystem->ListFilesTree( "env/maps", "*.exr", true );
int numFiles = files->GetNumFiles();
CommandlineProgressBar progressBar( numFiles, renderSystem->GetWidth(), renderSystem->GetHeight() );
progressBar.Start();
for( int i = 0; i < files->GetNumFiles(); i++ )
{
const char* filename = files->GetFile( i );
if( idStr::FindText( filename, "envprobe" ) != -1 )
{
if( idStr::FindText( filename, "_spec" ) != -1 )
{
globalImages->ImageFromFile( filename, TF_DEFAULT, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
}
else
{
globalImages->ImageFromFile( filename, TF_LINEAR, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
}
}
else if( idStr::FindText( filename, "lightgrid" ) != -1 )
{
globalImages->ImageFromFile( filename, TF_LINEAR, TR_CLAMP, TD_R11G11B10F, CF_2D );
}
progressBar.Increment( true );
}
fileSystem->FreeFileList( files );
int end = Sys_Milliseconds();
common->Printf( "%05d images cached in %5.1f seconds\n", numFiles, ( end - start ) * 0.001 );
common->Printf( "----------------------------------------\n" );
globalImages->preloadingMapImages = false;
globalImages->cacheImages = false;
}
#endif

View file

@ -573,6 +573,7 @@ static void LoadEXR( const char* filename, unsigned char** pic, int* width, int*
if( ret != 0 )
{
common->Error( "LoadEXR( %s ): %s\n", filename, err );
FreeEXRErrorMessage( err );
return;
}
}
@ -852,7 +853,7 @@ void R_WriteEXR( const char* filename, const void* rgba16f, int channelsPerPixel
if( size == 0 )
{
common->Error( "R_WriteEXR( %s ): Save EXR err: %s\n", filename, err );
FreeEXRErrorMessage( err );
goto cleanup;
}
@ -905,14 +906,14 @@ static void LoadHDR( const char* filename, unsigned char** pic, int* width, int*
int32 numChannels;
float* rgba = stbi_loadf_from_memory( ( stbi_uc const* ) fbuffer, fileSize, width, height, &numChannels, 0 );
float* rgb = stbi_loadf_from_memory( ( stbi_uc const* ) fbuffer, fileSize, width, height, &numChannels, 0 );
if( numChannels != 3 )
{
common->Error( "LoadHDR( %s ): HDR has not 3 channels\n", filename );
}
if( rgba )
if( rgb )
{
int32 pixelCount = *width * *height;
byte* out = ( byte* )R_StaticAlloc( pixelCount * 4, TAG_IMAGE );
@ -921,7 +922,7 @@ static void LoadHDR( const char* filename, unsigned char** pic, int* width, int*
// convert to packed R11G11B10F as uint32 for each pixel
const float* src = rgba;
const float* src = rgb;
byte* dst = out;
for( int i = 0; i < pixelCount; i++ )
{
@ -936,11 +937,11 @@ static void LoadHDR( const char* filename, unsigned char** pic, int* width, int*
uint32_t value = float3_to_r11g11b10f( p );
*( uint32_t* )dst = value;
src += 4;
src += 3;
dst += 4;
}
free( rgba );
free( rgb );
}
Mem_Free( ( void* )fbuffer );
@ -1268,6 +1269,52 @@ bool R_LoadCubeImages( const char* imgName, cubeFiles_t extensions, byte* pics[6
return true;
}
if( extensions == CF_PANORAMA )
{
ID_TIME_T thisTime;
byte* thisPic[1];
thisPic[0] = nullptr;
if( pics )
{
R_LoadImageProgram( imgName, thisPic, &width, &height, &thisTime );
}
else
{
// load just the timestamps
R_LoadImageProgram( imgName, nullptr, &width, &height, &thisTime );
}
if( thisTime == FILE_NOT_FOUND_TIMESTAMP )
{
return false;
}
if( timestamp )
{
if( thisTime > *timestamp )
{
*timestamp = thisTime;
}
}
if( pics )
{
cubeMapSize = 1024;
*outSize = cubeMapSize;
for( int i = 0; i < 6; i++ )
{
pics[i] = R_GenerateCubeMapSideFromPanoramaImage( thisPic[0], width, height, cubeMapSize, i );
}
R_StaticFree( thisPic[0] );
}
return true;
}
for( i = 0 ; i < 6 ; i++ )
{
idStr::snPrintf( fullName, sizeof( fullName ), "%s%s", imgName, sides[i] );

View file

@ -1248,6 +1248,41 @@ CONSOLE_COMMAND( makeImageHeader, "load an image and turn it into a .h file", NU
Mem_Free( buffer );
}
class idSortColors : public idSort_Quick< idVec3, idSortColors >
{
public:
int SizeMetric( const idVec3& v ) const
{
return v.x * v.x + v.y * v.y + v.z * v.z;
}
int Compare( const idVec3& a, const idVec3& b ) const
{
//idVec3 diff = b - a;
//return SizeMetric( diff );
return SizeMetric( a ) - SizeMetric( b );
}
};
idVec3 Average( const idList<idVec3>& colors )
{
idVec3 avg = vec3_zero;
int numColors = colors.Num();
for( int i = 0; i < numColors; i++ )
{
avg += colors[i];
}
avg *= ( 1.0f / numColors );
return avg;
}
idVec3 Median( const idList<idVec3>& sortedPal )
{
return sortedPal[sortedPal.Num() / 2];
}
CONSOLE_COMMAND( makePaletteHeader, "load a .pal palette, build an image from it and turn it into a .h file", NULL )
{
if( args.Argc() < 2 )
@ -1280,17 +1315,66 @@ CONSOLE_COMMAND( makePaletteHeader, "load a .pal palette, build an image from it
int numColors = src.ParseInt();
//idList<id
byte rgb[3];
idList<idVec3> colors;
colors.AssureSize( numColors );
idVec3 rgb;
for( int i = 0; i < numColors; i++ )
{
rgb[0] = src.ParseInt();
rgb[1] = src.ParseInt();
rgb[2] = src.ParseInt();
idLib::Printf( "RGB( %d, %d, %d ),\n", rgb[0], rgb[1], rgb[2] );
colors[ i ] = rgb;
//idLib::Printf( "RGB( %d, %d, %d ),\n", (int)rgb[0], (int)rgb[1], (int)rgb[2] );
}
idLib::Printf( "// SORTED ============\n" );
colors.SortWithTemplate( idSortColors() );
idLib::Printf( "const float3 palette[NUM_COLORS] = // %d\n{\n", numColors );
for( int i = 0; i < numColors; i++ )
{
rgb = colors[ i ];
idLib::Printf( "\tRGB( %d, %d, %d ),\n", ( int )rgb[0], ( int )rgb[1], ( int )rgb[2] );
}
idLib::Printf( "};\n\n" );
// calc the median absolute deviation
idVec3 median = Median( colors );
idList<idVec3> deviations;
deviations.AssureSize( numColors );
for( int i = 0; i < numColors; i++ )
{
idVec3 diff = colors[i] - median;
deviations[i].x = idMath::Fabs( diff.x );
deviations[i].y = idMath::Fabs( diff.y );
deviations[i].z = idMath::Fabs( diff.z );
}
deviations.SortWithTemplate( idSortColors() );
rgb = Median( deviations );
idLib::Printf( "const float3 medianAbsoluteDeviation = RGB( %d, %d, %d );\n", ( int )rgb[0], ( int )rgb[1], ( int )rgb[2] );
// calc the standard deviation
idVec3 avg = Average( colors );
idVec3 deviation = vec3_zero;
for( int i = 0; i < numColors; i++ )
{
idVec3 diff = colors[i] - avg;
deviation.x += idMath::Fabs( diff.x );
deviation.y += idMath::Fabs( diff.y );
deviation.z += idMath::Fabs( diff.z );
}
deviation *= ( 1.0f / numColors );
rgb = deviation;
idLib::Printf( "const float3 deviation = RGB( %d, %d, %d );\n", ( int )rgb[0], ( int )rgb[1], ( int )rgb[2] );
fileSystem->FreeFile( palBuffer );
filename.StripFileExtension();
@ -1364,4 +1448,4 @@ CONSOLE_COMMAND( makePaletteHeader, "load a .pal palette, build an image from it
Mem_Free( buffer );
*/
}
}

View file

@ -156,11 +156,11 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_DEPTH;
break;
// sp begin
// SP begin
case TD_DEPTH_STENCIL:
opts.format = FMT_DEPTH_STENCIL;
break;
// sp end
// SP end
case TD_SHADOW_ARRAY:
opts.format = FMT_SHADOW_ARRAY;
@ -200,6 +200,7 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_DXT5;
opts.colorFormat = CFM_YCOCG_DXT5;
break;
case TD_SPECULAR:
opts.gammaMips = true;
opts.format = FMT_DXT1;
@ -223,16 +224,19 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_DXT5;
opts.colorFormat = CFM_DEFAULT;
break;
case TD_BUMP:
opts.format = FMT_DXT5;
opts.colorFormat = CFM_NORMAL_DXT5;
break;
case TD_FONT:
opts.format = FMT_DXT1;
opts.colorFormat = CFM_GREEN_ALPHA;
opts.numLevels = 4; // We only support 4 levels because we align to 16 in the exporter
opts.gammaMips = true;
break;
case TD_LIGHT:
// RB: TODO check binary format version
// D3 BFG assets require RGB565 but it introduces color banding
@ -240,16 +244,20 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_RGB565; //FMT_RGBA8;
opts.gammaMips = true;
break;
case TD_LOOKUP_TABLE_MONO:
opts.format = FMT_INT8;
break;
case TD_LOOKUP_TABLE_ALPHA:
opts.format = FMT_ALPHA;
break;
case TD_LOOKUP_TABLE_RGB1:
case TD_LOOKUP_TABLE_RGBA:
opts.format = FMT_RGBA8;
break;
// motorsep 05-17-2015; added this for uncompressed cubemap/skybox textures
case TD_HIGHQUALITY_CUBE:
opts.colorFormat = CFM_DEFAULT;
@ -261,6 +269,13 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_DXT5;
opts.gammaMips = true;
break;
// motorsep end
case TD_HDRI:
opts.format = FMT_R11G11B10F;
//opts.numLevels = 1;
break;
default:
assert( false );
opts.format = FMT_RGBA8;
@ -364,9 +379,6 @@ void idImage::GenerateImage( const byte* pic, int width, int height, textureFilt
#if defined( USE_NVRHI ) && !defined( DMAP )
if( commandList )
{
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
const int bytesPerBlock = info.bytesPerBlock;
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
for( int i = 0; i < im.NumImages(); i++ )
@ -439,15 +451,8 @@ void idImage::GenerateCubeImage( const byte* pic[6], int size, textureFilter_t f
AllocImage();
#if defined( USE_NVRHI ) && !defined( DMAP )
int numChannels = 4;
int bytesPerPixel = numChannels;
if( opts.format == FMT_ALPHA || opts.format == FMT_DXT1 || opts.format == FMT_INT8 || opts.format == FMT_R8 )
{
bytesPerPixel = 1;
}
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
bytesPerPixel = info.bytesPerBlock;
//const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
//bytesPerPixel = info.bytesPerBlock;
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
@ -555,9 +560,6 @@ void idImage::ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandL
// RB: the following does not load the source images from disk because pic is NULL
// but it tries to get the timestamp to see if we have a newer file than the one in the compressed .bimage
// TODO also check for alternative names like .png suffices or _rmao.png or even _rmaod.png files
// to support the PBR code path
if( com_productionMode.GetInteger() != 0 )
{
sourceFileTime = FILE_NOT_FOUND_TIMESTAMP;
@ -574,7 +576,7 @@ void idImage::ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandL
{
opts.textureType = TT_2D_ARRAY;
}
else if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA || cubeFiles == CF_QUAKE1 || cubeFiles == CF_SINGLE )
else if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA || cubeFiles == CF_QUAKE1 || cubeFiles == CF_SINGLE || cubeFiles == CF_PANORAMA )
{
opts.textureType = TT_CUBIC;
repeat = TR_CLAMP;
@ -606,6 +608,12 @@ void idImage::ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandL
idStrStatic< MAX_OSPATH > generatedName = GetName();
GetGeneratedName( generatedName, usage, cubeFiles );
//if( generatedName.Find( "textures/base_floor/a_stairs_d02", false ) >= 0 )
//{
// #924
//int c = 1;
//}
// RB: try to load the .bimage and skip if sourceFileTime is newer
idBinaryImage im( generatedName );
binaryFileTime = im.LoadFromGeneratedFile( sourceFileTime );
@ -700,10 +708,6 @@ void idImage::ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandL
binarizeReason = va( "binarize: binary file not found '%s'", generatedName.c_str() );
}
else if( header.colorFormat != opts.colorFormat )
{
binarizeReason = va( "binarize: mismatch color format '%s'", generatedName.c_str() );
}
else if( header.colorFormat != opts.colorFormat )
{
binarizeReason = va( "binarize: mismatched color format '%s'", generatedName.c_str() );
}
@ -714,7 +718,7 @@ void idImage::ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandL
//else if( toolUsage )
// binarizeReason = va( "binarize: tool usage '%s'", generatedName.c_str() );
if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA || cubeFiles == CF_QUAKE1 || cubeFiles == CF_SINGLE )
if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA || cubeFiles == CF_QUAKE1 || cubeFiles == CF_SINGLE || cubeFiles == CF_PANORAMA )
{
int size;
byte* pics[6];
@ -737,7 +741,11 @@ void idImage::ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandL
DeriveOpts();
// foresthale 2014-05-30: give a nice progress display when binarizing
commonLocal.LoadPacifierBinarizeFilename( generatedName.c_str(), binarizeReason.c_str() );
if( !globalImages->cacheImages )
{
commonLocal.LoadPacifierBinarizeFilename( generatedName.c_str(), binarizeReason.c_str() );
}
if( opts.numLevels > 1 )
{
commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.width * 6 * 4 / 3 );
@ -796,8 +804,6 @@ void idImage::ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandL
memset( clear.Ptr(), 0, clear.Size() );
#if defined( USE_NVRHI ) && !defined( DMAP )
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
for( int level = 0; level < opts.numLevels; level++ )
{
@ -832,14 +838,21 @@ void idImage::ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandL
// RB: convert to compressed DXT or whatever choosen target format
if( cubeFiles == CF_2D_PACKED_MIPCHAIN )
{
commonLocal.LoadPacifierBinarizeFilename( generatedName.c_str(), binarizeReason.c_str() );
if( !globalImages->cacheImages )
{
commonLocal.LoadPacifierBinarizeFilename( generatedName.c_str(), binarizeReason.c_str() );
}
commonLocal.LoadPacifierBinarizeProgressTotal( width * opts.height );
im.Load2DAtlasMipchainFromMemory( width, opts.height, pic, opts.numLevels, opts.format, opts.colorFormat );
}
else
{
commonLocal.LoadPacifierBinarizeFilename( generatedName.c_str(), binarizeReason.c_str() );
if( !globalImages->cacheImages )
{
commonLocal.LoadPacifierBinarizeFilename( generatedName.c_str(), binarizeReason.c_str() );
}
if( opts.numLevels > 1 )
{
commonLocal.LoadPacifierBinarizeProgressTotal( opts.width * opts.height * 4 / 3 );
@ -870,9 +883,6 @@ void idImage::ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandL
AllocImage();
#if defined( USE_NVRHI ) && !defined( DMAP )
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
const int bytesPerPixel = info.bytesPerBlock / info.blockSize;
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
for( int i = 0; i < im.NumImages(); i++ )
@ -880,45 +890,7 @@ void idImage::ActuallyLoadImage( bool fromBackEnd, nvrhi::ICommandList* commandL
const bimageImage_t& img = im.GetImageHeader( i );
const byte* pic = im.GetImageData( i );
#if 0
if( opts.format == FMT_RGB565 )
{
int bufferW = img.width;
int bufferH = img.height;
if( IsCompressed() )
{
bufferW = ( img.width + 3 ) & ~3;
bufferH = ( img.height + 3 ) & ~3;
}
int size = bufferW * bufferH * BitsForFormat( opts.format ) / 8;
byte* data = ( byte* )Mem_Alloc16( size, TAG_IMAGE );
memcpy( data, pic, size );
byte* imgData = ( byte* )pic;
for( int j = 0; j < size; j += 2 )
{
data[i] = imgData[i + 1];
data[i + 1] = imgData[i];
}
commandList->writeTexture( texture, img.destZ, img.level, data, GetRowPitch( opts.format, img.width ) );
Mem_Free16( data );
}
else
#endif
{
int bufferW = img.width;
if( IsCompressed() )
{
bufferW = ( img.width + 3 ) & ~3;
}
commandList->writeTexture( texture, img.destZ, img.level, pic, GetRowPitch( opts.format, img.width ) );
}
commandList->writeTexture( texture, img.destZ, img.level, pic, GetRowPitch( opts.format, img.width ) );
}
commandList->setPermanentTextureState( texture, nvrhi::ResourceStates::ShaderResource );
commandList->commitBarriers();
@ -983,26 +955,10 @@ void idImage::UploadScratch( const byte* data, int cols, int rows, nvrhi::IComma
}
#if defined( USE_NVRHI )
int numChannels = 4;
int bytesPerPixel = numChannels;
if( opts.format == FMT_ALPHA || opts.format == FMT_DXT1 || opts.format == FMT_INT8 || opts.format == FMT_R8 )
{
bytesPerPixel = 1;
}
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
bytesPerPixel = info.bytesPerBlock;
SetSamplerState( TF_LINEAR, TR_CLAMP );
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
int bufferW = opts.width;
if( IsCompressed() )
{
bufferW = ( opts.width + 3 ) & ~3;
}
for( int i = 0; i < 6; i++ )
{
commandList->writeTexture( texture, i, 0, pic[i], GetRowPitch( opts.format, opts.width ) );
@ -1032,24 +988,8 @@ void idImage::UploadScratch( const byte* data, int cols, int rows, nvrhi::IComma
if( data != NULL && commandList != NULL )
{
int numChannels = 4;
int bytesPerPixel = numChannels;
if( opts.format == FMT_ALPHA || opts.format == FMT_DXT1 || opts.format == FMT_INT8 || opts.format == FMT_R8 || opts.format == FMT_LUM8 )
{
bytesPerPixel = 1;
}
const nvrhi::FormatInfo& info = nvrhi::getFormatInfo( texture->getDesc().format );
bytesPerPixel = info.bytesPerBlock;
SetSamplerState( TF_LINEAR, TR_REPEAT );
int bufferW = opts.width;
if( IsCompressed() )
{
bufferW = ( opts.width + 3 ) & ~3;
}
commandList->beginTrackingTextureState( texture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common );
commandList->writeTexture( texture, 0, 0, data, GetRowPitch( opts.format, opts.width ) );
@ -1242,7 +1182,7 @@ void idImage::Reload( bool force, nvrhi::ICommandList* commandList )
if( !force )
{
ID_TIME_T current;
if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA || cubeFiles == CF_QUAKE1 || cubeFiles == CF_SINGLE )
if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA || cubeFiles == CF_QUAKE1 || cubeFiles == CF_SINGLE || cubeFiles == CF_PANORAMA )
{
R_LoadCubeImages( imgName, cubeFiles, NULL, NULL, &current );
}

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2021 Robert Beckebans
Copyright (C) 2021-2025 Robert Beckebans
Copyright (C) 2021 Stephen Pridham
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -33,6 +33,8 @@ If you have questions concerning this license or the applicable additional terms
#include "RenderCommon.h"
#include "../libs/mesa/format_r11g11b10f.h"
/*
================
R_ResampleTexture
@ -463,6 +465,152 @@ byte* R_MipMap( const byte* in, int width, int height )
return out;
}
// RB begin
byte* R_MipMapR11G11B10F( const byte* in, int width, int height )
{
int i, j;
const byte* in_p;
byte* out, *out_p;
int row;
int newWidth, newHeight;
if( width < 1 || height < 1 || ( width + height == 2 ) )
{
return NULL;
}
row = width * 4;
newWidth = width >> 1;
newHeight = height >> 1;
if( !newWidth )
{
newWidth = 1;
}
if( !newHeight )
{
newHeight = 1;
}
out = ( byte* )R_StaticAlloc( newWidth * newHeight * 4, TAG_IMAGE );
out_p = out;
in_p = in;
width >>= 1;
height >>= 1;
typedef union
{
uint32 i;
byte b[4];
} convert_t;
if( width == 0 || height == 0 )
{
width += height; // get largest
for( i = 0 ; i < width ; i++, out_p += 4, in_p += 8 )
{
convert_t p1;
p1.b[0] = in_p[0];
p1.b[1] = in_p[1];
p1.b[2] = in_p[2];
p1.b[3] = in_p[3];
convert_t p2;
p2.b[0] = in_p[4];
p2.b[1] = in_p[5];
p2.b[2] = in_p[6];
p2.b[3] = in_p[7];
float c1[3];
r11g11b10f_to_float3( p1.i, c1 );
float c2[3];
r11g11b10f_to_float3( p2.i, c2 );
float rgb[3];
rgb[0] = ( c1[0] + c2[0] ) * 0.5f;
rgb[1] = ( c1[1] + c2[1] ) * 0.5f;
rgb[2] = ( c1[2] + c2[2] ) * 0.5f;
p1.i = float3_to_r11g11b10f( rgb );
out_p[0] = p1.b[0];
out_p[1] = p1.b[1];
out_p[2] = p1.b[2];
out_p[3] = p1.b[3];
//out_p[0] = ( in_p[0] + in_p[4] ) >> 1;
//out_p[1] = ( in_p[1] + in_p[5] ) >> 1;
//out_p[2] = ( in_p[2] + in_p[6] ) >> 1;
//out_p[3] = ( in_p[3] + in_p[7] ) >> 1;
}
return out;
}
for( i = 0 ; i < height ; i++, in_p += row )
{
for( j = 0 ; j < width ; j++, out_p += 4, in_p += 8 )
{
convert_t p1;
p1.b[0] = in_p[0];
p1.b[1] = in_p[1];
p1.b[2] = in_p[2];
p1.b[3] = in_p[3];
convert_t p2;
p2.b[0] = in_p[4];
p2.b[1] = in_p[5];
p2.b[2] = in_p[6];
p2.b[3] = in_p[7];
convert_t p3;
p3.b[0] = in_p[row + 0];
p3.b[1] = in_p[row + 1];
p3.b[2] = in_p[row + 2];
p3.b[3] = in_p[row + 3];
convert_t p4;
p4.b[0] = in_p[row + 4];
p4.b[1] = in_p[row + 5];
p4.b[2] = in_p[row + 6];
p4.b[3] = in_p[row + 7];
float c1[3];
r11g11b10f_to_float3( p1.i, c1 );
float c2[3];
r11g11b10f_to_float3( p2.i, c2 );
float c3[3];
r11g11b10f_to_float3( p3.i, c3 );
float c4[3];
r11g11b10f_to_float3( p4.i, c4 );
float rgb[3];
rgb[0] = ( c1[0] + c2[0] + c3[0] + c4[0] ) * 0.25f;
rgb[1] = ( c1[1] + c2[1] + c3[1] + c4[1] ) * 0.25f;
rgb[2] = ( c1[2] + c2[2] + c3[2] + c4[2] ) * 0.25f;
p1.i = float3_to_r11g11b10f( rgb );
out_p[0] = p1.b[0];
out_p[1] = p1.b[1];
out_p[2] = p1.b[2];
out_p[3] = p1.b[3];
//out_p[0] = ( in_p[0] + in_p[4] + in_p[row + 0] + in_p[row + 4] ) >> 2;
//out_p[1] = ( in_p[1] + in_p[5] + in_p[row + 1] + in_p[row + 5] ) >> 2;
//out_p[2] = ( in_p[2] + in_p[6] + in_p[row + 2] + in_p[row + 6] ) >> 2;
//out_p[3] = ( in_p[3] + in_p[7] + in_p[row + 3] + in_p[row + 7] ) >> 2;
}
}
return out;
}
// RB end
/*
==================
R_BlendOverTexture
@ -631,8 +779,7 @@ int R_CalculateUsedAtlasPixels( int dimensions )
}
// SP begin
byte* R_GenerateCubeMapSideFromSingleImage( byte* data, int srcWidth, int srcHeight, int size, int side )
byte* R_GenerateCubeMapSideFromSingleImage( const byte* in, int srcWidth, int srcHeight, int size, int side )
{
size_t x = 0, y = 0;
switch( side )
@ -689,7 +836,7 @@ byte* R_GenerateCubeMapSideFromSingleImage( byte* data, int srcWidth, int srcHei
const size_t copySize = ( size_t )size * ( size_t )size * 4;
byte* out = ( byte* )R_StaticAlloc( copySize, TAG_IMAGE );
uint32_t* out_p = ( uint32_t* )out;
const uint32_t* in_p = ( uint32_t* )data + x + y * srcWidth;
const uint32_t* in_p = ( uint32_t* )in + x + y * srcWidth;
for( int j = 0; j < size; j++ )
{
@ -701,5 +848,321 @@ byte* R_GenerateCubeMapSideFromSingleImage( byte* data, int srcWidth, int srcHei
return out;
}
// SP end
// RB: ripped from cmft utils by Dario Manesku
/*
* Copyright 2014-2015 Dario Manesku. All rights reserved.
* License: http://www.opensource.org/licenses/BSD-2-Clause
*/
///
///
/// +----------+
/// | +---->+x |
/// | | |
/// | | +y |
/// |+z 2 |
/// +----------+----------+----------+----------+
/// | +---->+z | +---->+x | +---->-z | +---->-x |
/// | | | | | | | | |
/// | | -x | | +z | | +x | | -z |
/// |-y 1 |-y 4 |-y 0 |-y 5 |
/// +----------+----------+----------+----------+
/// | +---->+x |
/// | | |
/// | | -y |
/// |-z 3 |
/// +----------+
///
static const float s_faceUvVectors[6][3][3] =
{
{
// +x face
{ 0.0f, 0.0f, -1.0f }, // u -> -z
{ 0.0f, -1.0f, 0.0f }, // v -> -y
{ 1.0f, 0.0f, 0.0f }, // +x face
},
{
// -x face
{ 0.0f, 0.0f, 1.0f }, // u -> +z
{ 0.0f, -1.0f, 0.0f }, // v -> -y
{ -1.0f, 0.0f, 0.0f }, // -x face
},
{
// +y face
{ 1.0f, 0.0f, 0.0f }, // u -> +x
{ 0.0f, 0.0f, 1.0f }, // v -> +z
{ 0.0f, 1.0f, 0.0f }, // +y face
},
{
// -y face
{ 1.0f, 0.0f, 0.0f }, // u -> +x
{ 0.0f, 0.0f, -1.0f }, // v -> -z
{ 0.0f, -1.0f, 0.0f }, // -y face
},
{
// +z face
{ 1.0f, 0.0f, 0.0f }, // u -> +x
{ 0.0f, -1.0f, 0.0f }, // v -> -y
{ 0.0f, 0.0f, 1.0f }, // +z face
},
{
// -z face
{ -1.0f, 0.0f, 0.0f }, // u -> -x
{ 0.0f, -1.0f, 0.0f }, // v -> -y
{ 0.0f, 0.0f, -1.0f }, // -z face
}
};
enum
{
CMFT_FACE_POS_X = 0,
CMFT_FACE_NEG_X = 1,
CMFT_FACE_POS_Y = 2,
CMFT_FACE_NEG_Y = 3,
CMFT_FACE_POS_Z = 4,
CMFT_FACE_NEG_Z = 5,
};
enum
{
CMFT_EDGE_LEFT = 0,
CMFT_EDGE_RIGHT = 1,
CMFT_EDGE_TOP = 2,
CMFT_EDGE_BOTTOM = 3,
};
///
/// --> U _____
/// | | |
/// v | +Y |
/// V _____|_____|_____ _____
/// | | | | |
/// | -X | +Z | +X | -Z |
/// |_____|_____|_____|_____|
/// | |
/// | -Y |
/// |_____|
///
/// Neighbour faces in order: left, right, top, bottom.
/// FaceEdge is the edge that belongs to the neighbour face.
static const struct CubeFaceNeighbour
{
uint8_t m_faceIdx;
uint8_t m_faceEdge;
} s_cubeFaceNeighbours[6][4] =
{
{
//POS_X
{ CMFT_FACE_POS_Z, CMFT_EDGE_RIGHT },
{ CMFT_FACE_NEG_Z, CMFT_EDGE_LEFT },
{ CMFT_FACE_POS_Y, CMFT_EDGE_RIGHT },
{ CMFT_FACE_NEG_Y, CMFT_EDGE_RIGHT },
},
{
//NEG_X
{ CMFT_FACE_NEG_Z, CMFT_EDGE_RIGHT },
{ CMFT_FACE_POS_Z, CMFT_EDGE_LEFT },
{ CMFT_FACE_POS_Y, CMFT_EDGE_LEFT },
{ CMFT_FACE_NEG_Y, CMFT_EDGE_LEFT },
},
{
//POS_Y
{ CMFT_FACE_NEG_X, CMFT_EDGE_TOP },
{ CMFT_FACE_POS_X, CMFT_EDGE_TOP },
{ CMFT_FACE_NEG_Z, CMFT_EDGE_TOP },
{ CMFT_FACE_POS_Z, CMFT_EDGE_TOP },
},
{
//NEG_Y
{ CMFT_FACE_NEG_X, CMFT_EDGE_BOTTOM },
{ CMFT_FACE_POS_X, CMFT_EDGE_BOTTOM },
{ CMFT_FACE_POS_Z, CMFT_EDGE_BOTTOM },
{ CMFT_FACE_NEG_Z, CMFT_EDGE_BOTTOM },
},
{
//POS_Z
{ CMFT_FACE_NEG_X, CMFT_EDGE_RIGHT },
{ CMFT_FACE_POS_X, CMFT_EDGE_LEFT },
{ CMFT_FACE_POS_Y, CMFT_EDGE_BOTTOM },
{ CMFT_FACE_NEG_Y, CMFT_EDGE_TOP },
},
{
//NEG_Z
{ CMFT_FACE_POS_X, CMFT_EDGE_RIGHT },
{ CMFT_FACE_NEG_X, CMFT_EDGE_LEFT },
{ CMFT_FACE_POS_Y, CMFT_EDGE_TOP },
{ CMFT_FACE_NEG_Y, CMFT_EDGE_BOTTOM },
}
};
/// _u and _v should be center adressing and in [-1.0+invSize..1.0-invSize] range.
static inline void TexelCoordToVec( float* _out3f, float _u, float _v, uint8_t _faceId )
{
// out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
_out3f[0] = s_faceUvVectors[_faceId][0][0] * _u + s_faceUvVectors[_faceId][1][0] * _v + s_faceUvVectors[_faceId][2][0];
_out3f[1] = s_faceUvVectors[_faceId][0][1] * _u + s_faceUvVectors[_faceId][1][1] * _v + s_faceUvVectors[_faceId][2][1];
_out3f[2] = s_faceUvVectors[_faceId][0][2] * _u + s_faceUvVectors[_faceId][1][2] * _v + s_faceUvVectors[_faceId][2][2];
// Normalize.
const float invLen = 1.0f / sqrtf( _out3f[0] * _out3f[0] + _out3f[1] * _out3f[1] + _out3f[2] * _out3f[2] );
_out3f[0] *= invLen;
_out3f[1] *= invLen;
_out3f[2] *= invLen;
}
/// Notice: _faceSize should not be equal to one!
static inline float WarpFixupFactor( float _faceSize )
{
// Edge fixup.
// Based on Nvtt : http://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvtt/CubeSurface.cpp
if( _faceSize == 1.0f )
{
return 1.0f;
}
const float fs = _faceSize;
const float fsmo = fs - 1.0f;
return ( fs * fs ) / ( fsmo * fsmo * fsmo );
}
/// _u and _v should be center adressing and in [-1.0+invSize..1.0-invSize] range.
static inline void TexelCoordToVecWarp( float* _out3f, float _u, float _v, uint8_t _faceId, float _warpFixup )
{
_u = ( _warpFixup * _u * _u * _u ) + _u;
_v = ( _warpFixup * _v * _v * _v ) + _v;
TexelCoordToVec( _out3f, _u, _v, _faceId );
}
inline void vec3Mul( float* __restrict _result, const float* __restrict _a, float _b )
{
_result[0] = _a[0] * _b;
_result[1] = _a[1] * _b;
_result[2] = _a[2] * _b;
}
inline float vec3Dot( const float* __restrict _a, const float* __restrict _b )
{
return _a[0] * _b[0] + _a[1] * _b[1] + _a[2] * _b[2];
}
/// _u and _v are in [0.0 .. 1.0] range.
static inline void VecToTexelCoord( float& _u, float& _v, uint8_t& _faceIdx, const float* _vec )
{
const float absVec[3] =
{
fabsf( _vec[0] ),
fabsf( _vec[1] ),
fabsf( _vec[2] ),
};
const float max = fmaxf( fmaxf( absVec[0], absVec[1] ), absVec[2] );
// Get face id (max component == face vector).
if( max == absVec[0] )
{
_faceIdx = ( _vec[0] >= 0.0f ) ? uint8_t( CMFT_FACE_POS_X ) : uint8_t( CMFT_FACE_NEG_X );
}
else if( max == absVec[1] )
{
_faceIdx = ( _vec[1] >= 0.0f ) ? uint8_t( CMFT_FACE_POS_Y ) : uint8_t( CMFT_FACE_NEG_Y );
}
else //if (max == absVec[2])
{
_faceIdx = ( _vec[2] >= 0.0f ) ? uint8_t( CMFT_FACE_POS_Z ) : uint8_t( CMFT_FACE_NEG_Z );
}
// Divide by max component.
float faceVec[3];
vec3Mul( faceVec, _vec, 1.0f / max );
// Project other two components to face uv basis.
_u = ( vec3Dot( s_faceUvVectors[_faceIdx][0], faceVec ) + 1.0f ) * 0.5f;
_v = ( vec3Dot( s_faceUvVectors[_faceIdx][1], faceVec ) + 1.0f ) * 0.5f;
}
#define CMFT_RPI 0.31830988618379067153f
static inline void LatLongFromVec( float& _u, float& _v, const float _vec[3] )
{
const float phi = atan2f( _vec[0], _vec[2] );
const float theta = acosf( _vec[1] );
_u = ( idMath::PI + phi ) * ( 0.5f / idMath::PI );
_v = theta * CMFT_RPI;
}
static inline void VecFromLatLong( float _vec[3], float _u, float _v )
{
const float phi = _u * idMath::TWO_PI;
const float theta = _v * idMath::PI;
_vec[0] = -sinf( theta ) * sinf( phi );
_vec[1] = cosf( theta );
_vec[2] = -sinf( theta ) * cosf( phi );
}
byte* R_GenerateCubeMapSideFromPanoramaImage( const byte* in, int srcWidth, int srcHeight, int cubeWidth, int side )
{
size_t x = 0, y = 0;
const uint32 bytesPerPixel = 4;
const int copySize = cubeWidth * cubeWidth * bytesPerPixel;
byte* out = ( byte* )R_StaticAlloc( copySize, TAG_IMAGE );
uint32_t* out_p = ( uint32_t* )out;
const uint32 dstFaceSize = cubeWidth;
const uint32 dstPitch = dstFaceSize * bytesPerPixel;
//const uint32 dstFaceDataSize = dstPitch * dstFaceSize;
//const uint32 dstDataSize = dstFaceDataSize * 6;
const float srcWidthMinusOne = float( int32( srcWidth - 1 ) );
const float srcHeightMinusOne = float( int32( srcHeight - 1 ) );
const uint32 srcPitch = srcWidth * bytesPerPixel;
const float invDstFaceSizef = 1.0f / float( dstFaceSize );
// maybe wrong, done by observation
const idMat4 toDoomTransform( idAngles( -90, 0, -90 ).ToMat3(), vec3_origin );
byte* dstFaceData = ( byte* )out;// + face * dstFaceDataSize;
for( int y = 0; y < dstFaceSize; y++ )
{
byte* dstRowData = ( byte* )dstFaceData + y * dstPitch;
for( int x = 0; x < dstFaceSize; x++ )
{
// Cubemap (u,v) on current face.
const float uu = 2.0f * x * invDstFaceSizef - 1.0f;
const float vv = 2.0f * y * invDstFaceSizef - 1.0f;
// Get cubemap vector (x,y,z) from (u,v,faceIdx).
idVec3 vec;
TexelCoordToVec( &vec[0], uu, vv, side );
vec = toDoomTransform * vec;
// Convert cubemap vector (x,y,z) to latlong (u,v).
float xSrcf;
float ySrcf;
LatLongFromVec( xSrcf, ySrcf, &vec[0] );
// Convert from [0..1] to [0..(size-1)] range.
xSrcf *= srcWidthMinusOne;
ySrcf *= srcHeightMinusOne;
const int32 xSrc = int32( idMath::Fabs( idMath::Rint( xSrcf ) ) );
const int32 ySrc = int32( idMath::Fabs( idMath::Rint( ySrcf ) ) );
const byte* src = ( const byte* )in + ySrc * srcPitch + xSrc * bytesPerPixel ;
byte* dstColumnData = ( uint8_t* )dstRowData + x * bytesPerPixel;
dstColumnData[0] = src[0];
dstColumnData[1] = src[1];
dstColumnData[2] = src[2];
dstColumnData[3] = src[3];
}
}
return out;
}
// RB end

View file

@ -509,6 +509,7 @@ void idInteraction::UnlinkAndFree()
{
// clear the table pointer
idRenderWorldLocal* renderWorld = this->lightDef->world;
// RB: added check for NULL
if( renderWorld->interactionTable != NULL )
{

View file

@ -1285,6 +1285,17 @@ void idMaterial::ParseFragmentMap( idLexer& src, newShaderStage_t* newStage )
cubeMap = CF_SINGLE;
continue;
}
if( !token.Icmp( "panoramaMap" ) )
{
cubeMap = CF_PANORAMA;
continue;
}
if( !token.Icmp( "hdriMap" ) )
{
cubeMap = CF_PANORAMA;
td = TD_HDRI;
continue;
}
if( !token.Icmp( "nearest" ) )
{
tf = TF_NEAREST;
@ -1807,6 +1818,24 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
continue;
}
if( !token.Icmp( "panoramaMap" ) )
{
str = R_ParsePastImageProgram( src );
idStr::Copynz( imageName, str, sizeof( imageName ) );
cubeMap = CF_PANORAMA;
td = TD_HIGHQUALITY_CUBE;
continue;
}
if( !token.Icmp( "hdriMap" ) )
{
str = R_ParsePastImageProgram( src );
idStr::Copynz( imageName, str, sizeof( imageName ) );
cubeMap = CF_PANORAMA;
td = TD_HDRI;
continue;
}
if( !token.Icmp( "cubeMapSize" ) )
{
cubeMapSize = src.ParseInt();
@ -3960,7 +3989,7 @@ CONSOLE_COMMAND_SHIP( makeMaterials, "Make .mtr file from a models or textures f
return;
}
bool stripFolderFromMaterial = false;
bool ueMode = false;
idStr option;
for( int i = 1; i < args.Argc(); i++ )
@ -3970,7 +3999,7 @@ CONSOLE_COMMAND_SHIP( makeMaterials, "Make .mtr file from a models or textures f
if( option.IcmpPrefix( "Unreal" ) == 0 )
{
stripFolderFromMaterial = true;
ueMode = true;
}
}
@ -4043,8 +4072,9 @@ CONSOLE_COMMAND_SHIP( makeMaterials, "Make .mtr file from a models or textures f
materialName.CopyRange( baseName.c_str(), 0, baseName.Length() - 2 );
}
if( stripFolderFromMaterial )
if( ueMode )
{
// strip folder from material name
idStr matName;
materialName.ExtractFileName( matName );
materialName = matName;
@ -4143,7 +4173,7 @@ CONSOLE_COMMAND_SHIP( makeMaterials, "Make .mtr file from a models or textures f
if( testStamp != FILE_NOT_FOUND_TIMESTAMP )
{
if( name.Cmp( "_normal_opengl" ) == 0 )
if( name.Cmp( "_nor_dx" ) == 0 || name.Cmp( "_normal_directx" ) == 0 || ueMode )
{
mtrBuffer += va( "\tnormalmap invertGreen( %s )\n", testName.c_str() );
}
@ -4255,6 +4285,52 @@ CONSOLE_COMMAND_SHIP( makeMaterials, "Make .mtr file from a models or textures f
}
}
if( ueMode )
{
// ===============================
// test UE4 specular map
idStrList specNames = { "_specular" };
byte* specPic = NULL;
int specWidth = 0;
int specHeight = 0;
for( auto& name : specNames )
{
ID_TIME_T testStamp;
idStr testName = baseName + name + resName;
R_LoadImage( testName, &specPic, &specWidth, &specHeight, &testStamp, true, NULL );
if( testStamp != FILE_NOT_FOUND_TIMESTAMP )
{
// swap bytes to RMAO order
int c = specWidth * specHeight * 4;
for( int j = 0 ; j < c ; j += 4 )
{
byte ao = specPic[j + 0];
byte roughness = specPic[j + 1];
byte metal = specPic[j + 2];
specPic[j + 0] = roughness;
specPic[j + 1] = metal;
specPic[j + 2] = ao;
// put middle 0.5 value into alpha channel for the case we want to add displacement later
specPic[j + 3] = 128;
}
idStr mergedName = baseName + "_rmao.png";
R_WritePNG( mergedName, static_cast<byte*>( specPic ), 4, specWidth, specHeight, "fs_basepath" );
mergedName.StripFileExtension();
mtrBuffer += va( "\trmaomap %s\n", mergedName.c_str() );
R_StaticFree( specPic );
break;
}
}
}
if( roughPic )
{
R_StaticFree( roughPic );

View file

@ -75,7 +75,7 @@ private:
bool fileExclusive;
bool hasAnimations;
float maxJointVertDist; // maximum distance a vertex is separated from a joint
float maxJointVertDist = 10.0f; // maximum distance a vertex is separated from a joint
idList<int, TAG_MODEL> animIds;
idList<int, TAG_MODEL> bones;
idList<int, TAG_MODEL> MeshNodeIds;

View file

@ -1177,7 +1177,7 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
const textureUsage_t specUsage = din->specularImage->GetUsage();
// RB begin
if( useIBL && currentSpace->useLightGrid && r_useLightGrid.GetBool() )
if( useIBL && din->surf->area != NULL && r_useLightGrid.GetBool() )
{
idVec4 probeMins, probeMaxs, probeCenter;
@ -1199,9 +1199,11 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
SetVertexParm( RENDERPARM_WOBBLESKY_Z, probeCenter.ToFloatPtr() );
// use rpGlobalLightOrigin for lightGrid center
idVec4 lightGridOrigin( currentSpace->lightGridOrigin.x, currentSpace->lightGridOrigin.y, currentSpace->lightGridOrigin.z, 1.0f );
idVec4 lightGridSize( currentSpace->lightGridSize.x, currentSpace->lightGridSize.y, currentSpace->lightGridSize.z, 1.0f );
idVec4 lightGridBounds( currentSpace->lightGridBounds[0], currentSpace->lightGridBounds[1], currentSpace->lightGridBounds[2], 1.0f );
const LightGrid& lightGrid = din->surf->area->lightGrid;
idVec4 lightGridOrigin( lightGrid.lightGridOrigin.x, lightGrid.lightGridOrigin.y, lightGrid.lightGridOrigin.z, 1.0f );
idVec4 lightGridSize( lightGrid.lightGridSize.x, lightGrid.lightGridSize.y, lightGrid.lightGridSize.z, 1.0f );
idVec4 lightGridBounds( lightGrid.lightGridBounds[0], lightGrid.lightGridBounds[1], lightGrid.lightGridBounds[2], 1.0f );
renderProgManager.SetUniformValue( RENDERPARM_GLOBALLIGHTORIGIN, lightGridOrigin.ToFloatPtr() );
renderProgManager.SetUniformValue( RENDERPARM_JITTERTEXSCALE, lightGridSize.ToFloatPtr() );
@ -1209,10 +1211,10 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
// individual probe sizes on the atlas image
idVec4 probeSize;
probeSize[0] = currentSpace->lightGridAtlasSingleProbeSize - currentSpace->lightGridAtlasBorderSize;
probeSize[1] = currentSpace->lightGridAtlasSingleProbeSize;
probeSize[2] = currentSpace->lightGridAtlasBorderSize;
probeSize[3] = float( currentSpace->lightGridAtlasSingleProbeSize - currentSpace->lightGridAtlasBorderSize ) / currentSpace->lightGridAtlasSingleProbeSize;
probeSize[0] = lightGrid.imageSingleProbeSize - lightGrid.imageBorderSize;
probeSize[1] = lightGrid.imageSingleProbeSize;
probeSize[2] = lightGrid.imageBorderSize;
probeSize[3] = float( lightGrid.imageSingleProbeSize - lightGrid.imageBorderSize ) / lightGrid.imageSingleProbeSize;
renderProgManager.SetUniformValue( RENDERPARM_SCREENCORRECTIONFACTOR, probeSize.ToFloatPtr() ); // rpScreenCorrectionFactor
// specular cubemap blend weights
@ -1256,9 +1258,9 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
}
GL_SelectTexture( INTERACTION_TEXUNIT_AMBIENT_CUBE1 );
currentSpace->lightGridAtlasImage->Bind();
lightGrid.GetIrradianceImage()->Bind();
idVec2i res = currentSpace->lightGridAtlasImage->GetUploadResolution();
idVec2i res = lightGrid.GetIrradianceImage()->GetUploadResolution();
idVec4 textureSize( res.x, res.y, 1.0f / res.x, 1.0f / res.y );
renderProgManager.SetUniformValue( RENDERPARM_CASCADEDISTANCES, textureSize.ToFloatPtr() );
@ -1710,7 +1712,7 @@ void idRenderBackend::RenderInteractions( const drawSurf_t* surfList, const view
// are added single-threaded, and there is only a negligable amount
// of benefit to trying to sort by materials.
//---------------------------------
static const int MAX_INTERACTIONS_PER_LIGHT = 1024;
static const int MAX_INTERACTIONS_PER_LIGHT = 2048; // 1024 in BFG
static const int MAX_COMPLEX_INTERACTIONS_PER_LIGHT = 256;
idStaticList< const drawSurf_t*, MAX_INTERACTIONS_PER_LIGHT > allSurfaces;
idStaticList< const drawSurf_t*, MAX_COMPLEX_INTERACTIONS_PER_LIGHT > complexSurfaces;
@ -3012,12 +3014,9 @@ void idRenderBackend::SetupShadowMapMatrices( viewLight_t* vLight, int side, idR
lightProjectionMatrix[1 * 4 + 2] = 0.0f;
lightProjectionMatrix[2 * 4 + 2] = -0.999f; // adjust value to prevent imprecision issues
#if 0 //defined( USE_NVRHI )
// the D3D clip space Z is in range [0,1] instead of [-1,1]
lightProjectionMatrix[3 * 4 + 2] = -zNear;
#else
// FIXME -1.0f * zNear kills shadow depth
lightProjectionMatrix[3 * 4 + 2] = -2.0f * zNear;
#endif
lightProjectionMatrix[0 * 4 + 3] = 0.0f;
lightProjectionMatrix[1 * 4 + 3] = 0.0f;
@ -3096,21 +3095,28 @@ void idRenderBackend::ShadowMapPassPerforated( const drawSurf_t** drawSurfs, int
// like a no-change-required
GL_State( glState | GLS_POLYGON_OFFSET );
const float polygonFactor = r_shadowMapPolygonFactor.GetFloat();
float polygonOffset = r_dxShadowMapPolygonOffset.GetFloat();
if( deviceManager->GetGraphicsAPI() == nvrhi::GraphicsAPI::VULKAN )
{
polygonOffset = r_vkShadowMapPolygonOffset.GetFloat();
}
switch( r_shadowMapOccluderFacing.GetInteger() )
{
case 0:
GL_State( ( glStateBits & ~( GLS_CULL_MASK ) ) | GLS_CULL_FRONTSIDED );
GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat(), r_shadowMapPolygonOffset.GetFloat() );
GL_PolygonOffset( polygonFactor, polygonOffset );
break;
case 1:
GL_State( ( glStateBits & ~( GLS_CULL_MASK ) ) | GLS_CULL_BACKSIDED );
GL_PolygonOffset( -r_shadowMapPolygonFactor.GetFloat(), -r_shadowMapPolygonOffset.GetFloat() );
GL_PolygonOffset( -polygonFactor, -polygonOffset );
break;
default:
GL_State( ( glStateBits & ~( GLS_CULL_MASK ) ) | GLS_CULL_TWOSIDED );
GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat(), r_shadowMapPolygonOffset.GetFloat() );
GL_PolygonOffset( polygonFactor, polygonOffset );
break;
}
@ -3318,21 +3324,28 @@ void idRenderBackend::ShadowMapPassFast( const drawSurf_t* drawSurfs, viewLight_
// like a no-change-required
GL_State( glState | GLS_POLYGON_OFFSET );
const float polygonFactor = r_shadowMapPolygonFactor.GetFloat();
float polygonOffset = r_dxShadowMapPolygonOffset.GetFloat();
if( deviceManager->GetGraphicsAPI() == nvrhi::GraphicsAPI::VULKAN )
{
polygonOffset = r_vkShadowMapPolygonOffset.GetFloat();
}
switch( r_shadowMapOccluderFacing.GetInteger() )
{
case 0:
GL_State( ( glStateBits & ~( GLS_CULL_MASK ) ) | GLS_CULL_FRONTSIDED );
GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat(), r_shadowMapPolygonOffset.GetFloat() );
GL_PolygonOffset( polygonFactor, polygonOffset );
break;
case 1:
GL_State( ( glStateBits & ~( GLS_CULL_MASK ) ) | GLS_CULL_BACKSIDED );
GL_PolygonOffset( -r_shadowMapPolygonFactor.GetFloat(), -r_shadowMapPolygonOffset.GetFloat() );
GL_PolygonOffset( -polygonFactor, -polygonOffset );
break;
default:
GL_State( ( glStateBits & ~( GLS_CULL_MASK ) ) | GLS_CULL_TWOSIDED );
GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat(), r_shadowMapPolygonOffset.GetFloat() );
GL_PolygonOffset( polygonFactor, polygonOffset );
break;
}
@ -5789,6 +5802,7 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
//-------------------------------------------------
// resolve the screen for SSR
//-------------------------------------------------
if( is3D && r_useSSR.GetBool() )
{
if( R_GetMSAASamples() > 1 )
{
@ -6575,12 +6589,6 @@ void idRenderBackend::PostProcess( const void* data )
renderProgManager.BindShader_PostProcess_RetroCPC();
}
else if( r_renderMode.GetInteger() == RENDERMODE_NES || r_renderMode.GetInteger() == RENDERMODE_NES_HIGHRES )
{
jitterTexScale[0] = r_renderMode.GetInteger() == RENDERMODE_NES_HIGHRES ? 2.0 : 1.0;
renderProgManager.BindShader_PostProcess_RetroNES();
}
else if( r_renderMode.GetInteger() == RENDERMODE_GENESIS || r_renderMode.GetInteger() == RENDERMODE_GENESIS_HIGHRES )
{
jitterTexScale[0] = r_renderMode.GetInteger() == RENDERMODE_GENESIS_HIGHRES ? 2.0 : 1.0;

View file

@ -98,10 +98,11 @@ struct drawSurf_t
const idMaterial* material; // may be NULL for shadow volumes
uint64 extraGLState; // Extra GL state |'d with material->stage[].drawStateBits
float sort; // material->sort, modified by gui / entity sort offsets
const float* shaderRegisters; // evaluated and adjusted for referenceShaders
const float* shaderRegisters; // evaluated and adjusted for referenceShaders
drawSurf_t* nextOnLight; // viewLight chains
drawSurf_t** linkChain; // defer linking to lights to a serial section to avoid a mutex
idScreenRect scissorRect; // for scissor clipping, local inside renderView viewport
const struct portalArea_s* area; // RB: if != NULL then the area provides valid lightgrid
};
// areas have references to hold all the lights and entities in them
@ -422,17 +423,6 @@ struct viewEntity_t
// parallelAddModels will build a chain of surfaces here that will need to
// be linked to the lights or added to the drawsurf list in a serial code section
drawSurf_t* drawSurfs;
// RB: use light grid of the best area this entity is in
bool useLightGrid;
idImage* lightGridAtlasImage;
int lightGridAtlasSingleProbeSize; // including border
int lightGridAtlasBorderSize;
idVec3 lightGridOrigin;
idVec3 lightGridSize;
int lightGridBounds[3];
// RB end
};
// RB: viewEnvprobes are allocated on the frame temporary stack memory
@ -1200,8 +1190,6 @@ extern idCVar r_singleEntity; // suppress all but one entity
extern idCVar r_singleEnvprobe; // suppress all but one envprobe
extern idCVar r_singleArea; // only draw the portal area the view is actually in
extern idCVar r_singleSurface; // suppress all but one surface on each entity
extern idCVar r_shadowPolygonOffset; // bias value added to depth test for stencil shadow drawing
extern idCVar r_shadowPolygonFactor; // scale value for stencil shadow drawing
extern idCVar r_orderIndexes; // perform index reorganization to optimize vertex use
@ -1233,7 +1221,8 @@ extern idCVar r_shadowMapSplitWeight;
extern idCVar r_shadowMapLodScale;
extern idCVar r_shadowMapLodBias;
extern idCVar r_shadowMapPolygonFactor;
extern idCVar r_shadowMapPolygonOffset;
extern idCVar r_dxShadowMapPolygonOffset;
extern idCVar r_vkShadowMapPolygonOffset;
extern idCVar r_shadowMapOccluderFacing;
extern idCVar r_shadowMapRegularDepthBiasScale;
extern idCVar r_shadowMapSunDepthBiasScale;
@ -1298,8 +1287,6 @@ enum RenderMode
RENDERMODE_C64_HIGHRES,
RENDERMODE_CPC,
RENDERMODE_CPC_HIGHRES,
RENDERMODE_NES,
RENDERMODE_NES_HIGHRES,
RENDERMODE_GENESIS,
RENDERMODE_GENESIS_HIGHRES,
RENDERMODE_PSX,

View file

@ -345,9 +345,9 @@ void idRenderProgManager::Init( nvrhi::IDevice* device )
auto ppFxBindingLayout2 = nvrhi::BindingLayoutDesc()
.setVisibility( nvrhi::ShaderType::All )
.addItem( renderParmLayoutItem )
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 0 ) ) // LDR _currentRender
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 1 ) ) // _blueNoise
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 2 ) ) // _currentNormals
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 0 ) ) // LDR _currentRender
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 1 ) ) // _blueNoise
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 2 ) ) // _currentNormals
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 3 ) ); // _currentDepth
bindingLayouts[BINDING_LAYOUT_POST_PROCESS_FINAL2] = { device->createBindingLayout( ppFxBindingLayout2 ), samplerTwoBindingLayout };
@ -575,7 +575,6 @@ void idRenderProgManager::Init( nvrhi::IDevice* device )
{ BUILTIN_POSTPROCESS_RETRO_2BIT, "builtin/post/retro_2bit", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_POSTPROCESS_RETRO_C64, "builtin/post/retro_c64", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_POSTPROCESS_RETRO_CPC, "builtin/post/retro_cpc", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL2 },
{ BUILTIN_POSTPROCESS_RETRO_NES, "builtin/post/retro_nes", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_POSTPROCESS_RETRO_GENESIS, "builtin/post/retro_genesis", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_POSTPROCESS_RETRO_PSX, "builtin/post/retro_ps1", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_CRT_MATTIAS, "builtin/post/crt_mattias", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_CRT },

View file

@ -375,7 +375,6 @@ enum
BUILTIN_POSTPROCESS_RETRO_2BIT, // CGA, Gameboy, cool for Gamejams
BUILTIN_POSTPROCESS_RETRO_C64, // Commodore 64
BUILTIN_POSTPROCESS_RETRO_CPC, // Amstrad 6128
BUILTIN_POSTPROCESS_RETRO_NES, // NES
BUILTIN_POSTPROCESS_RETRO_GENESIS, // Sega Genesis / Megadrive
BUILTIN_POSTPROCESS_RETRO_PSX, // Sony Playstation 1
BUILTIN_CRT_MATTIAS,
@ -857,11 +856,6 @@ public:
BindShader_Builtin( BUILTIN_POSTPROCESS_RETRO_2BIT );
}
void BindShader_PostProcess_RetroNES()
{
BindShader_Builtin( BUILTIN_POSTPROCESS_RETRO_NES );
}
void BindShader_PostProcess_RetroGenesis()
{
BindShader_Builtin( BUILTIN_POSTPROCESS_RETRO_GENESIS );

View file

@ -165,8 +165,6 @@ idCVar r_offsetFactor( "r_offsetfactor", "0", CVAR_RENDERER | CVAR_FLOAT, "polyg
#endif
// RB end
idCVar r_shadowPolygonOffset( "r_shadowPolygonOffset", "-1", CVAR_RENDERER | CVAR_FLOAT, "bias value added to depth test for stencil shadow drawing" );
idCVar r_shadowPolygonFactor( "r_shadowPolygonFactor", "0", CVAR_RENDERER | CVAR_FLOAT, "scale value for stencil shadow drawing" );
idCVar r_subviewOnly( "r_subviewOnly", "0", CVAR_RENDERER | CVAR_BOOL, "1 = don't render main view, allowing subviews to be debugged" );
idCVar r_testGamma( "r_testGamma", "0", CVAR_RENDERER | CVAR_FLOAT, "if > 0 draw a grid pattern to test gamma levels", 0, 195 );
idCVar r_testGammaBias( "r_testGammaBias", "0", CVAR_RENDERER | CVAR_FLOAT, "if > 0 draw a grid pattern to test gamma levels" );
@ -257,10 +255,11 @@ idCVar r_shadowMapSplitWeight( "r_shadowMapSplitWeight", "0.9", CVAR_RENDERER |
idCVar r_shadowMapLodScale( "r_shadowMapLodScale", "1.4", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "" );
idCVar r_shadowMapLodBias( "r_shadowMapLodBias", "0", CVAR_RENDERER | CVAR_INTEGER | CVAR_NEW, "" );
idCVar r_shadowMapPolygonFactor( "r_shadowMapPolygonFactor", "2", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "polygonOffset factor for drawing shadow buffer" );
idCVar r_shadowMapPolygonOffset( "r_shadowMapPolygonOffset", "3000", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "polygonOffset units for drawing shadow buffer" );
idCVar r_dxShadowMapPolygonOffset( "r_dxShadowMapPolygonOffset", "0.1", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "polygonOffset units for drawing shadow buffer" );
idCVar r_vkShadowMapPolygonOffset( "r_vkShadowMapPolygonOffset", "1", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "polygonOffset units for drawing shadow buffer" );
idCVar r_shadowMapOccluderFacing( "r_shadowMapOccluderFacing", "2", CVAR_RENDERER | CVAR_INTEGER | CVAR_NEW, "0 = front faces, 1 = back faces, 2 = twosided" );
idCVar r_shadowMapRegularDepthBiasScale( "r_shadowMapRegularDepthBiasScale", "0.999", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "shadowmap bias to fight shadow acne for point and spot lights" );
idCVar r_shadowMapSunDepthBiasScale( "r_shadowMapSunDepthBiasScale", "0.999991", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "shadowmap bias to fight shadow acne for cascaded shadow mapping with parallel lights" );
idCVar r_shadowMapSunDepthBiasScale( "r_shadowMapSunDepthBiasScale", "0.999", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "shadowmap bias to fight shadow acne for cascaded shadow mapping with parallel lights" );
// RB: HDR parameters
idCVar r_hdrAutoExposure( "r_hdrAutoExposure", "0", CVAR_RENDERER | CVAR_BOOL | CVAR_NEW, "EXPENSIVE: enables adapative HDR tone mapping otherwise the exposure is derived by r_exposure" );
@ -315,7 +314,7 @@ idCVar r_crtVignette( "r_crtVignette", "0.8", CVAR_RENDERER | CVAR_FLOAT | CVAR_
idCVar r_retroDitherScale( "r_retroDitherScale", "0.3", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "" );
idCVar r_renderMode( "r_renderMode", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER | CVAR_NEW, "0 = Doom, 1 = CGA, 2 = CGA Highres, 3 = Commodore 64, 4 = Commodore 64 Highres, 5 = Amstrad CPC 6128, 6 = Amstrad CPC 6128 Highres, 7 = NES, 8 = NES Highres, 9 = Sega Genesis, 10 = Sega Genesis Highres, 11 = Sony PSX", 0, 11 );
idCVar r_renderMode( "r_renderMode", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER | CVAR_NEW, "0 = Doom, 1 = CGA, 2 = CGA Highres, 3 = Commodore 64, 4 = Commodore 64 Highres, 5 = Amstrad CPC 6128, 6 = Amstrad CPC 6128 Highres, 7 = Sega Genesis, 8 = Sega Genesis Highres, 9 = Sony PSX", 0, 9 );
idCVar r_psxVertexJitter( "r_psxVertexJitter", "0.5", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "", 0.0f, 0.75f );
idCVar r_psxAffineTextures( "r_psxAffineTextures", "1", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "" );

View file

@ -1133,7 +1133,14 @@ CONSOLE_COMMAND_SHIP( bakeEnvironmentProbes, "Bake environment probes", NULL )
}
// generate .bimage file
globalImages->ImageFromFile( job->filename, TF_LINEAR, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
if( job->outHeight == RADIANCE_OCTAHEDRON_SIZE )
{
globalImages->ImageFromFile( job->filename, TF_DEFAULT, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
}
else
{
globalImages->ImageFromFile( job->filename, TF_LINEAR, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
}
Mem_Free( job->outBuffer );

View file

@ -497,7 +497,8 @@ void idRenderWorldLocal::WriteLightGrid( idFile* fp, const LightGrid& lightGrid
{
const lightGridPoint_t* gridPoint = &lightGrid.lightGridPoints[i];
fp->WriteFloatString( "/* lgp %i */ %d ( %f %f %f )", i, ( int )gridPoint->valid, gridPoint->origin[0], gridPoint->origin[1], gridPoint->origin[2] );
//fp->WriteFloatString( "/* lgp %i */ %d ( %f %f %f )", i, ( int )gridPoint->valid, gridPoint->origin[0], gridPoint->origin[1], gridPoint->origin[2] );
fp->WriteFloatString( " %d ( %f %f %f )", ( int )gridPoint->valid, gridPoint->origin[0], gridPoint->origin[1], gridPoint->origin[2] );
#if STORE_LIGHTGRID_SHDATA
// spherical harmonic

View file

@ -249,7 +249,7 @@ public:
idBlockAlloc<areaReference_t, 1024> areaReferenceAllocator;
idBlockAlloc<idInteraction, 256> interactionAllocator;
#ifdef ID_PC
#if 1 //def ID_PC
static const int MAX_DECAL_SURFACES = 32;
#else
static const int MAX_DECAL_SURFACES = 16;

View file

@ -4,8 +4,8 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2016-2017 Dustin Land
Copyright (C) 2020 Robert Beckebans
Copyright (C) 2022 Stephen Pridham
Copyright (C) 2024 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -33,7 +33,7 @@ If you have questions concerning this license or the applicable additional terms
#if 1
// RB: increased some static memory limits for custom modder content
// RB: quadruppled static memory limits for custom content
const int VERTCACHE_INDEX_MEMORY_PER_FRAME = 31 * 1024 * 1024;
const int VERTCACHE_VERTEX_MEMORY_PER_FRAME = 31 * 1024 * 1024;
@ -42,7 +42,7 @@ If you have questions concerning this license or the applicable additional terms
// there are a lot more static indexes than vertexes, because interactions are just new
// index lists that reference existing vertexes
const int STATIC_INDEX_MEMORY = 4 * 31 * 1024 * 1024;
const int STATIC_VERTEX_MEMORY = 2 * 31 * 1024 * 1024; // make sure it fits in VERTCACHE_OFFSET_MASK!
const int STATIC_VERTEX_MEMORY = 4 * 31 * 1024 * 1024; // make sure it fits in VERTCACHE_OFFSET_MASK!
// vertCacheHandle_t packs size, offset, and frame number into 64 bits
typedef uint64 vertCacheHandle_t;
@ -52,10 +52,10 @@ If you have questions concerning this license or the applicable additional terms
const int VERTCACHE_SIZE_MASK = 0x7fffff; // 23 bits = 8 megs
const int VERTCACHE_OFFSET_SHIFT = 24;
const int VERTCACHE_OFFSET_MASK = 0x3ffffff; // 26 bits = 64 megs
const int VERTCACHE_OFFSET_MASK = 0x7ffffff; // 27 bits = 128 megs
const int VERTCACHE_FRAME_SHIFT = 50;
const int VERTCACHE_FRAME_MASK = 0x3fff; // 14 bits = 16382 frames to wrap around
const int VERTCACHE_FRAME_SHIFT = 51;
const int VERTCACHE_FRAME_MASK = 0x1fff; // 13 bits = 8191 frames to wrap around
#else

View file

@ -177,7 +177,6 @@ idRenderModel* R_EntityDefDynamicModel( idRenderEntityLocal* def )
// if we don't have a snapshot of the dynamic model, generate it now
if( def->dynamicModel == NULL )
{
SCOPED_PROFILE_EVENT( "InstantiateDynamicModel" );
// instantiate the snapshot of the dynamic model, possibly reusing memory from the cached snapshot
@ -316,9 +315,6 @@ void R_AddSingleModel( viewEntity_t* vEntity )
// we will add all interaction surfs here, to be chained to the lights in later serial code
vEntity->drawSurfs = NULL;
// RB
vEntity->useLightGrid = false;
// globals we really should pass in...
const viewDef_t* viewDef = tr.viewDef;
@ -495,32 +491,6 @@ void R_AddSingleModel( viewEntity_t* vEntity )
}
}
// RB: use first valid lightgrid
for( areaReference_t* ref = entityDef->entityRefs; ref != NULL; ref = ref->ownerNext )
{
idImage* lightGridImage = ref->area->lightGrid.GetIrradianceImage();
if( ref->area->lightGrid.lightGridPoints.Num() && lightGridImage && !lightGridImage->IsDefaulted() )
{
vEntity->useLightGrid = true;
vEntity->lightGridAtlasImage = lightGridImage;
vEntity->lightGridAtlasSingleProbeSize = ref->area->lightGrid.imageSingleProbeSize;
vEntity->lightGridAtlasBorderSize = ref->area->lightGrid.imageBorderSize;
for( int i = 0; i < 3; i++ )
{
vEntity->lightGridOrigin[i] = ref->area->lightGrid.lightGridOrigin[i];
vEntity->lightGridSize[i] = ref->area->lightGrid.lightGridSize[i];
vEntity->lightGridBounds[i] = ref->area->lightGrid.lightGridBounds[i];
}
break;
}
}
// RB end
//---------------------------
// copy matrix related stuff for back-end use
// and setup a render matrix for faster culling
@ -709,26 +679,23 @@ void R_AddSingleModel( viewEntity_t* vEntity )
tr.pc.c_mocIndexes += 36;
tr.pc.c_mocVerts += 8;
const float size = 16.0f;
idBounds debugBounds( idVec3( -size ), idVec3( size ) );
//debugBounds = vEntity->entityDef->localReferenceBounds;
#if 0
idBounds surfaceBounds;
#if 1
if( gpuSkinned )
{
//debugBounds = vEntity->entityDef->localReferenceBounds;
debugBounds = model->Bounds();
surfaceBounds = vEntity->entityDef->localReferenceBounds;
}
else
#endif
{
debugBounds = tri->bounds;
surfaceBounds = tri->bounds;
}
idRenderMatrix modelRenderMatrix;
idRenderMatrix::CreateFromOriginAxis( renderEntity->origin, renderEntity->axis, modelRenderMatrix );
idRenderMatrix inverseBaseModelProject;
idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, debugBounds, inverseBaseModelProject );
idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, surfaceBounds, inverseBaseModelProject );
idRenderMatrix invProjectMVPMatrix;
idRenderMatrix::Multiply( viewDef->worldSpace.unjitteredMVP, inverseBaseModelProject, invProjectMVPMatrix );
@ -760,8 +727,6 @@ void R_AddSingleModel( viewEntity_t* vEntity )
}
#endif // #if defined(USE_INTRINSICS_SSE)
//--------------------------
// base drawing surface
//--------------------------
@ -845,6 +810,99 @@ void R_AddSingleModel( viewEntity_t* vEntity )
baseDrawSurf->nextOnLight = vEntity->drawSurfs;
vEntity->drawSurfs = baseDrawSurf;
}
// RB: use area the surface is in because a model can span multiple areas #965
baseDrawSurf->area = NULL;
if( shader->ReceivesLighting() )
{
idVec3 surfaceCenter;
idVec3 triCenter = tri->bounds.GetCenter();
idRenderMatrix modelRenderMatrix;
idRenderMatrix::CreateFromOriginAxis( renderEntity->origin, renderEntity->axis, modelRenderMatrix );
modelRenderMatrix.TransformPoint( triCenter, surfaceCenter );
int surfaceArea = tr.primaryWorld->PointInArea( surfaceCenter );
for( areaReference_t* ref = entityDef->entityRefs; ref != NULL; ref = ref->ownerNext )
{
idImage* lightGridImage = ref->area->lightGrid.GetIrradianceImage();
if( surfaceArea == ref->area->areaNum && ref->area->lightGrid.lightGridPoints.Num() && lightGridImage != NULL && !lightGridImage->IsDefaulted() )
{
baseDrawSurf->area = ref->area;
break;
}
}
// RB: use first valid lightgrid
// this would be wrong but less wrong than a flickering env_probe fallback
if( baseDrawSurf->area == NULL )
{
for( areaReference_t* ref = entityDef->entityRefs; ref != NULL; ref = ref->ownerNext )
{
idImage* lightGridImage = ref->area->lightGrid.GetIrradianceImage();
if( ref->area->lightGrid.lightGridPoints.Num() && lightGridImage != NULL && !lightGridImage->IsDefaulted() )
{
baseDrawSurf->area = ref->area;
break;
}
}
}
#if 0
// show which area the surface is coming from
//if( baseDrawSurf->area == NULL )
{
idBounds surfaceBounds;
if( gpuSkinned )
{
surfaceBounds = vEntity->entityDef->localReferenceBounds;
}
else
{
surfaceBounds = tri->bounds;
}
idRenderMatrix modelRenderMatrix;
idRenderMatrix::CreateFromOriginAxis( renderEntity->origin, renderEntity->axis, modelRenderMatrix );
idRenderMatrix inverseBaseModelProject;
idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, surfaceBounds, inverseBaseModelProject );
// NOTE: unit cube instead of zeroToOne cube
idVec4* verts = tr.maskedUnitCubeVerts;
idVec4 triVerts[8];
for( int i = 0; i < 8; i++ )
{
// transform to clip space
inverseBaseModelProject.TransformPoint( verts[i], triVerts[i] );
}
static idVec4 colors[] = { colorBrown, colorBlue, colorCyan, colorGreen, colorYellow, colorRed, colorWhite };
idVec4 color = colors[surfaceArea & 7];
if( baseDrawSurf->area == NULL )
{
color = colorPurple;
}
// same as idRenderWorldLocal::DebugBox
const int lifetime = 0;
for( int i = 0; i < 4; i++ )
{
tr.viewDef->renderWorld->DebugLine( color, triVerts[i].ToVec3(), triVerts[( i + 1 ) & 3].ToVec3(), lifetime );
tr.viewDef->renderWorld->DebugLine( color, triVerts[4 + i].ToVec3(), triVerts[4 + ( ( i + 1 ) & 3 )].ToVec3(), lifetime );
tr.viewDef->renderWorld->DebugLine( color, triVerts[i].ToVec3(), triVerts[4 + i].ToVec3(), lifetime );
}
tr.viewDef->renderWorld->DebugAxis( surfaceCenter, renderEntity->axis );
}
#endif
}
}
//----------------------------------------

View file

@ -382,51 +382,80 @@ void R_RenderSingleModel( viewEntity_t* vEntity )
#if 0
else
{
idVec4 triVerts[3];
unsigned int triIndices[] = { 0, 1, 2 };
tr.pc.c_mocIndexes += 36;
tr.pc.c_mocVerts += 8;
idBounds surfaceBounds;
if( gpuSkinned )
{
surfaceBounds = vEntity->entityDef->localReferenceBounds;
}
else
{
surfaceBounds = tri->bounds;
}
idRenderMatrix modelRenderMatrix;
idRenderMatrix::CreateFromOriginAxis( renderEntity->origin, renderEntity->axis, modelRenderMatrix );
//const float size = 16.0f;
//idBounds debugBounds( idVec3( -size ), idVec3( size ) );
idBounds debugBounds;
#if 0
if( gpuSkinned )
{
//debugBounds = vEntity->entityDef->localReferenceBounds;
debugBounds = model->Bounds();
}
else
#endif
{
debugBounds = tri->bounds;
}
idRenderMatrix inverseBaseModelProject;
idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, debugBounds, inverseBaseModelProject );
idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, surfaceBounds, inverseBaseModelProject );
idRenderMatrix invProjectMVPMatrix;
idRenderMatrix::Multiply( viewDef->worldSpace.unjitteredMVP, inverseBaseModelProject, invProjectMVPMatrix );
// NOTE: unit cube instead of zeroToOne cube
idVec4* verts = tr.maskedUnitCubeVerts;
unsigned int* indexes = tr.maskedZeroOneCubeIndexes;
for( int i = 0, face = 0; i < 36; i += 3, face++ )
idVec4 triVerts[8];
for( int i = 0; i < 8; i++ )
{
const idVec4& v0 = verts[indexes[i + 0]];
const idVec4& v1 = verts[indexes[i + 1]];
const idVec4& v2 = verts[indexes[i + 2]];
// transform to clip space
invProjectMVPMatrix.TransformPoint( v0, triVerts[0] );
invProjectMVPMatrix.TransformPoint( v1, triVerts[1] );
invProjectMVPMatrix.TransformPoint( v2, triVerts[2] );
invProjectMVPMatrix.TransformPoint( verts[i], triVerts[i] );
}
tr.maskedOcclusionCulling->RenderTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_CCW );
tr.maskedOcclusionCulling->RenderTriangles( ( float* )triVerts, tr.maskedZeroOneCubeIndexes, 12, NULL, MaskedOcclusionCulling::BACKFACE_CCW );
}
#elif 0
else
{
idBounds surfaceBounds;
if( gpuSkinned )
{
surfaceBounds = vEntity->entityDef->localReferenceBounds;
}
else
{
surfaceBounds = tri->bounds;
}
idRenderMatrix modelRenderMatrix;
idRenderMatrix::CreateFromOriginAxis( renderEntity->origin, renderEntity->axis, modelRenderMatrix );
idRenderMatrix inverseBaseModelProject;
idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, surfaceBounds, inverseBaseModelProject );
// NOTE: unit cube instead of zeroToOne cube
idVec4* verts = tr.maskedUnitCubeVerts;
idVec4 triVerts[8];
for( int i = 0; i < 8; i++ )
{
// transform to clip space
inverseBaseModelProject.TransformPoint( verts[i], triVerts[i] );
}
static idVec4 colors[] = { colorRed, colorGreen, colorBlue, colorYellow, colorMagenta, colorCyan, colorWhite, colorPurple };
idVec4 color = colors[surfaceNum & 7];
// same as idRenderWorldLocal::DebugBox
const int lifetime = 0;
for( int i = 0; i < 4; i++ )
{
tr.viewDef->renderWorld->DebugLine( color, triVerts[i].ToVec3(), triVerts[( i + 1 ) & 3].ToVec3(), lifetime );
tr.viewDef->renderWorld->DebugLine( color, triVerts[4 + i].ToVec3(), triVerts[4 + ( ( i + 1 ) & 3 )].ToVec3(), lifetime );
tr.viewDef->renderWorld->DebugLine( color, triVerts[i].ToVec3(), triVerts[4 + i].ToVec3(), lifetime );
}
}
#endif

View file

@ -58,5 +58,7 @@ void main( VS_IN vertex, out VS_OUT result )
result.texcoord0 = vertex.position.xyz - rpLocalViewOrigin.xyz;
result.color = ( swizzleColor( vertex.color ) * rpVertexColorModulate ) + rpVertexColorAdd;
// RB: pass rpColor as intensity scaling factor for HDRI skies because the vertex color logic isn't used on skyboxes afaik
//result.color = ( swizzleColor( vertex.color ) * rpVertexColorModulate ) + rpVertexColorAdd;
result.color = rpColor;
}

View file

@ -242,14 +242,11 @@ void main( PS_IN fragment, out PS_OUT result )
gridCoord[j] = int( floor( v ) );
frac[ j ] = v - gridCoord[ j ];
/*
if( gridCoord[i] < 0 )
if( gridCoord[j] < 0 )
{
gridCoord[i] = 0;
gridCoord[j] = 0;
}
else
*/
if( gridCoord[j] >= lightGridBounds[j] - 1 )
else if( gridCoord[j] >= lightGridBounds[j] - 1 )
{
gridCoord[j] = lightGridBounds[j] - 1;
}

View file

@ -113,7 +113,7 @@ void main( PS_IN fragment, out PS_OUT result )
Params params;
params.curvature = rpWindowCoord.x;
params.ghosting = 0.0;
params.scanroll = 1.0;
params.scanroll = 0.0;
params.wiggle_toggle = 0.0;
params.vignette = rpWindowCoord.y;
params.FrameCount = int( rpJitterTexOffset.w );

View file

@ -106,73 +106,6 @@ float3 LinearSearch( float3 c, float3 pal[NUM_COLORS] )
return pal[index];
}
/*
float3 GetClosest( float3 val1, float3 val2, float3 target )
{
if( distance( target, val1 ) >= distance( val2, target ) )
{
return val2;
}
else
{
return val1;
}
}
// find nearest palette color using Euclidean disntance and binary search
// this requires an already sorted palette as input
float3 BinarySearch( float3 target, float3 pal[NUM_COLORS] )
{
float targetY = PhotoLuma( target );
// left-side case
if( targetY <= PhotoLuma( pal[0] ) )
{
return pal[0];
}
// right-side case
if( targetY >= PhotoLuma( pal[NUM_COLORS - 1] ) )
{
return pal[NUM_COLORS - 1];
}
int i = 0, j = NUM_COLORS, mid = 0;
while( i < j )
{
mid = ( i + j ) / 2;
if( distance( pal[mid], target ) < 0.01 )
{
return pal[mid];
}
// if target is less than array element, then search in left
if( targetY < PhotoLuma( pal[mid] ) )
{
// if target is greater than previous
// to mid, return closest of two
if( mid > 0 && targetY > PhotoLuma( pal[mid - 1] ) )
{
return GetClosest( pal[mid - 1], pal[mid], target );
}
j = mid;
}
else
{
if( mid < ( NUM_COLORS - 1 ) && targetY < PhotoLuma( pal[mid + 1] ) )
{
return GetClosest( pal[mid], pal[mid + 1], target );
}
i = mid + 1;
}
}
// only single element left after search
return pal[mid];
}
*/
#define RGB(r, g, b) float3(float(r)/255.0, float(g)/255.0, float(b)/255.0)
@ -283,7 +216,6 @@ void main( PS_IN fragment, out PS_OUT result )
// find closest color match from C64 color palette
color = LinearSearch( color.rgb, palette );
//color = float4( BinarySearch( color.rgb, palette ), 1.0 );
result.color = float4( color, 1.0 );
}

View file

@ -53,7 +53,7 @@ struct PS_OUT
#define RESOLUTION_DIVISOR 4.0
#define NUM_COLORS 32 // original 27
#define NUM_COLORS 31 // original 27
float3 Average( float3 pal[NUM_COLORS] )
@ -233,46 +233,131 @@ void main( PS_IN fragment, out PS_OUT result )
#endif
};
#elif 1
#elif 0
// Tweaked LOSPEC CPC BOY PALETTE which is less saturated by Arne Niklas Jansson
// https://lospec.com/palette-list/cpc-boy
const float3 palette[NUM_COLORS] = // 32
{
RGB( 0, 0, 0 ),
RGB( 36, 49, 55 ),
RGB( 27, 27, 101 ),
RGB( 53, 53, 201 ),
RGB( 102, 30, 37 ),
RGB( 85, 51, 97 ),
RGB( 127, 53, 201 ),
RGB( 188, 53, 53 ),
RGB( 192, 70, 110 ),
RGB( 223, 109, 155 ),
RGB( 27, 101, 27 ),
RGB( 27, 110, 131 ),
RGB( 30, 121, 229 ),
RGB( 102, 30, 37 ),
RGB( 63, 80, 63 ),
RGB( 85, 51, 97 ),
RGB( 121, 95, 27 ),
RGB( 128, 128, 128 ),
RGB( 145, 148, 223 ),
RGB( 201, 127, 53 ),
RGB( 227, 155, 141 ),
RGB( 248, 120, 248 ),
RGB( 27, 110, 131 ),
RGB( 53, 175, 53 ),
RGB( 118, 132, 72 ),
RGB( 188, 53, 53 ),
RGB( 53, 53, 201 ),
RGB( 128, 128, 128 ),
RGB( 192, 70, 110 ),
RGB( 53, 183, 143 ),
RGB( 53, 193, 215 ),
RGB( 127, 201, 53 ),
RGB( 127, 53, 201 ),
RGB( 201, 127, 53 ),
RGB( 30, 121, 229 ),
RGB( 172, 181, 107 ),
RGB( 223, 109, 155 ),
RGB( 53, 193, 215 ),
RGB( 145, 148, 223 ),
RGB( 225, 198, 67 ),
RGB( 227, 155, 141 ),
RGB( 173, 200, 170 ),
RGB( 141, 225, 199 ),
RGB( 225, 198, 67 ),
RGB( 228, 221, 154 ),
RGB( 255, 255, 255 ),
RGB( 248, 120, 248 ),
RGB( 238, 234, 224 ),
RGB( 172, 181, 107 ),
RGB( 118, 132, 72 ),
RGB( 63, 80, 63 ),
RGB( 36, 49, 55 ),
RGB( 255, 255, 255 ),
};
const float3 medianAbsoluteDeviation = RGB( 65, 131, 57 );
const float3 deviation = RGB( 66, 57, 63 );
#elif 1
// https://lospec.com/palette-list/ruzzi-cpc
const float3 palette[NUM_COLORS] = // 31
{
RGB( 0, 0, 28 ), // dark blue
RGB( 28, 0, 28 ), // dark magenta
RGB( 33, 30, 32 ),
RGB( 85, 85, 104 ),
RGB( 36, 14, 11 ),
RGB( 26, 34, 114 ),
RGB( 68, 118, 16 ),
RGB( 129, 16, 51 ),
RGB( 50, 131, 113 ),
RGB( 124, 36, 136 ),
RGB( 151, 122, 44 ),
RGB( 16, 55, 218 ),
RGB( 143, 136, 132 ),
RGB( 222, 18, 92 ),
RGB( 100, 222, 21 ),
RGB( 32, 144, 210 ),
RGB( 120, 58, 220 ),
RGB( 74, 228, 112 ),
RGB( 223, 39, 158 ),
RGB( 236, 126, 74 ),
RGB( 174, 228, 38 ),
RGB( 136, 151, 219 ),
RGB( 49, 234, 203 ),
RGB( 163, 236, 128 ),
RGB( 238, 142, 151 ),
RGB( 224, 60, 223 ),
RGB( 249, 234, 56 ),
RGB( 152, 244, 218 ),
RGB( 239, 157, 228 ),
RGB( 252, 244, 144 ),
RGB( 255, 255, 233 ),
};
const float3 medianAbsoluteDeviation = RGB( 175, 6, 56 );
const float3 deviation = RGB( 67, 70, 62 );
#elif 0
// https://lospec.com/palette-list/ancientheritage30
const float3 palette[NUM_COLORS] = // 30
{
RGB( 2, 4, 5 ),
RGB( 21, 33, 43 ),
RGB( 51, 38, 20 ),
RGB( 30, 56, 56 ),
RGB( 32, 50, 66 ),
RGB( 77, 59, 34 ),
RGB( 95, 26, 41 ),
RGB( 41, 77, 70 ),
RGB( 97, 31, 73 ),
RGB( 45, 71, 94 ),
RGB( 51, 99, 83 ),
RGB( 125, 69, 52 ),
RGB( 83, 88, 94 ),
RGB( 113, 89, 72 ),
RGB( 146, 40, 62 ),
RGB( 67, 104, 121 ),
RGB( 140, 76, 128 ),
RGB( 175, 107, 66 ),
RGB( 109, 153, 106 ),
RGB( 199, 78, 51 ),
RGB( 122, 129, 140 ),
RGB( 154, 116, 181 ),
RGB( 100, 166, 194 ),
RGB( 240, 120, 62 ),
RGB( 176, 178, 181 ),
RGB( 255, 168, 97 ),
RGB( 171, 157, 227 ),
RGB( 119, 217, 213 ),
RGB( 255, 240, 156 ),
RGB( 233, 241, 242 ),
};
const float3 medianAbsoluteDeviation = RGB( 87, 12, 60 );
const float3 deviation = RGB( 57, 50, 51 );
#elif 0
// Atari STE
@ -354,29 +439,6 @@ void main( PS_IN fragment, out PS_OUT result )
RGB( 46, 43, 18 ),
};
#elif 0
// Hollow
// https://lospec.com/palette-list/hollow
const float3 palette[NUM_COLORS] = // 4
{
RGB( 15, 15, 27 ),
RGB( 86, 90, 117 ),
RGB( 198, 183, 190 ),
RGB( 250, 251, 246 ),
};
#else
// https://lospec.com/palette-list/2bit-demichrome
const float3 palette[NUM_COLORS] = // 4
{
RGB( 33, 30, 32 ),
RGB( 85, 85, 104 ),
RGB( 160, 160, 139 ),
RGB( 233, 239, 236 ),
};
#endif
float2 uv = ( fragment.texcoord0 );
@ -384,6 +446,7 @@ void main( PS_IN fragment, out PS_OUT result )
float3 quantizationPeriod = _float3( 1.0 / NUM_COLORS );
float3 quantDeviation = Deviation( palette );
//quantDeviation = medianAbsoluteDeviation;
// get pixellated base color
float4 color = t_BaseColor.Sample( s_LinearClamp, uvPixelated * rpWindowCoord.xy );

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2023 Robert Beckebans
Copyright (C) 2024 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -34,8 +34,8 @@ If you have questions concerning this license or the applicable additional terms
Texture2D t_BaseColor : register( t0 VK_DESCRIPTOR_SET( 0 ) );
Texture2D t_BlueNoise : register( t1 VK_DESCRIPTOR_SET( 0 ) );
SamplerState samp0 : register(s0 VK_DESCRIPTOR_SET( 1 ) );
SamplerState samp1 : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256
SamplerState s_LinearClamp : register(s0 VK_DESCRIPTOR_SET( 1 ) );
SamplerState s_LinearWrap : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256
struct PS_IN
{
@ -50,52 +50,345 @@ struct PS_OUT
// *INDENT-ON*
#define RESOLUTION_DIVISOR 4.0
#define Dithering_QuantizationSteps 8.0 // 8.0 = 2 ^ 3 quantization bits
#define RESOLUTION_DIVISOR 4.0
#define NUM_COLORS 64 // original 61
float3 Quantize( float3 color, float3 period )
// squared distance to avoid the sqrt of distance function
float ColorCompare( float3 a, float3 b )
{
return floor( color * Dithering_QuantizationSteps ) * ( 1.0 / ( Dithering_QuantizationSteps - 1.0 ) );
//return floor( ( color + period / 2.0 ) / period ) * period;
float3 diff = b - a;
return dot( diff, diff );
}
float3 BlueNoise3( float2 n, float x )
// find nearest palette color using Euclidean distance
float3 LinearSearch( float3 c, float3 pal[NUM_COLORS] )
{
float2 uv = n.xy * rpJitterTexOffset.xy;
int index = 0;
float minDist = ColorCompare( c, pal[0] );
float3 noise = t_BlueNoise.Sample( samp1, uv ).rgb;
for( int i = 1; i < NUM_COLORS; i++ )
{
float dist = ColorCompare( c, pal[i] );
noise = frac( noise + c_goldenRatioConjugate * rpJitterTexOffset.w * x );
if( dist < minDist )
{
minDist = dist;
index = i;
}
}
noise.x = RemapNoiseTriErp( noise.x );
noise.y = RemapNoiseTriErp( noise.y );
noise.z = RemapNoiseTriErp( noise.z );
noise = noise * 2.0 - 1.0;
return noise;
return pal[index];
}
#define RGB(r, g, b) float3(float(r)/255.0, float(g)/255.0, float(b)/255.0)
void main( PS_IN fragment, out PS_OUT result )
{
#if 0
// + very colorful
// - no blacks
// - looks more 8 bit than 16 bit
// https://lospec.com/palette-list/meld-plus
const float3 palette[NUM_COLORS] = // 45
{
RGB( 0, 0, 55 ),
RGB( 30, 13, 78 ),
RGB( 0, 60, 69 ),
RGB( 81, 6, 44 ),
RGB( 82, 48, 55 ),
RGB( 76, 2, 91 ),
RGB( 64, 47, 93 ),
RGB( 0, 89, 86 ),
RGB( 19, 33, 120 ),
RGB( 64, 60, 105 ),
RGB( 79, 10, 138 ),
RGB( 149, 18, 58 ),
RGB( 135, 14, 87 ),
RGB( 33, 165, 63 ),
RGB( 95, 92, 128 ),
RGB( 29, 84, 177 ),
RGB( 131, 97, 144 ),
RGB( 189, 101, 55 ),
RGB( 205, 80, 24 ),
RGB( 4, 182, 146 ),
RGB( 156, 130, 119 ),
RGB( 209, 57, 103 ),
RGB( 53, 135, 210 ),
RGB( 133, 223, 83 ),
RGB( 13, 233, 142 ),
RGB( 255, 94, 67 ),
RGB( 149, 154, 187 ),
RGB( 194, 42, 218 ),
RGB( 230, 167, 88 ),
RGB( 255, 130, 87 ),
RGB( 255, 153, 51 ),
RGB( 197, 180, 161 ),
RGB( 210, 154, 173 ),
RGB( 97, 212, 255 ),
RGB( 152, 255, 192 ),
RGB( 231, 255, 125 ),
RGB( 249, 132, 237 ),
RGB( 251, 227, 163 ),
RGB( 242, 230, 179 ),
RGB( 255, 231, 160 ),
RGB( 255, 211, 200 ),
RGB( 247, 236, 206 ),
RGB( 209, 234, 251 ),
RGB( 255, 205, 243 ),
RGB( 255, 255, 255 ),
};
const float3 medianAbsoluteDeviation = RGB( 29, 87, 155 );
const float3 deviation = RGB( 80, 72, 55 );
#elif 1
// + very good dithering variety at dark grey values
// + does not leak too much color into grey values
// + good saturation when colors are really needed
// - a bit too strong visible dithering pattern
// https://lospec.com/palette-list/famicube
const float3 palette[NUM_COLORS] = // 64
{
RGB( 0, 0, 0 ),
RGB( 21, 21, 21 ),
RGB( 35, 23, 18 ),
RGB( 23, 40, 8 ),
RGB( 13, 32, 48 ),
RGB( 33, 22, 64 ),
RGB( 0, 78, 0 ),
RGB( 79, 21, 7 ),
RGB( 52, 52, 52 ),
RGB( 92, 60, 13 ),
RGB( 0, 96, 75 ),
RGB( 55, 109, 3 ),
RGB( 0, 23, 125 ),
RGB( 0, 82, 128 ),
RGB( 65, 93, 102 ),
RGB( 135, 22, 70 ),
RGB( 130, 60, 61 ),
RGB( 19, 157, 8 ),
RGB( 90, 25, 145 ),
RGB( 61, 52, 165 ),
RGB( 173, 78, 26 ),
RGB( 32, 181, 98 ),
RGB( 106, 180, 23 ),
RGB( 147, 151, 23 ),
RGB( 174, 108, 55 ),
RGB( 123, 123, 123 ),
RGB( 2, 74, 202 ),
RGB( 10, 152, 172 ),
RGB( 106, 49, 202 ),
RGB( 88, 211, 50 ),
RGB( 224, 60, 40 ),
RGB( 207, 60, 113 ),
RGB( 163, 40, 179 ),
RGB( 204, 143, 21 ),
RGB( 140, 214, 18 ),
RGB( 113, 166, 161 ),
RGB( 218, 101, 94 ),
RGB( 98, 100, 220 ),
RGB( 182, 193, 33 ),
RGB( 197, 151, 130 ),
RGB( 10, 137, 255 ),
RGB( 246, 143, 55 ),
RGB( 168, 168, 168 ),
RGB( 225, 130, 137 ),
RGB( 37, 226, 205 ),
RGB( 91, 168, 255 ),
RGB( 255, 187, 49 ),
RGB( 190, 235, 113 ),
RGB( 204, 105, 228 ),
RGB( 166, 117, 254 ),
RGB( 155, 160, 239 ),
RGB( 245, 183, 132 ),
RGB( 255, 231, 55 ),
RGB( 255, 130, 206 ),
RGB( 226, 215, 181 ),
RGB( 213, 156, 252 ),
RGB( 152, 220, 255 ),
RGB( 215, 215, 215 ),
RGB( 189, 255, 202 ),
RGB( 238, 255, 169 ),
RGB( 226, 201, 255 ),
RGB( 255, 233, 197 ),
RGB( 254, 201, 237 ),
RGB( 255, 255, 255 ),
};
const float3 medianAbsoluteDeviation = RGB( 63, 175, 2 );
const float3 deviation = RGB( 76, 62, 75 );
#elif 0
// Resurrect 64 - Most popular 64 colors palette
// - leaks too much color into grey scale bar
// - dark greys are just dark purple
// https://lospec.com/palette-list/resurrect-64
const float3 palette[NUM_COLORS] = // 64
{
RGB( 46, 34, 47 ),
RGB( 49, 54, 56 ),
RGB( 69, 41, 63 ),
RGB( 76, 62, 36 ),
RGB( 62, 53, 70 ),
RGB( 50, 51, 83 ),
RGB( 22, 90, 76 ),
RGB( 55, 78, 74 ),
RGB( 110, 39, 39 ),
RGB( 11, 94, 101 ),
RGB( 122, 48, 69 ),
RGB( 103, 102, 51 ),
RGB( 117, 60, 84 ),
RGB( 72, 74, 119 ),
RGB( 131, 28, 93 ),
RGB( 105, 79, 98 ),
RGB( 98, 85, 101 ),
RGB( 107, 62, 117 ),
RGB( 35, 144, 99 ),
RGB( 84, 126, 100 ),
RGB( 158, 69, 57 ),
RGB( 174, 35, 52 ),
RGB( 179, 56, 49 ),
RGB( 11, 138, 143 ),
RGB( 162, 75, 111 ),
RGB( 150, 108, 108 ),
RGB( 195, 36, 84 ),
RGB( 127, 112, 138 ),
RGB( 77, 101, 180 ),
RGB( 30, 188, 115 ),
RGB( 14, 175, 155 ),
RGB( 205, 104, 61 ),
RGB( 144, 94, 169 ),
RGB( 162, 169, 71 ),
RGB( 232, 59, 59 ),
RGB( 234, 79, 54 ),
RGB( 171, 148, 122 ),
RGB( 146, 169, 132 ),
RGB( 207, 101, 127 ),
RGB( 251, 107, 29 ),
RGB( 240, 79, 120 ),
RGB( 230, 144, 78 ),
RGB( 145, 219, 105 ),
RGB( 245, 125, 74 ),
RGB( 77, 155, 230 ),
RGB( 247, 150, 23 ),
RGB( 155, 171, 178 ),
RGB( 178, 186, 144 ),
RGB( 48, 225, 185 ),
RGB( 246, 129, 129 ),
RGB( 237, 128, 153 ),
RGB( 213, 224, 75 ),
RGB( 249, 194, 43 ),
RGB( 205, 223, 108 ),
RGB( 251, 185, 84 ),
RGB( 168, 132, 243 ),
RGB( 252, 167, 144 ),
RGB( 143, 211, 255 ),
RGB( 199, 220, 208 ),
RGB( 143, 248, 226 ),
RGB( 253, 203, 176 ),
RGB( 234, 173, 237 ),
RGB( 251, 255, 134 ),
RGB( 255, 255, 255 ),
};
const float3 medianAbsoluteDeviation = RGB( 94, 43, 86 );
const float3 deviation = RGB( 64, 54, 46 );
#elif 0
// Endesga 64
// + great dithering in the grey scale bar
// - makes the game look too grey
// https://lospec.com/palette-list/endesga-64
const float3 palette[NUM_COLORS] = // 64
{
RGB( 14, 7, 27 ),
RGB( 19, 19, 19 ),
RGB( 28, 18, 28 ),
RGB( 27, 27, 27 ),
RGB( 26, 25, 50 ),
RGB( 39, 39, 39 ),
RGB( 3, 25, 63 ),
RGB( 57, 31, 33 ),
RGB( 12, 46, 68 ),
RGB( 59, 20, 67 ),
RGB( 87, 28, 39 ),
RGB( 42, 47, 78 ),
RGB( 61, 61, 61 ),
RGB( 19, 76, 76 ),
RGB( 93, 44, 40 ),
RGB( 0, 57, 109 ),
RGB( 30, 111, 80 ),
RGB( 98, 36, 97 ),
RGB( 137, 30, 43 ),
RGB( 12, 2, 147 ),
RGB( 66, 76, 110 ),
RGB( 142, 37, 29 ),
RGB( 93, 93, 93 ),
RGB( 138, 72, 54 ),
RGB( 51, 152, 75 ),
RGB( 0, 105, 170 ),
RGB( 196, 36, 48 ),
RGB( 101, 115, 146 ),
RGB( 147, 56, 143 ),
RGB( 198, 69, 36 ),
RGB( 48, 3, 217 ),
RGB( 133, 133, 133 ),
RGB( 90, 197, 79 ),
RGB( 191, 111, 74 ),
RGB( 234, 50, 60 ),
RGB( 200, 80, 134 ),
RGB( 224, 116, 56 ),
RGB( 255, 0, 64 ),
RGB( 237, 118, 20 ),
RGB( 255, 80, 0 ),
RGB( 0, 152, 220 ),
RGB( 245, 85, 93 ),
RGB( 122, 9, 250 ),
RGB( 146, 161, 185 ),
RGB( 153, 230, 95 ),
RGB( 202, 82, 201 ),
RGB( 230, 156, 105 ),
RGB( 255, 162, 20 ),
RGB( 237, 171, 80 ),
RGB( 246, 129, 135 ),
RGB( 180, 180, 180 ),
RGB( 0, 205, 249 ),
RGB( 255, 200, 37 ),
RGB( 219, 63, 253 ),
RGB( 12, 241, 255 ),
RGB( 211, 252, 126 ),
RGB( 246, 202, 159 ),
RGB( 255, 235, 87 ),
RGB( 199, 207, 221 ),
RGB( 243, 137, 245 ),
RGB( 148, 253, 255 ),
RGB( 249, 230, 207 ),
RGB( 253, 210, 237 ),
RGB( 255, 255, 255 ),
};
const float3 medianAbsoluteDeviation = RGB( 33, 166, 46 );
const float3 deviation = RGB( 82, 65, 64 );
#endif
float2 uv = ( fragment.texcoord0 );
float2 uvPixelated = floor( fragment.position.xy / RESOLUTION_DIVISOR ) * RESOLUTION_DIVISOR;
// the Sega Mega Drive has a 9 bit HW palette making a total of 512 available colors
// that is 3 bit per RGB channel
// 2^3 = 8
// 8 * 8 * 8 = 512 colors
// although only 61 colors were available on the screen at the same time but we ignore this for now
const int quantizationSteps = Dithering_QuantizationSteps;
float3 quantizationPeriod = _float3( 1.0 / ( quantizationSteps - 1 ) );
float3 quantizationPeriod = _float3( 1.0 / NUM_COLORS );
float3 quantDeviation = deviation;
//quantDeviation = medianAbsoluteDeviation;
// get pixellated base color
float3 color = t_BaseColor.Sample( samp0, uvPixelated * rpWindowCoord.xy ).rgb;
float3 color = t_BaseColor.Sample( s_LinearClamp, uvPixelated * rpWindowCoord.xy ).rgb;
float2 uvDither = uvPixelated;
//if( rpJitterTexScale.x > 1.0 )
@ -116,7 +409,7 @@ void main( PS_IN fragment, out PS_OUT result )
{
// quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.0625 ) * 16.0 ) );
color = Quantize( color, quantizationPeriod );
color = LinearSearch( color, palette );
result.color = float4( color, 1.0 );
return;
@ -126,8 +419,8 @@ void main( PS_IN fragment, out PS_OUT result )
// dithered quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.125 ) * 16.0 ) );
color.rgb += float3( dither, dither, dither ) * quantizationPeriod;
color = Quantize( color, quantizationPeriod );
color.rgb += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y;
color = LinearSearch( color, palette );
result.color = float4( color, 1.0 );
return;
@ -135,14 +428,19 @@ void main( PS_IN fragment, out PS_OUT result )
else if( uv.y < 0.25 )
{
color = _float3( uv.x );
color = Quantize( color, quantizationPeriod );
color = floor( color * NUM_COLORS ) * ( 1.0 / ( NUM_COLORS - 1.0 ) );
color += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y;
color = LinearSearch( color.rgb, palette );
result.color = float4( color, 1.0 );
return;
}
#endif
color.rgb += float3( dither, dither, dither ) * quantizationPeriod;// * rpJitterTexScale.y;
color.rgb += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y;
// find closest color match from Sega Mega Drive color palette
color = Quantize( color, quantizationPeriod );
// find closest color match from C64 color palette
color = LinearSearch( color.rgb, palette );
result.color = float4( color, 1.0 );
}

View file

@ -1,306 +0,0 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2024 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
Texture2D t_BaseColor : register( t0 VK_DESCRIPTOR_SET( 0 ) );
Texture2D t_BlueNoise : register( t1 VK_DESCRIPTOR_SET( 0 ) );
SamplerState s_LinearClamp : register(s0 VK_DESCRIPTOR_SET( 1 ) );
SamplerState s_LinearWrap : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256
struct PS_IN
{
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
struct PS_OUT
{
float4 color : SV_Target0;
};
// *INDENT-ON*
#define RESOLUTION_DIVISOR 4.0
#define NUM_COLORS 55
float3 Average( float3 pal[NUM_COLORS] )
{
float3 sum = _float3( 0 );
for( int i = 0; i < NUM_COLORS; i++ )
{
sum += pal[i];
}
return sum / float( NUM_COLORS );
}
float3 Deviation( float3 pal[NUM_COLORS] )
{
float3 sum = _float3( 0 );
float3 avg = Average( pal );
for( int i = 0; i < NUM_COLORS; i++ )
{
sum += abs( pal[i] - avg );
}
return sum / float( NUM_COLORS );
}
// squared distance to avoid the sqrt of distance function
float ColorCompare( float3 a, float3 b )
{
float3 diff = b - a;
return dot( diff, diff );
}
// find nearest palette color using Euclidean distance
float3 LinearSearch( float3 c, float3 pal[NUM_COLORS] )
{
int index = 0;
float minDist = ColorCompare( c, pal[0] );
for( int i = 1; i < NUM_COLORS; i++ )
{
float dist = ColorCompare( c, pal[i] );
if( dist < minDist )
{
minDist = dist;
index = i;
}
}
return pal[index];
}
#define RGB(r, g, b) float3(float(r)/255.0, float(g)/255.0, float(b)/255.0)
void main( PS_IN fragment, out PS_OUT result )
{
#if 0
// NES 1
// https://lospec.com/palette-list/nintendo-entertainment-system
const float3 palette[NUM_COLORS] = // 55
{
RGB( 0, 0, 0 ),
RGB( 252, 252, 252 ),
RGB( 248, 248, 248 ),
RGB( 188, 188, 188 ),
RGB( 124, 124, 124 ),
RGB( 164, 228, 252 ),
RGB( 60, 188, 252 ),
RGB( 0, 120, 248 ),
RGB( 0, 0, 252 ),
RGB( 184, 184, 248 ),
RGB( 104, 136, 252 ),
RGB( 0, 88, 248 ),
RGB( 0, 0, 188 ),
RGB( 216, 184, 248 ),
RGB( 152, 120, 248 ),
RGB( 104, 68, 252 ),
RGB( 68, 40, 188 ),
RGB( 248, 184, 248 ),
RGB( 248, 120, 248 ),
RGB( 216, 0, 204 ),
RGB( 148, 0, 132 ),
RGB( 248, 164, 192 ),
RGB( 248, 88, 152 ),
RGB( 228, 0, 88 ),
RGB( 168, 0, 32 ),
RGB( 240, 208, 176 ),
RGB( 248, 120, 88 ),
RGB( 248, 56, 0 ),
RGB( 168, 16, 0 ),
RGB( 252, 224, 168 ),
RGB( 252, 160, 68 ),
RGB( 228, 92, 16 ),
RGB( 136, 20, 0 ),
RGB( 248, 216, 120 ),
RGB( 248, 184, 0 ),
RGB( 172, 124, 0 ),
RGB( 80, 48, 0 ),
RGB( 216, 248, 120 ),
RGB( 184, 248, 24 ),
RGB( 0, 184, 0 ),
RGB( 0, 120, 0 ),
RGB( 184, 248, 184 ),
RGB( 88, 216, 84 ),
RGB( 0, 168, 0 ),
RGB( 0, 104, 0 ),
RGB( 184, 248, 216 ),
RGB( 88, 248, 152 ),
RGB( 0, 168, 68 ),
RGB( 0, 88, 0 ),
RGB( 0, 252, 252 ),
RGB( 0, 232, 216 ),
RGB( 0, 136, 136 ),
RGB( 0, 64, 88 ),
RGB( 248, 216, 248 ),
RGB( 120, 120, 120 ),
};
#else
// NES Advanced
// https://lospec.com/palette-list/nes-advanced
const float3 palette[NUM_COLORS] = // 55
{
RGB( 0, 0, 0 ),
RGB( 38, 35, 47 ),
RGB( 49, 64, 71 ),
RGB( 89, 109, 98 ),
RGB( 146, 156, 116 ),
RGB( 200, 197, 163 ),
RGB( 252, 252, 252 ),
RGB( 27, 55, 127 ),
RGB( 20, 122, 191 ),
RGB( 64, 175, 221 ),
RGB( 178, 219, 244 ),
RGB( 24, 22, 103 ),
RGB( 59, 44, 150 ),
RGB( 112, 106, 225 ),
RGB( 143, 149, 238 ),
RGB( 68, 10, 65 ),
RGB( 129, 37, 147 ),
RGB( 204, 75, 185 ),
RGB( 236, 153, 219 ),
RGB( 63, 0, 17 ),
RGB( 179, 28, 53 ),
RGB( 239, 32, 100 ),
RGB( 242, 98, 130 ),
RGB( 150, 8, 17 ),
RGB( 232, 24, 19 ),
RGB( 167, 93, 105 ),
RGB( 236, 158, 164 ),
RGB( 86, 13, 4 ),
RGB( 196, 54, 17 ),
RGB( 226, 106, 18 ),
RGB( 240, 175, 102 ),
RGB( 42, 26, 20 ),
RGB( 93, 52, 42 ),
RGB( 166, 110, 70 ),
RGB( 223, 156, 110 ),
RGB( 142, 78, 17 ),
RGB( 216, 149, 17 ),
RGB( 234, 209, 30 ),
RGB( 245, 235, 107 ),
RGB( 47, 84, 28 ),
RGB( 90, 131, 27 ),
RGB( 162, 187, 30 ),
RGB( 198, 223, 107 ),
RGB( 15, 69, 15 ),
RGB( 0, 139, 18 ),
RGB( 11, 203, 18 ),
RGB( 62, 243, 63 ),
RGB( 17, 81, 83 ),
RGB( 12, 133, 99 ),
RGB( 4, 191, 121 ),
RGB( 106, 230, 170 ),
RGB( 38, 39, 38 ),
RGB( 81, 79, 76 ),
RGB( 136, 126, 131 ),
RGB( 179, 170, 192 ),
};
#endif
float2 uv = ( fragment.texcoord0 );
float2 uvPixelated = floor( fragment.position.xy / RESOLUTION_DIVISOR ) * RESOLUTION_DIVISOR;
float3 quantizationPeriod = _float3( 1.0 / NUM_COLORS );
float3 quantDeviation = Deviation( palette );
// get pixellated base color
float3 color = t_BaseColor.Sample( s_LinearClamp, uvPixelated * rpWindowCoord.xy ).rgb;
float2 uvDither = uvPixelated;
//if( rpJitterTexScale.x > 1.0 )
{
uvDither = fragment.position.xy / ( RESOLUTION_DIVISOR / rpJitterTexScale.x );
}
float dither = DitherArray8x8( uvDither ) - 0.5;
#if 0
if( uv.y < 0.0625 )
{
color = HSVToRGB( float3( uv.x, 1.0, uv.y * 16.0 ) );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.125 )
{
// quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.0625 ) * 16.0 ) );
color = LinearSearch( color, palette );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.1875 )
{
// dithered quantized
color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.125 ) * 16.0 ) );
color.rgb += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y;
color = LinearSearch( color, palette );
result.color = float4( color, 1.0 );
return;
}
else if( uv.y < 0.25 )
{
color = _float3( uv.x );
color = floor( color * NUM_COLORS ) * ( 1.0 / ( NUM_COLORS - 1.0 ) );
color += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y;
color = LinearSearch( color.rgb, palette );
result.color = float4( color, 1.0 );
return;
}
#endif
color.rgb += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y;
// find closest color match from C64 color palette
color = LinearSearch( color.rgb, palette );
result.color = float4( color, 1.0 );
}

View file

@ -1,55 +0,0 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
struct VS_IN
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float4 normal : NORMAL;
float4 tangent : TANGENT;
float4 color : COLOR0;
float4 color2 : COLOR1;
};
struct VS_OUT {
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
// *INDENT-ON*
void main( VS_IN vertex, out VS_OUT result )
{
result.position = vertex.position;
result.position.y = -result.position.y;
result.texcoord0 = vertex.texcoord;
}

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2023 Robert Beckebans
Copyright (C) 2024 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").

View file

@ -60,8 +60,6 @@ builtin/post/retro_cpc.vs.hlsl -T vs
builtin/post/retro_cpc.ps.hlsl -T ps
builtin/post/retro_2bit.vs.hlsl -T vs
builtin/post/retro_2bit.ps.hlsl -T ps
builtin/post/retro_nes.vs.hlsl -T vs
builtin/post/retro_nes.ps.hlsl -T ps
builtin/post/retro_genesis.vs.hlsl -T vs
builtin/post/retro_genesis.ps.hlsl -T ps
builtin/post/retro_ps1.vs.hlsl -T vs

View file

@ -488,9 +488,14 @@ void Dmap( const idCmdArgs& args )
// create AAS files
RunAAS_f( args );
}
common->DmapPacifierFilename( passedName, "Done" );
}
else
{
common->DmapPacifierFilename( passedName, "Failed due to errors. Quit program." );
}
common->DmapPacifierFilename( passedName, "Done" );
// free the common .map representation
delete dmapGlobals.dmapFile;

View file

@ -1234,11 +1234,11 @@ int main( int argc, char** argv )
Dmap_f( args );
#if 0
#if 1
// maybe only do this if dmap has a leaked BSP
while( true )
{
bool captureToImage = false;
common->UpdateScreen( captureToImage );
common->UpdateScreen( false );
}
#endif

View file

@ -41,14 +41,8 @@ If you have questions concerning this license or the applicable additional terms
namespace ImGuiTools
{
// things in impl need to be used in at least one other file, but should generally not be touched
namespace impl
{
void SetReleaseToolMouse( bool doRelease );
} //namespace impl
bool ReleaseMouseForTools();
bool AreEditorsActive();

View file

@ -40,27 +40,16 @@ If you have questions concerning this license or the applicable additional terms
extern idCVar g_editEntityMode;
static bool releaseMouse = false;
#if 0 // currently this doesn't make too much sense
void ShowEditors_f( const idCmdArgs& args )
{
showToolWindows = true;
}
#endif // 0
namespace ImGuiTools
{
// things in impl need to be used in at least one other file, but should generally not be touched
namespace impl
{
void SetReleaseToolMouse( bool doRelease )
{
releaseMouse = doRelease;
}
} //namespace impl
bool AreEditorsActive()
{
// FIXME: this is not exactly clean and must be changed if we ever support game dlls
@ -69,11 +58,17 @@ bool AreEditorsActive()
bool ReleaseMouseForTools()
{
return AreEditorsActive() && releaseMouse;
// RB: ignore everything as long right mouse button is pressed
return AreEditorsActive() && releaseMouse && !ImGuiHook::RightMouseActive();
}
void DrawToolWindows()
{
if( !AreEditorsActive() )
{
return;
}
if( LightEditor::Instance().IsShown() )
{
LightEditor::Instance().Draw();
@ -98,7 +93,7 @@ void LightEditorInit( const idDict* dict, idEntity* ent )
LightEditor::Instance().ShowIt( true );
impl::SetReleaseToolMouse( true );
SetReleaseToolMouse( true );
LightEditor::ReInit( dict, ent );
}
@ -106,7 +101,7 @@ void LightEditorInit( const idDict* dict, idEntity* ent )
void AfEditorInit()
{
AfEditor::Instance().ShowIt( true );
impl::SetReleaseToolMouse( true );
SetReleaseToolMouse( true );
}
} //namespace ImGuiTools

View file

@ -196,7 +196,7 @@ void AfEditor::Draw()
if( ImGui::Begin( "AF Editor", &showTool, ImGuiWindowFlags_MenuBar ) )
{
impl::SetReleaseToolMouse( true );
SetReleaseToolMouse( true );
bool changedAf = false;
bool openedAfBrowser = false;
@ -571,7 +571,7 @@ void AfEditor::Draw()
{
// TODO: do the same as when pressing cancel?
isShown = showTool;
impl::SetReleaseToolMouse( false );
SetReleaseToolMouse( false );
}
}

View file

@ -1017,9 +1017,9 @@ void LightEditor::Draw()
ImGui::Spacing();
if( ImGui::Button( "Save to .map" ) )
if( ImGui::Button( "Apply" ) )
{
SaveChanges( true );
SaveChanges( false );
showTool = false;
}
else if( ImGui::SameLine(), ImGui::Button( "Cancel" ) )
@ -1229,7 +1229,7 @@ void LightEditor::Draw()
if( isShown && !showTool )
{
isShown = showTool;
impl::SetReleaseToolMouse( false );
SetReleaseToolMouse( false );
}
}