Repository navigation
Conversation
- Add 'a' field to ZBufferPoint (8.16 fixed-point, same as r,g,b) - Propagate vertex alpha from glColor4f through the vertex pipeline - Add GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA blend factors to TGL_BLEND_FUNC and TGL_BLEND_FUNC_RGB macros - Use TGL_ALPHA_MUL helper with (factor + factor>>7) correction to map [0,255] -> [0,256], ensuring alpha=255 is identity and alpha=0 produces exactly zero (no darkening artifacts) - Preserve texture alpha through RGB_MIX_FUNC in 32-bit mode - Add INTERP_A support to ztriangle.h for per-vertex alpha interpolation - Update smooth-shaded blend triangles to interpolate and use alpha - Update flat-shaded blend triangles to pack vertex alpha into pixel - Update line/point blend paths to pass alpha
- Add gl_convertRGBA_to_8A8R8G8B() that preserves the alpha channel when converting from RGBA byte data to internal 0xAARRGGBB format - Add gl_resizeImageNoInterpolate4() for resizing 4-channel textures - Update glopTexImage2D to accept GL_RGBA with components=4 - Texture alpha is preserved through TGL_BLEND_FUNC via the pixel's high byte, enabling proper alpha-blended textured geometry
Add 7 tests covering alpha channel rendering correctness: Untextured: - alpha_zero_transparent: alpha=0 produces fully transparent output - alpha_full_opaque: alpha=1 produces fully opaque output - alpha_half_blend: alpha=0.5 produces correct 50/50 blend - alpha_smooth_interp: GL_SMOOTH interpolates alpha per-vertex Textured (GL_RGBA): - alpha_texture_transparent: RGBA texture with alpha=0 is invisible - alpha_texture_opaque: RGBA texture with alpha=255 is fully visible - alpha_texture_half_blend: RGBA texture with alpha=128 blends correctly All tests use direct framebuffer readback and verify pixel values with a small tolerance for fixed-point rounding.
|
Please provide sample programs to illustrate the use of newly-introduced APIs. |
|
@jserv good idea. Added a |
You don't have to state that. As long as you ensure that a human remains in the loop, their use is perfectly acceptable and even encouraged. |
| #if TGL_HAS(LIT_TEXTURES) | ||
| #if TGL_FEATURE_RENDER_BITS == 32 | ||
| /* Preserve alpha from the texture pixel through the color mix */ | ||
| #define RGB_MIX_FUNC(rr, gg, bb, tpix) \ |
There was a problem hiding this comment.
The 32-bit branch pulls source alpha from tpix & 0xFF000000, but gl_convertRGB_to_8A8R8G8B in src/image_util.c leaves the high byte at zero, so every plain GL_RGB texture carries alpha 0. With glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) those textures become fully transparent and vanish. OpenGL defines alpha as 1.0 for a GL_RGB internal format, so that converter should write 0xFF000000 into the pixel. The new tests only upload GL_RGBA, so this path is uncovered.
| sr = GET_REDDER(temp); \ | ||
| sg = GET_GREENER(temp); \ | ||
| sb = GET_BLUEER(temp); \ | ||
| sa = (temp >> 24) & 0xFF; \ |
There was a problem hiding this comment.
sa is read from bits 24..31 of source, which only exist when PIXEL is 32 bits. In a TGL_FEATURE_16_BITS build the textured paths feed this macro the result of RGB_MIX_FUNC, whose non-32-bit branch carries no alpha, so sa is always 0 and every textured primitive disappears under GL_SRC_ALPHA. The flat untextured path escapes this only because color is a GLuint with alpha packed above the pixel width. Either hand alpha to the textured path out of band, or reject the two new factors when TGL_FEATURE_RENDER_BITS == 16.
| case GL_ONE: \ | ||
| default: \ | ||
| break; \ | ||
| case GL_SRC_ALPHA: \ |
There was a problem hiding this comment.
GL_SRC_ALPHA is handled only as a source factor and GL_ONE_MINUS_SRC_ALPHA only as a destination factor, so a legal call like glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA) falls through default and silently degrades to GL_ONE, GL_ONE. Both factors are valid in either slot. Mirror the cases into the other switch, here and in TGL_BLEND_FUNC_RGB.
| } | ||
|
|
||
| #define TGL_BLEND_FUNC_RGB(rr, gg, bb, dest) \ | ||
| #define TGL_BLEND_FUNC_RGB(rr, gg, bb, aa, dest) \ |
There was a problem hiding this comment.
TGL_BLEND_FUNC_RGB lives in the installed header and goes from four arguments to five, in this definition and in the TGL_FEATURE_BLEND == 0 one further down, so any out-of-tree caller stops compiling. Keep the four-argument form as a wrapper that passes opaque alpha and give the new form its own name, TGL_BLEND_FUNC_RGBA.
| im->ysize = height; | ||
| #if TGL_FEATURE_RENDER_BITS == 32 | ||
| gl_convertRGB_to_8A8R8G8B(im->pixmap, pixels1, width, height); | ||
| if (is_rgba) |
There was a problem hiding this comment.
This branch covers only TGL_FEATURE_RENDER_BITS == 32. The 16-bit #elif below still calls gl_convertRGB_to_5R6G5B, which advances three bytes per texel, while pixels1 now holds four bytes per texel when is_rgba. Texel 1 onward decode across byte boundaries and the whole texture is scrambled in any 16-bit build. The parameter check above accepts GL_RGBA regardless of render depth, so nothing stops it. Add a four-byte-stride conversion, or reject GL_RGBA unless the render depth is 32.
| (GLint) (v->color.v[2] * COLOR_CORRECTED_MULT_MASK + COLOR_MIN_MULT) & | ||
| COLOR_MASK; | ||
|
|
||
| /* Propagate alpha in the same 8.16 fixed-point format as r,g,b */ |
There was a problem hiding this comment.
src/init.c still sets c->current_color.W = 0.0, so an application that never calls glColor* now propagates vertex alpha 0 through here. Enable glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) and all of its geometry renders fully transparent. OpenGL's initial current color is (1, 1, 1, 1), so current_color.W should be 1.0.
|
|
||
| /* Propagate alpha in the same 8.16 fixed-point format as r,g,b */ | ||
| v->zp.a = | ||
| (GLint) (v->color.v[3] * COLOR_CORRECTED_MULT_MASK + COLOR_MIN_MULT) & |
There was a problem hiding this comment.
The clipped counterpart of this function, gl_transform_to_viewport_clip_c in src/clip.c, still writes only zp.r, zp.g and zp.b, and the vertices it transforms come from GLinterpolate (loop bound i < 3) and updateTmp (three explicit assignments), neither of which touches color.v[3]. Any primitive crossing a clip plane therefore rasterizes with a stale zp.a, so clipped triangles and lines get arbitrary opacity. Interpolate the fourth component in both helpers and set zp.a in the clip transform.
| *pp = RGB_TO_PIXEL(p->r, p->g, p->b); | ||
| else | ||
| TGL_BLEND_FUNC_RGB(p->r, p->g, p->b, (*pp)) | ||
| TGL_BLEND_FUNC_RGB(p->r, p->g, p->b, p->a, (*pp)) |
There was a problem hiding this comment.
This is ZB_plot, the point path. Line rasterization goes through RGBPIXEL in src/zline.h, which writes *pp = RGB_TO_PIXEL(...) without consulting zb->enable_blend, so GL_LINES, line strips and line loops stay opaque with GL_BLEND enabled. Either route those pixels through the blend macro as follow-up work, or drop the line claim from the description.
| /* Variant DT0_DW0 */ | ||
| #undef INTERP_Z | ||
| #undef INTERP_RGB | ||
| #undef INTERP_A |
There was a problem hiding this comment.
INTERP_A is left undefined for every ZB_fillTriangleMappingPerspective_* variant, so interpolated vertex alpha never reaches the blend on textured geometry and source alpha comes purely from the texel. Under the default GL_MODULATE environment a vertex alpha of 0.5 over a texel alpha of 0.5 should give 0.25, and glColor4f alpha on a textured primitive is ignored outright. Defining INTERP_A here and folding oa1 into the packed source alpha is the follow-up this needs.
afield toZBufferPoint(8.16 fixed-point, same asr,g,b)glColor4fthrough the vertex pipelineGL_SRC_ALPHA/GL_ONE_MINUS_SRC_ALPHAblend factors toTGL_BLEND_FUNCandTGL_BLEND_FUNC_RGBmacrosTGL_ALPHA_MULhelper with (factor + factor>>7) correction to map[0,255]->[0,256], ensuringalpha=255is identity andalpha=0produces exactly zero (no darkening artifacts)RGB_MIX_FUNCin 32-bit modeINTERP_Asupport toztriangle.hfor per-vertex alpha interpolationAdded tests, for both textured and untextured models, to ensure that alpha blending works correctly.
Also added a compilable demo,
examples/raw/alpha.c, to illustrate how transparency may look like. It renders a scene like the image below:closes #6
Disclaimer: Coding agent (GitHub Copilot + Claude Sonnet 4.6) is heavily used in this PR.