View Issue Details

IDProjectCategoryView StatusLast Update
0006606The Dark ModGraphicspublic09.02.2025 20:29
Reporterstgatilov Assigned Tostgatilov  
PrioritynormalSeveritynormalReproducibilityhave not tried
Status assignedResolutionopen 
Product VersionTDM 2.13 
Target VersionTDM 2.14 
Summary0006606: Apply tonemap to 3D game only, don't change HUDs
DescriptionIn the original Doom 3, gamma and brightness changed global OS settings, and thus applied to everything.
Then it was replaced with tonemap, which also applied to everything.

After that we had an attempt to make tonemap only work on 3d rendering but not to GUI overlays/menus.
It failed because we found that some GUI overlays are part of the game, e.g. underwater overlays.

In 2.13 we have r_tonemapOnlyGame3d, which disables tonemap for main menus.
However, it still applies to everything including HUD when the game is rendered.

It would be great to put tonemap to its proper place finally!
TagsNo tags attached.

Activities

stgatilov

stgatilov

09.02.2025 20:03

administrator   ~0016967

I believe I managed to do this.

The main problem is that player has GUI overlays.
All of them are called "HUD" in the code, but some of them are actually fullscreen postprocessing stuff (e.g. underwater overlay and X-ray glasses).
These postprocessing overlays must be run before tonemapping, while the proper HUD must be run after tonemapping.

All the overlays are sorted by "layer".
The core idea is to run all overlays with (layer <= LAYER_LAST_TONEMAPPED) before tonemapping, and all the remaining overlays after tonemapping.
So I extracted the code which issues tonemap command into its own method of Session, and call it inside idPlayer::DrawHUD.
It is not very nice that such an unavoidable part of rendering is done so deeply inside game code... but I guess it's better than splitting this code more hard way.

I faced a few problems here:
1) Before we run tonemap, we should remember to invoke EmitFullScreen + Clear on tr.guiModel.
  It flushes GUI geometry from accumulation buffer into the current view.
2) We still must do something like tonemap when player view is not rendered at all (processing is useless, but switching FBO is necessary).
  So I decided to explicitly invoke "full-black tonemap" at the beginning of idSessionLocal::Draw when player view is not rendered.
  It is different from normal tonemap in that it does not do any processing, it only switches to output FBO and clears it to black.
stgatilov

stgatilov

09.02.2025 20:28

administrator   ~0016968

If fixing the water was rather easy, X-ray glasses were not.

They must be rendered before tonemapping, because they use image generated as subview, and because we want it to be adjusted with brightness/gamma along with the rest of the world.
But right now the X-ray overlay is created in arbitrary layer (no it's usually layer = 6, i.e. after tonemap), because nobody added any special interface for it.
So the first thing which had to be done was to wrap creation of X-ray overlay into special script event.
This is a breaking change: we'll have to search for all X-ray glasses in all missions and replace overlay creation with $player1.createXrayOverlay.

In general, the X-ray GUI stuff was implemented in too loose way, which will bite us in future.
From this moment, I would assume that:
1) X-ray GUI is a player overlay created with "createXrayOverlay" event.
2) The overlay only exists when X-ray rendering is needed, and destroyed when glasses are put off.
3) The overlay GUI contains exactly one window with background material that has exactly one xrayRenderMap.

The X-ray GUI is a very tough feature to maintain, because it tied together many separate systems: game, GUI, frontend.
I had to almost completely rewrite its integration recently, and now I had to rewrite it again, because after tonemap split it is no longer possible to pass information in tr.guiModel.
And since I have to change this anyway, I decided to also fix the issue of one frame delay.

Now there is special method idPlayer::CheckForXrayOverlay which is called at the beginning of gameplay drawing.
It checks whether player has some X-ray overlay, and puts information about it into idRenderWorldLocal::xrayGuiOverlayStage.
When frontend generates subviews for the main view, it looks at this information: if GUI overlay exists, than X-ray subview is generated.
The output image of this subview is passed further into tr.xrayGuiImageOverride.
Finally, when GUI geometry is flushed into rendered view, we check for Xray materials in idGuiModel::ProcessOverlaySubviews.
If we find any, we tell them to use the override image of the subview.
stgatilov

stgatilov

09.02.2025 20:29

administrator   ~0016969

I also find a bug with using X-ray glasses with nontrivial Render Scale.
But this issue happens now on 2.13 beta too, so I committed it in svn rev 10933.

The rest will obviously be committed after 2.13 is released.
Meahwhile, attaching here the archive with patches.

P.S. And don't forget about updating all missions that use X-ray glasses.
patches.zip (19,568 bytes)

Issue History

Date Modified Username Field Change
26.01.2025 10:04 stgatilov New Issue
26.01.2025 10:04 stgatilov Status new => assigned
26.01.2025 10:04 stgatilov Assigned To => stgatilov
09.02.2025 20:03 stgatilov Note Added: 0016967
09.02.2025 20:28 stgatilov Note Added: 0016968
09.02.2025 20:29 stgatilov Note Added: 0016969
09.02.2025 20:29 stgatilov File Added: patches.zip