It is currently December 7th, 2022, 7:25 pm

[Solved] InlineSetting=Shadow error when using TransformationMatrix

Report bugs with the Rainmeter application and suggest features.
User avatar
SilverAzide
Rainmeter Sage
Posts: 2180
Joined: March 23rd, 2015, 5:26 pm

[Solved] InlineSetting=Shadow error when using TransformationMatrix

Post by SilverAzide »

Hello,

It appears that the String meter's InlineSetting=Shadow option is not rendering the shadow quite right when using TransformationMatrix on the meter. It is acting as if the shadow is being drawn with scaling applied twice or something similar.

For example:
Annotation 2022-08-09 164416.png
The code to duplicate this is below. Please note what happens if you comment out the SkinWidth line; the rendering will be correct. This effect also happens when setting the width on the string meter; text will render the shadow incorrectly in proportion to the width as specified by the TransformationMatrix value.

Code: Select all

[Rainmeter]
AccurateText=1
BackgroundMode=2
DynamicWindowSize=1
SolidColor=88,138,178,255
SkinWidth=400

[Meter1]
Meter=String
AntiAlias=1
FontColor=255,255,255
FontSize=20
FontWeight=400
InlineSetting=Shadow | 2 | 4 | 3 | 0,0,0
Text="100% Test Test Test Test Test Test Test Test"
X=5
Y=5

[Meter2]
Meter=String
AntiAlias=1
FontColor=255,255,255
FontSize=30
FontWeight=400
InlineSetting=Shadow | 2 | 4 | 3 | 0,0,0
Text="66% Test Test Test Test Test Test Test Test Test Test Test"
X=0r
Y=60r
TransformationMatrix=0.66;0;0;0.66;0;0

[Meter3]
Meter=String
AntiAlias=1
FontColor=255,255,255
FontSize=40
FontWeight=400
InlineSetting=Shadow | 2 | 4 | 3 | 0,0,0
Text="50% Test Test Test Test Test Test Test Test Test Test Test"
X=0r
Y=100r
TransformationMatrix=0.50;0;0;0.50;0;0
Thanks!
You do not have the required permissions to view the files attached to this post.
Gadgets Wiki GitHub More Gadgets...
User avatar
Yincognito
Rainmeter Sage
Posts: 4817
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Bug] InlineSetting=Shadow error when using TransformationMatrix

Post by Yincognito »

SilverAzide wrote: August 9th, 2022, 8:57 pmIt appears that the String meter's InlineSetting=Shadow option is not rendering the shadow quite right when using TransformationMatrix on the meter. It is acting as if the shadow is being drawn with scaling applied twice or something similar.
[...]
The code to duplicate this is below. Please note what happens if you comment out the SkinWidth line; the rendering will be correct. This effect also happens when setting the width on the string meter; text will render the shadow incorrectly in proportion to the width as specified by the TransformationMatrix value.
[...]
I don't think this is the fault of TransformationMatrix or InlineSetting=Shadow options, which probably both work correctly. The way I see it, the SkinWidth option is most likely "clamping" the meter / string width to a value less than TransformationMatrix needs to scale the inline Shadow completely (in other words, less than the meters' original widths). Also, setting the width of the String meters doesn't produce incomplete shadows if used along a ClipString=... option (scroll to see the effect on various widths - also, notice how the final visible width is not the one set by the variable, but that value scaled by TransformationMatrix, which kind of explains why the shadow extended to precisely the same area in your screenshot as well):

Code: Select all

[Variables]
Width=400

