Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AGS4: Attribute DrawingSurface::DrawingTransparency #1514

Closed
fernewelten opened this issue Jan 23, 2022 · 10 comments
Closed

AGS4: Attribute DrawingSurface::DrawingTransparency #1514

fernewelten opened this issue Jan 23, 2022 · 10 comments
Labels
ags 4 related to the ags4 development context: graphics context: script api res: in consideration type: enhancement a suggestion or necessity to have something improved

Comments

@fernewelten
Copy link
Contributor

fernewelten commented Jan 23, 2022

Describe the problem
True-colour space provides a full-fledged alpha channel (RGBA). This alpha channel isn't easily accessible in AGS games.

In AGS, when you want to draw onto a DrawingSurface in true-colour games, you can set the pen colour with DrawingSurface::DrawingColor. However, there's no way to set the pen transparency. So convoluted workarounds are needed in order to draw semi-transparent shapes onto a surface.

Suggested change
Introduce int DrawingSurface::DrawingTransparency to set the alpha channel value of the drawing pen.

The range of this attribute would need to be discussed:
AFAIK, the real range of the alpha channel in true-colour space is [0 .. 255]. However, traditionally in AGS, alpha values are given in percent. This must by needs be inexact from the get-go, and 255 isn't an exact multiple of 100, so some percentages must by needs be “more inexact” than others.

  • [0 .. 100] (100 means completely transparent, so nothing drawn is visible)
  • [0 .. 255] (255 means completely transparent)
  • [0 .. 99] (99 translates to 252 in the scale of [0 .. 255])
  • float [0.0 .. 1.0}

We also need to discuss how this parameter should be handled in non-true-colour games, i.e., games where pixels can only be completely transparent or completely opaque.

  • Ignore the value
  • Don't draw anything whenever the value is non-zero
  • Have some other cut-off, e.g., don't draw anything whenever the value is above 50 %.
@ivan-mogilko ivan-mogilko added ags 4 related to the ags4 development context: graphics context: script api res: in consideration type: enhancement a suggestion or necessity to have something improved labels Jan 23, 2022
@ivan-mogilko
Copy link
Contributor

ivan-mogilko commented Jan 23, 2022

I mentioned this elsewhere, so will restate here. Besides finding a good script API for this feature there seem to be a couple of major problems blocking it:

  1. Currently the draw colours in AGS are represented in 16-bit range (at least ones settable by script API). Even though they are stored in 32-bit integer, they are remapped on assignment to match the range available for 16-bit graphics. Having DrawingTransparency as a separate field may potentially mitigate this issue (completely or to some extent), but otoh if you like DrawingColor to have alpha channel component instead, then solving it becomes a higher priority. Moving to full 32-bit color representation in all "color" fields is a must.

  2. IIRC all the primitive drawing operations (line, rectangle, and so on) in the graphics library are ignoring alpha channel: this has to be double checked, but they probably simply copy value over to dest. Properly using alpha channel would assume alpha-blending operations for primitive draws. Either this has to be implemented as a separate set of operations, or internally drawn on an intermediate bitmap and then result blended to the dest.

Perhaps it's worth to have at least p1 as a separate ticket.


