daid / EmptyEpsilon

Open source bridge simulator. Build with the SeriousProton engine.
https://daid.github.io/EmptyEpsilon/
GNU General Public License v2.0
528 stars 177 forks source link

[Android] Low color contrast, blending/layering issues make GL lines difficult to discern #1814

Closed oznogon closed 1 year ago

oznogon commented 1 year ago

Reproduced with:

Reproduced on:

Steps to reproduce:

  1. Start a server
  2. Select any scenario with scannable targets, and options. (Used Battlefield to test)
  3. Select a player ship (create one if necessary)
  4. Select Science or Operations stations
  5. Select a scannable target and attempt to scan it

Expected behavior:

The scanning interface displays the colored beams that must be aligned by moving the slider.

Observed behavior:

The colored bands are nearly invisible and unusable in play.

PXL_20221230_204132064

oznogon commented 1 year ago

Ran into additional similar issues:

On Android, the radar border, heading ticks, unit range circles, and missile targeting lines are so faint that they're barely visible in screenshots and not visible on the actual device:

image

Compare to this Windows desktop shot, where the lines are all clearly visible and opaque white or blue:

image

On Science, similar issues. Sector borders aren't visible, but sector names are. Signal bands and shield/beam frequency damage graphs are nearly invisible:

image

Windows desktop comparison:

image

Also note that the background on desktop is lighter, the background's grid of small crosses appear on the radar, and that text, UI element frames and buttons, sprites, beam ranges, and shield segments seem unaffected on Android.

This doesn't seem to be specific to any device; these screenshots are from a 2019 9th-gen Fire HD 10, and I've now also observed it on a 5th-gen Fire 7, Pixel 3a, and OnePlus Nord N10 running a variety of flavors and versions of Android.

The behavior, along with #1813, suggests to me some potential layer and alpha blending issues specific to Android. The lines are being rendered, but either with faint transparency or with a dark translucent layer over them.

oznogon commented 1 year ago

Relay with a normal alert level, master branch Android armv7 build. Note no visible sector gridlines or dots, how the friendly radar appears darker rather than lighter than the fog of war, and the heading numbers rendering over the controls (#1813):

Screenshot_20230307-181105

Windows desktop, master branch:

image

Relay with a red alert overlay, master branch Android armv7 build. Note how much darker the radar view becomes - no color blending:

Screenshot_20230307-181116

Windows desktop, master branch:

image

oznogon commented 1 year ago

Alert overlays are implemented in src/screenComponents/indicatorOverlays.cpp via sp::RenderTarget::drawRectColorMultiply, which is just:

void RenderTarget::drawRectColorMultiply(const sp::Rect& rect, glm::u8vec4 col
or)
{
    finish();
    glBlendFunc(GL_DST_COLOR, GL_ZERO);
    fillRect(rect, color);
    finish();
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

GL_BLEND is enabled in the constructor, and so is glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) . So this function just changes the blending function to a color filter, draws the rectangle in the given color, and goes back to the prior blending function.

It feels like only the desktop renderer understands the blend modes/GLES needs a shader to blend?

daid commented 1 year ago

blending shouldn't be depended on shaders at all. glBlendFunc is part of opengles2.0: https://registry.khronos.org/OpenGL-Refpages/es3/html/glBlendFunc.xhtml

Not sure why it behaves differently...

oznogon commented 1 year ago

This makes no sense. Removing the glBlendFunc completely from drawRectColorMultiply:

void RenderTarget::drawRectColorMultiply(const sp::Rect& rect, glm::u8vec4 color)
 {
     finish();
-    glBlendFunc(GL_DST_COLOR, GL_ZERO);
     fillRect(rect, color);

should result in a solid opaque pink (red alert) or yellow (yellow alert) rectangle, as it does on desktop:

image

But on Android the rectangle is rendered as if it's low-opacity:

image

Explicitly setting srcAlpha and dstAlpha with glBlendFuncSeparate:

void RenderTarget::drawRectColorMultiply(const sp::Rect& rect, glm::u8vec4 color)
 {
     finish();
-    glBlendFunc(GL_DST_COLOR, GL_ZERO);
+   glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ONE, GL_ZERO);
     fillRect(rect, color);

results in the desired behavior on Android, matching the desktop at least on alert overlay:

image

But why?

oznogon commented 1 year ago

It looks like the Android color and alpha blending are technically working as expected, for a narrow definition. The resulting colors are transforming exactly as you'd expect considering the inputs are wrong.

The alert overlay color rect that's being blended should be 255, 192, 192, 255 for red alert - the light pink in the desktop build above. On Android without glEnable(GL_BLEND), the rect's measurable color is 62, 46, 47, or if each value was multiplied by about 0.75.

image

So doing a GL_DST_COLOR blend on the UI with a 62, 46, 47 rect should look like this:

image

The question is, what's changing that color? Is a layer out of order?

Also with glBlend not enabled, that 75% darker color transformation is also still happening on anything in the radar background - the sector gridlines, range circles, - as well as scan dialog waveforms and the radar signal waveform ring. Those things are rendered 75% darker, but sprites, text, and UI elements aren't. Meanwhile, the base radar background itself isn't as dark on Android as on desktop, so fog of war is washed out.

Android hardware above via scrcpy, desktop below, with glEnable(GL_BLEND) commented out of sp::RenderTarget's constructor:

image

daid commented 1 year ago

Maybe the fillrect has some issue on android? (next to the blending issues) It uses a single color pixel in the texture to get a solid white. There could be a few issues at play:

oznogon commented 1 year ago

@daid I don't know why, but reducing the atlas size from 2k to 1k seems to fix this. https://github.com/daid/SeriousProton/pull/234