[Rainmeter]
AccurateText=1
BackgroundMode=2
DynamicWindowSize=1
SolidColor=88,138,178,255
; SkinWidth=400
MouseScrollUpAction=[!SetVariable Width (Clamp([#Width]+5,5,[#SCREENAREAWIDTH]))][!Update]
MouseScrollDownAction=[!SetVariable Width (Clamp([#Width]-5,5,[#SCREENAREAWIDTH]))][!Update]

[Meter1]
Meter=String
AntiAlias=1
FontColor=255,255,255
FontSize=20
FontWeight=400
InlineSetting=Shadow | 2 | 4 | 3 | 0,0,0
Text="100% Test Test Test Test Test Test Test Test"
X=5
Y=5
W=[#Width]
ClipString=1
DynamicVariables=1

[Meter2]
Meter=String
AntiAlias=1
FontColor=255,255,255
FontSize=30
FontWeight=400
InlineSetting=Shadow | 2 | 4 | 3 | 0,0,0
Text="66% Test Test Test Test Test Test Test Test Test Test Test"
X=0r
Y=60r
W=[#Width]
ClipString=1
TransformationMatrix=0.66;0;0;0.66;0;0
DynamicVariables=1

[Meter3]
Meter=String
AntiAlias=1
FontColor=255,255,255
FontSize=40
FontWeight=400
InlineSetting=Shadow | 2 | 4 | 3 | 0,0,0
Text="50% Test Test Test Test Test Test Test Test Test Test Test"
X=0r
Y=100r
W=[#Width]
ClipString=1
TransformationMatrix=0.50;0;0;0.50;0;0
DynamicVariables=1

One more thing, related to the observations before the code above: if you set SkinWidth to the largest width of those 3 String meters (roughly 1335 pixels as per my Screen Ruler skin), the inline shadow will be complete on all meters:
Largest String Meter Width.jpg
I guess this is because: a) the width is not clamped to less than that; b) the original width of the meters, along with the distance to the left side of the skin, is the one used by TransformationMatrix internally, something relatively consistent with the documentation on it.

That being said, if I remember correctly, you use TM extensively in your skins to scale things. It's probably too late and too much work to change the system now, but setting the skin dimensions based on the font face & size being used (via measuring the largest text dimension in the skin using an invisible String meter reference) is less prone to such surprises than doing the reverse and scaling things based on skin dimensions using TMs. Other than that, from a visual point of view, you shouldn't even need to set the skin dimensions since these will adjust to the opaque pixels in your skin anyway when using DynamicWindowSize=1.
You do not have the required permissions to view the files attached to this post.
User avatar
SilverAzide
Rainmeter Sage
Posts: 2180
Joined: March 23rd, 2015, 5:26 pm

Re: [Bug] InlineSetting=Shadow error when using TransformationMatrix

Post by SilverAzide »

Hmm. Yeah, it's got to be due to the original "pre-transformed" sizes being larger than the skin, but it still seems weird to me that it is happening only to the shadow and not to the text itself. Bummer. I'll just have to work around it, I guess.

I don't generally like scaling fonts by simply multiplying them by a scaling factor (although, as in this instance, it is an unavoidable workaround to using TM). The reason is that some (? most? all?) fonts don't scale smoothly. Like if you set a font to be 12.1 points, it will just end up being the same as 12. Same for other increments until you get to 12.5 or 13 or whatever, then it will "jump" to the next size it supports. With TM, fonts smoothly scale to any point size, including fractional ones. I used to have a skin that demoed this. This doesn't matter a whole lot at large point sizes, but at small point sizes (and/or with scale factors that are oddballs, like 0.85 or 1.33) it can make a huge difference. And a very huge difference if your skin is very tightly packed without a lot of room to spare.
Gadgets Wiki GitHub More Gadgets...
User avatar
Yincognito
Rainmeter Sage
Posts: 4817
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Bug] InlineSetting=Shadow error when using TransformationMatrix

Post by Yincognito »

SilverAzide wrote: August 30th, 2022, 12:03 amI don't generally like scaling fonts by simply multiplying them by a scaling factor (although, as in this instance, it is an unavoidable workaround to using TM). The reason is that some (? most? all?) fonts don't scale smoothly. Like if you set a font to be 12.1 points, it will just end up being the same as 12. Same for other increments until you get to 12.5 or 13 or whatever, then it will "jump" to the next size it supports. With TM, fonts smoothly scale to any point size, including fractional ones. I used to have a skin that demoed this. This doesn't matter a whole lot at large point sizes, but at small point sizes (and/or with scale factors that are oddballs, like 0.85 or 1.33) it can make a huge difference. And a very huge difference if your skin is very tightly packed without a lot of room to spare.
That's true. Well, my skins are just as tight and without any room to spare as yours, but I did indeed settle on using only integer font sizes. Some fonts do scale badly on small sizes, but the one I use (Tahoma) works just fine at size 7 for me. Anyway, it was just another way of doing things when talking about advantages and disadvantages, in case it helps spur some ideas - I perfectly understand why you chose this way (which otherwise is comfortable as well).
SilverAzide wrote: August 30th, 2022, 12:03 amHmm. Yeah, it's got to be due to the original "pre-transformed" sizes being larger than the skin, but it still seems weird to me that it is happening only to the shadow and not to the text itself. Bummer. I'll just have to work around it, I guess.
Actually, it does happen to the text as well, when it is clipped like in my adjusted code. It doesn't in your code because you didn't set a similar width on it (which is effectively done when using the ClipString option in the case of String meters). So, the result is that the SkinWidth option, while it does crop the text meters accordingly, doesn't enforce a (maximum) width on them, like it apparently does for the inline Shadow effect. I agree that it's unusual and might very well be a bug - I mean, even if the inline Shadow is treated like an "image" (which is also cropped by SkinWidth if at the margins of the skin), images scale fine and entirely in such a case, unlike inline shadows.

The devs should know more about the particularities in implementing the inline shadows. There were somewhat similar lil' bugs in the past when it came to inline shadows (since then, fixed), so maybe this is just the one that got away at the revision, so to speak. :D
User avatar
Brian
Developer
Posts: 2537
Joined: November 24th, 2011, 1:42 am
Location: Utah

Re: [Bug] InlineSetting=Shadow error when using TransformationMatrix

Post by Brian »

Yincognito is right on this. The meter is getting truncated at the width of the skin (in this case: 400). In this example, the shadow effect needs the extra width provided from the transform. This is why the skin is so wide (without using SkinWidth) - the transform is making it that wide.

If you place a SolidColor and W on the meter, you can see exactly where the shadow stops (using the SKinWidth version).

Code: Select all

[Meter3]
Meter=String
AntiAlias=1
FontColor=255,255,255
FontSize=40
FontWeight=400
InlineSetting=Shadow | 2 | 4 | 3 | 0,0,0
Text="50% Test Test Test Test Test Test Test Test Test Test Test"
X=0r
Y=100r
TransformationMatrix=0.50;0;0;0.50;0;0
SolidColor=255,0,0,100
W=400
Since SkinWidth is truncating the meter itself (as well as the entire skin), the shadow effect cannot apply shadow to "nothing".

-Brian
User avatar
Yincognito
Rainmeter Sage
Posts: 4817
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Bug] InlineSetting=Shadow error when using TransformationMatrix

Post by Yincognito »

Brian wrote: September 1st, 2022, 7:22 amThe meter is getting truncated at the width of the skin (in this case: 400). In this example, the shadow effect needs the extra width provided from the transform.
Indeed. In essence, the actual cause for the described effect is not the truncation itself, but the fact that it happens before TM gets the chance of transforming the entire (as in, not yet truncated) meter content. If there was a way to let TM (or any other stuff that needs the entire width) do its thing on the unaltered meter content, and only afterwards truncate skin elements via SkinWidth, then problem solved. Of course, this might not be feasible or possible given the current internal order of operations in Rainmeter, or if it was, it could produce other "new" side effects in other places... :???:
User avatar
Yincognito
Rainmeter Sage
Posts: 4817
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Bug] InlineSetting=Shadow error when using TransformationMatrix

Post by Yincognito »

SilverAzide wrote: August 9th, 2022, 8:57 pmIt appears that the String meter's InlineSetting=Shadow option is not rendering the shadow quite right when using TransformationMatrix on the meter. [...] Please note what happens if you comment out the SkinWidth line; the rendering will be correct.
Just for the record, it appears this effect also happens if one is truncating the dimensions of the skin using a Container meter ... at least when doing it the "normal" way, by setting the container's width to 400 pixels in the original example skin - I suppose that this is because of the phrase in the manual saying that the "content outside the container is truncated, and in effect doesn't exist" (hence, TM partially working with "nothing" in this case as well, as per Brian's words).

Luckily, using the trick of setting the container's width large enough for TM to do its job properly, coupled with displaying only the first 400 horizontal pixels via its Shape's opaque pixels, AND (very important!) keeping the SkinWidth option to finally truncate the result to the desired overall width gets you the expected result:

Code: Select all

[Rainmeter]
AccurateText=1
BackgroundMode=2
DynamicWindowSize=1
SolidColor=88,138,178,255
SkinWidth=400

[Meter0]
Meter=Shape
Shape=Rectangle 0,0,400,150 | Fill Color 0,0,0,255 | StrokeWidth 0
W=1335
H=150

[Meter1]
Container=Meter0
Meter=String
AntiAlias=1
FontColor=255,255,255
FontSize=20
FontWeight=400
InlineSetting=Shadow | 2 | 4 | 3 | 0,0,0
Text="100% Test Test Test Test Test Test Test Test"
X=5
Y=5

[Meter2]
Container=Meter0
Meter=String
AntiAlias=1
FontColor=255,255,255
FontSize=30
FontWeight=400
InlineSetting=Shadow | 2 | 4 | 3 | 0,0,0
Text="66% Test Test Test Test Test Test Test Test Test Test Test"
X=0r
Y=60r
TransformationMatrix=0.66;0;0;0.66;0;0

[Meter3]
Container=Meter0
Meter=String
AntiAlias=1
FontColor=255,255,255
FontSize=40
FontWeight=400
InlineSetting=Shadow | 2 | 4 | 3 | 0,0,0
Text="50% Test Test Test Test Test Test Test Test Test Test Test"
X=0r
Y=100r
TransformationMatrix=0.50;0;0;0.50;0;0
Properly Truncating Inline Shadow.jpg
Feel free to adjust things accordingly in your actual code - here I just used a hardcoded value for the width, but normally it would be the maximum of all the meters' original widths (or, you can just set it to #SCREENAREAWIDTH# or something similar). There is the slight gotcha that you have to also specify a height for the container in order for it to work, but I suppose this can be adjusted via some other trick some place else, so in the end I guess it's still a progress in the right direction. ;-)

Hopefully you'll be able to use skinwide containers in your actual code, because if you already have other containers in the skins, this will not work because containers cannot be "nested" as per the manual...
You do not have the required permissions to view the files attached to this post.
User avatar
SilverAzide
Rainmeter Sage
Posts: 2180
Joined: March 23rd, 2015, 5:26 pm

Re: [Bug] InlineSetting=Shadow error when using TransformationMatrix

Post by SilverAzide »

Thanks for the replies Brian and Yincognito!

In my particular scenario, I'm already using containers, so I can't use the container trick in this particular instance, though it would be a very handy solution elsewhere. Fortunately, I was able to use the simple work-around of not using TransformationMatrix and instead using "font size * scale" since it works fine in this instance. All the other text in the skin isn't affected by this issue since the strings are all short enough to fit within the skin's width.
Gadgets Wiki GitHub More Gadgets...
User avatar
Yincognito
Rainmeter Sage
Posts: 4817
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Bug] InlineSetting=Shadow error when using TransformationMatrix

Post by Yincognito »

SilverAzide wrote: September 1st, 2022, 11:59 am Thanks for the replies Brian and Yincognito!

In my particular scenario, I'm already using containers, so I can't use the container trick in this particular instance, though it would be a very handy solution elsewhere. Fortunately, I was able to use the simple work-around of not using TransformationMatrix and instead using "font size * scale" since it works fine in this instance. All the other text in the skin isn't affected by this issue since the strings are all short enough to fit within the skin's width.
No problem - whatever approach you used, the important thing is that it worked as desired. :great:

-------------------------------------------

On a side note, I wonder if there's any particular reason - apart from the defaults of the skin's screen space inherent to C++ - why TMs are locked into using the (0,0) point in the skin as a reference, since it kind of complicates the TM values needed for the transformation. Looking at the source code, it appears Rainmeter uses D2D1_MATRIX_3X2_F to apply the TM. From the examples provided by Microsoft it looks like the transformation can be done way easier just by specifying the desired transformation (rotating, scaling, skewing or translation) and the "center" point around which the transformation is being performed.

Now, I realize that this is the way transformations are done for the (once, new) Shape meter, along with specifying the order of transformations, but personally I would try to add a general meter Transform option that hopefully could reliably detect and perform mouse actions on the bounding box of the transformed meter (which would naturally update the meter's position and dimensions accordingly when updating the meter) and slowly attempt to deprecate both the TransformationMatrix option AND the meter type specific transformation options like ImageRotate, Angle, Shape meter's transform modifiers, etc. in order to replace them with a new, solid and working for all meters irrespective of type option. Something like Transform=Rotate 90,10,50 | Scale 3.0,0.5,100,100 | Skew 0,-20,100,0 | Translate 10,0 | TransformOrder Scale,Rotate,Skew,Translate or similar.

Of course, this is just a wishful thinking, until figuring out how to overcome the problems in the system and implementing it. It's a nice wish though... :sly:
User avatar
Brian
Developer
Posts: 2537
Joined: November 24th, 2011, 1:42 am
Location: Utah

Re: [Solved] InlineSetting=Shadow error when using TransformationMatrix

Post by Brian »

Ok...it turns out I sort of lied in my description of the problem. O.O I glanced over a few things when investigating this.

TransformationMatrix is applied before any drawing occurs. It's the first step.

When the shadow is applied, it needs to create another "target" to draw on since we are only applying a shadow to a portion of the text. This "target" uses the same dimensions as the skin....but in this case, those dimensions are truncated by SkinWidth. Then the shadow is drawn just before the regular text.

So, while the TM is applied before the shadow is rendered, the rendering assumed the dimensions incorrectly.

Good news, I fixed it. Instead of using the skins dimensions, I used the meter's dimensions.

Honestly, this would have never come up with using TM.


Yincognito wrote: September 1st, 2022, 1:59 pm On a side note, I wonder if there's any particular reason - apart from the defaults of the skin's screen space inherent to C++ - why TMs are locked into using the (0,0) point in the skin as a reference, since it kind of complicates the TM values needed for the transformation. Looking at the source code, it appears Rainmeter uses D2D1_MATRIX_3X2_F to apply the TM. From the examples provided by Microsoft it looks like the transformation can be done way easier just by specifying the desired transformation (rotating, scaling, skewing or translation) and the "center" point around which the transformation is being performed.

Now, I realize that this is the way transformations are done for the (once, new) Shape meter, along with specifying the order of transformations, but personally I would try to add a general meter Transform option that hopefully could reliably detect and perform mouse actions on the bounding box of the transformed meter (which would naturally update the meter's position and dimensions accordingly when updating the meter) and slowly attempt to deprecate both the TransformationMatrix option AND the meter type specific transformation options like ImageRotate, Angle, Shape meter's transform modifiers, etc. in order to replace them with a new, solid and working for all meters irrespective of type option. Something like Transform=Rotate 90,10,50 | Scale 3.0,0.5,100,100 | Skew 0,-20,100,0 | Translate 10,0 | TransformOrder Scale,Rotate,Skew,Translate or similar.

Of course, this is just a wishful thinking, until figuring out how to overcome the problems in the system and implementing it. It's a nice wish though... :sly:
Yes, there are easier ways to do this...however, when migrated from GDI to D2D, the goal was to get the same visual representation between the 2 rendering systems. Due to the high amount of effort this was, we often used the closest API functions to GDI as we could. This meant less "manual" testing at the time.

And yes, meter transforms are on the "TODO" list.....the never ending list. 8-)

-Brian