In regards to the script API, this is of course an open topic and will be discussed further, but my IMHO currently is:

  1. If we keep color fields as integers, then 0-255 is a better range, and it should be a properly handled range, without any special edge values (e.g. currently internally there's a backward compatible treatment of 0 and 255 transparency which are given reverse meaning).
  2. Having transparency in floats in script API would only make sense if we also move colors to floats too. Personally, I don't think that's a good idea, as many people seemed to handle 0-255 ranges better than the 0-1 (and it's easier to paste values from the graphic software); but maybe times are changing, idk.
  3. I think that Alpha (or Opaqueness) property is better than Transparency, although old users may beg to differ.
  4. I think that it may be worth to (instead) include alpha component into DrawingColor and any other color field. This will let to have any color setting transparent without having to add extra fields each time. That would require to solve problem 1 from the first list.

EDIT: regarding p4 of imho, I may have a false memory, but I think @AlanDrake once suggested to have a argb Color property for every object in game, which would determine its blending operation (optionally replacing Tint and Transparency properties altogether, or used by these properties under the hood). Such property would also include alpha value.

@fernewelten
Copy link
Contributor Author

I like the idea of having something like dsu.DrawingColor = Game.GetColorFromRGBA(250, 100, 100, 255); available (where the fourth “A” parameter would be optional and default to fully opaque), and all the primitives that the current libraries can provide.

But I can see that this is going to be a lot of work if the internal coding doesn't fully provide for the alpha channel yet.

@AlanDrake
Copy link
Contributor

I remember we discussed about the use cases and limitations of Tint, that it could cover more uses if it were possible to also apply a pure color ove the sprite, but that had more to do with shaders.
We had also discussed the possiblity of having a Color property inside Tint instead of separate R G B A integers, although in the case of Tint it would make more sense to have HSV, or HSL, or both, I don't know.
Currently Tint works as a "HSV colorize filter" where RGB are the Hue/Saturation, "TintSaturation" is alpha opacity, and TintLuminance is Value (because real luminance would allow us to brighten it to white).
A single RGBA Color should be capable of describing HSV and A, so yes, it could become a sub property of Tint, but I wouldn't replace player's transparency with it, unless we change the meaning of Tint. Because the alpha in that case is how much of the tinted filter to apply over the original sprite.

Then there's LightLevel that reused some of those values. This represents a Brigthness adjustment in HW, while SW rendering applies a flat white/black color (which would be directly translatable to HSL adjustment).

Both namings and implementations are misleading. Tint and Brightness should be made separate properties.
Ideally Tint would embrace the full HSL adjustment range, so it's less limited.
That would still come short for cases where tinting with flat colors other than white/black would be preferable, though.

Sorry for having derailed the topic with these separate topics.

Anyway, I agree with all points, @ivan-mogilko .
DrawingColor should be handled natively as 32bit 0-255 values.
"Alpha/Opacity" would be a good choice for a new parameter to phase out the deprecated awkward Transparency..

@ivan-mogilko
Copy link
Contributor

ivan-mogilko commented Apr 16, 2023

Opened a ticket regarding 32-bit color values: #1980

But this ticket, I think, may be repurposed into proposal to support alpha channel during primitive drawing operations, as it's not clear whether it will work automatically with the allegro sources we're currently using. So, an extra work may be required for that purpose (also see my comment above).

@ivan-mogilko
Copy link
Contributor

ivan-mogilko commented Jan 14, 2025

So, the colors are now defined as full ARGB values since #2525. We may return to this proposal.

As I mentioned elsewhere, there's a question of which operation is used when a color with alpha is used to draw on a surface.
It can be alpha blending, but can also be "copy", where color completely replaces the one underneath. And I think that both have a right to exist. An example where "copy color" is necessary is when you want the surface to contain a translucent shape. You can't achieve this if drawing shapes always uses alpha blending, as then the final alpha will be a multiplication of src and dest: if dest is 0, then the result will also be 0, if dest is opaque, the result will also be opaque.
Suppose we have alpha blending operation by default, but then we'd need another property which configures the operation.
We have a BlendMode property in ags4, may the same property be used there? In such case "no blending" would mean "blit", or "copy color over".

enum BlendMode {
eBlendNormal = 0,
eBlendAdd,
eBlendDarken,
eBlendLighten,
eBlendMultiply,
eBlendScreen,
eBlendBurn,
eBlendSubtract,
eBlendExclusion,
eBlendDodge
};

@messengerbag
Copy link

You can't achieve this if drawing shapes always uses alpha blending, as then the final alpha will be a multiplication of src and dest: if dest is 0, then the result will also be 0, if dest is opaque, the result will also be opaque.

I don't think that's right (apart from the fact that if dest is opaque the result will be opaque, which is usually what you want; otherwise you need to clear it first). The final alpha (in a [0,1] range) should be 1 - (1 - src_alpha)*(1 - dest_alpha), I think, which means that it is fully opaque if either src or dest is opaque, and fully transparent only if both are fully transparent.

@ivan-mogilko
Copy link
Contributor

ivan-mogilko commented Jan 15, 2025

Ah... my mistake. I probably was confusing this with something else.

Well, then, what remains is implementation. AFAIK allegro functions drawing primitives do not use alpha. I think that a solution could be to provide alternate function variants that accept a blender func as an argument and call it for each pixel, just like when blending sprites is done.
I have a very vague memory of seeing how allegro's "line" function was used in similar way by the old pathfinder, where it would run a custom callback, but I do not remember details now.

EDIT: ah, here it is:

/* do_line:
* Calculates all the points along a line between x1, y1 and x2, y2,
* calling the supplied function for each one. This will be passed a
* copy of the bmp parameter, the x and y position, and a copy of the
* d parameter (so do_line() can be used with putpixel()).
*/
void do_line(BITMAP *bmp, int x1, int y1, int x2, int y2, int d, void (*proc)(BITMAP *, int, int, int))

There are also corresponding functions as do_circle, do_ellipse, and do_arc:

AL_FUNC(void, do_circle, (struct BITMAP *bmp, int x, int y, int radius, int d, AL_METHOD(void, proc, (struct BITMAP *, int, int, int))));

I suppose that "do_line" is internally used for any shape that has straight lines, like rectangle and triangle.

@ivan-mogilko
Copy link
Contributor

From what I see, right now DrawingSurface can already use "alpha" component of a DrawingColor, but it copies the color, fully replacing the pixels, not blends it. DrawingSurface.Clear is the only function that works as expected.

@ivan-mogilko
Copy link
Contributor

ivan-mogilko commented Jan 17, 2025

Hmm, this may be good news. I did not know that before, but apparently Allegro 4 has a setting called "draw mode", set by a drawing_mode function. It's DRAW_MODE_SOLID by default, and among drawing modes there's one called DRAW_MODE_TRANS which optionally makes use of a blender set with set_blender_mode_*, just like the sprites.

I tested this quickly, and this seem to affect any shape drawing and filling function: rectangle, line, circle, triangle.
The only except is "putpixel", which will have to be handled separately.

This means that not only the functionality is available, but also that we may actually have our custom "blending mode" for raw drawing too.

Image

I'll try to make a working PR tomorrow.

@ivan-mogilko
Copy link
Contributor

Resolved by #2661

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ags 4 related to the ags4 development context: graphics context: script api res: in consideration type: enhancement a suggestion or necessity to have something improved
Projects
None yet
Development

No branches or pull requests

4 participants