Skip to content

Commit b9271fa

Browse files
committed
Fixing pre-multiplied textures when needed
1 parent c613d32 commit b9271fa

2 files changed

Lines changed: 93 additions & 3 deletions

File tree

RenderGl/ImageAlphaConverter.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
Copyright (c) 2026, Lars Brubaker
3+
All rights reserved.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
1. Redistributions of source code must retain the above copyright notice, this
9+
list of conditions and the following disclaimer.
10+
2. Redistributions in binary form must reproduce the above copyright notice,
11+
this list of conditions and the following disclaimer in the documentation
12+
and/or other materials provided with the distribution.
13+
14+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
25+
The views and conclusions contained in the software and documentation are those
26+
of the authors and should not be interpreted as representing official policies,
27+
either expressed or implied, of the FreeBSD Project.
28+
*/
29+
30+
using System;
31+
32+
namespace MatterHackers.RenderGl
33+
{
34+
public static class ImageAlphaConverter
35+
{
36+
public static byte[] ConvertPremultipliedBgraToStraightAlpha(byte[] premultipliedBgra)
37+
{
38+
if (premultipliedBgra == null)
39+
{
40+
throw new ArgumentNullException(nameof(premultipliedBgra));
41+
}
42+
43+
if (premultipliedBgra.Length % 4 != 0)
44+
{
45+
throw new ArgumentException("Expected BGRA pixels.", nameof(premultipliedBgra));
46+
}
47+
48+
var straightAlphaBgra = new byte[premultipliedBgra.Length];
49+
for (int pixelOffset = 0; pixelOffset < premultipliedBgra.Length; pixelOffset += 4)
50+
{
51+
byte alpha = premultipliedBgra[pixelOffset + 3];
52+
straightAlphaBgra[pixelOffset + 0] = UnpremultiplyChannel(premultipliedBgra[pixelOffset + 0], alpha);
53+
straightAlphaBgra[pixelOffset + 1] = UnpremultiplyChannel(premultipliedBgra[pixelOffset + 1], alpha);
54+
straightAlphaBgra[pixelOffset + 2] = UnpremultiplyChannel(premultipliedBgra[pixelOffset + 2], alpha);
55+
straightAlphaBgra[pixelOffset + 3] = alpha;
56+
}
57+
58+
return straightAlphaBgra;
59+
}
60+
61+
private static byte UnpremultiplyChannel(byte channel, byte alpha)
62+
{
63+
if (alpha == 0)
64+
{
65+
return 0;
66+
}
67+
68+
if (alpha == 255)
69+
{
70+
return channel;
71+
}
72+
73+
return (byte)Math.Min(255, (channel * 255 + alpha / 2) / alpha);
74+
}
75+
}
76+
}

VorticeD3D/NativeSceneEffects.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ public void Dispose()
182182

183183
private sealed class ImageTextureSource : IDisposable
184184
{
185+
public bool ConvertPremultipliedToStraightAlpha;
185186
public MatterHackers.Agg.Image.ImageBuffer SourceImage;
186187
public ID3D11ShaderResourceView ShaderResourceView;
187188
public ID3D11Texture2D Texture;
@@ -593,7 +594,10 @@ private ColorTextureTarget EnsureColorTarget(ColorTextureTarget existingTarget,
593594
return newTarget;
594595
}
595596

596-
private ImageTextureSource EnsureImageTextureSource(ImageTextureSource existingSource, MatterHackers.Agg.Image.ImageBuffer sourceImage)
597+
private ImageTextureSource EnsureImageTextureSource(
598+
ImageTextureSource existingSource,
599+
MatterHackers.Agg.Image.ImageBuffer sourceImage,
600+
bool convertPremultipliedToStraightAlpha = false)
597601
{
598602
if (sourceImage == null)
599603
{
@@ -602,6 +606,7 @@ private ImageTextureSource EnsureImageTextureSource(ImageTextureSource existingS
602606
}
603607

604608
if (ReferenceEquals(existingSource?.SourceImage, sourceImage)
609+
&& existingSource.ConvertPremultipliedToStraightAlpha == convertPremultipliedToStraightAlpha
605610
&& existingSource.ShaderResourceView != null)
606611
{
607612
return existingSource;
@@ -610,6 +615,7 @@ private ImageTextureSource EnsureImageTextureSource(ImageTextureSource existingS
610615
existingSource?.Dispose();
611616
var textureSource = new ImageTextureSource
612617
{
618+
ConvertPremultipliedToStraightAlpha = convertPremultipliedToStraightAlpha,
613619
SourceImage = sourceImage,
614620
};
615621

@@ -625,7 +631,9 @@ private ImageTextureSource EnsureImageTextureSource(ImageTextureSource existingS
625631
BindFlags = BindFlags.ShaderResource,
626632
};
627633

628-
var pixels = sourceImage.GetBuffer();
634+
var pixels = convertPremultipliedToStraightAlpha
635+
? ImageAlphaConverter.ConvertPremultipliedBgraToStraightAlpha(sourceImage.GetBuffer())
636+
: sourceImage.GetBuffer();
629637
var handle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
630638
try
631639
{
@@ -674,7 +682,13 @@ private void RenderBedShadowTexture(BedRenderCommand bedCommand)
674682
}
675683

676684
EnsureBedTargets(bedCommand.TopBaseTexture.Width, bedCommand.TopBaseTexture.Height);
677-
bedBaseTexture = EnsureImageTextureSource(bedBaseTexture, bedCommand.TopBaseTexture);
685+
// AGG stores this generated texture with premultiplied color channels.
686+
// Convert it back to straight alpha for the D3D textured mesh pipeline so
687+
// a translucent white bed stays visually white instead of turning gray.
688+
bedBaseTexture = EnsureImageTextureSource(
689+
bedBaseTexture,
690+
bedCommand.TopBaseTexture,
691+
convertPremultipliedToStraightAlpha: true);
678692

679693
var signature = ComputeBedShadowSignature(bedCommand);
680694
if (signature == lastBedShadowSignature

0 commit comments

Comments
 (0)