Ren'Py Help wanted: user-customisable tinted .png GUI (frame:) backgrounds

Me666

Newbie
Mar 14, 2018
96
214
Hello again :)

I promise I looked through the /doc folder, and smacked Google about for ages...

I have a nice little .png with full transparency except where it's opaque white. I stretch it across frames in both directions to provide edges. I've successfully used the deprecated image manipulator functions to tint it whatever shade I like - as long as I hardcode it or use defined constants. I'd like to know how to use matrixcolor TintMatrix(Color()) properly, preferably in a way that lets the user change the tint on the fly with e.g. RGB Bars.

Here's what I've tried so far (not all at once, obvs)...
You don't have permission to view the spoiler content. Log in or register now.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
I don't have time to test this answer as I type, so regard this as a suggestion rather than a solution.

Firstly, define is primarily used for static values. Values that are never changed by code or the player. What would be a CONST in other languages. Unless I'm misunderstanding your requirements, what you want is default.

Beyond that, depending on context - sometimes RenPy requires you to specify store. as a prefix to the variables names (so RenPy doesn't think it's a "local" variable, retained only during the current function). Usually I'd expect to see that only in init: blocks - but perhaps it impacts here too. Generally there's no real downside to qualifying things, expect the extra typing. However, in this case, I don't think you'd want to do that... see the next point...

I'm guessing you'd want something that is retained for future playthroughs, not something that would require the player to alter each new game. For that reason, rather than prefix these variables with store., I'm going to suggest persistent. - which would still be changeable, but would be independent of each save file.

Try this... it'll either work or it won't...

Python:
default persistent.hud_gui_r = 0.0
default persistent.hud_gui_g = 0.2
default persistent.hud_gui_b = 0.0

define hud_gui_color = "#030"

transform hud_tint:
    matrixcolor TintMatrix(hud_gui_color)

style hud:
    margin (0, 0)
    padding (5, 5)

style hud_frame is hud:
    xfill True
    background Frame(im.MatrixColor("gui/section.png", im.matrix.tint(persistent.hud_gui_r, persistent.hud_gui_g, persistent.hud_gui_b)))

My only concern is when this style / screen definition is refreshed. Screens are often pre-processed or cached. If RenPy doesn't redraw the background as the values are changed - you might not see any differences in real time. It might be that you need to move the background Frame [...] code into the frame: code within the screen: rather than using style:. Again, try it... maybe my skepticism is misplaced.
 
  • Like
Reactions: Me666

Me666

Newbie
Mar 14, 2018
96
214
I don't have time to test this answer as I type, so regard this as a suggestion rather than a solution.

Firstly, define is primarily used for static values. Values that are never changed by code or the player. What would be a CONST in other languages. Unless I'm misunderstanding your requirements, what you want is default.

Beyond that, depending on context - sometimes RenPy requires you to specify store. as a prefix to the variables names (so RenPy doesn't think it's a "local" variable, retained only during the current function). Usually I'd expect to see that only in init: blocks - but perhaps it impacts here too. Generally there's no real downside to qualifying things, expect the extra typing. However, in this case, I don't think you'd want to do that... see the next point...

I'm guessing you'd want something that is retained for future playthroughs, not something that would require the player to alter each new game. For that reason, rather than prefix these variables with store., I'm going to suggest persistent. - which would still be changeable, but would be independent of each save file.

Try this... it'll either work or it won't...

Python:
default persistent.hud_gui_r = 0.0
default persistent.hud_gui_g = 0.2
default persistent.hud_gui_b = 0.0

define hud_gui_color = "#030"

transform hud_tint:
    matrixcolor TintMatrix(hud_gui_color)

style hud:
    margin (0, 0)
    padding (5, 5)

style hud_frame is hud:
    xfill True
    background Frame(im.MatrixColor("gui/section.png", im.matrix.tint(persistent.hud_gui_r, persistent.hud_gui_g, persistent.hud_gui_b)))

My only concern is when this style / screen definition is refreshed. Screens are often pre-processed or cached. If RenPy doesn't redraw the background as the values are changed - you might not see any differences in real time. It might be that you need to move the background Frame [...] code into the frame: code within the screen: rather than using style:. Again, try it... maybe my skepticism is misplaced.
Hello, 79flavors , and thank you for your suggestions :)

I did try declaring the variables with default, since I'm aware that defines are supposed to be static, but then any attempt to use those variables in the style description failed, stating that the variables had not been defined - even when I initialised them at a lower init level.

I've not yet run into the need to prefix with store., but perhaps that's a thing I should get used to doing sooner rather than later. I shall certainly try it.

This piece of code is part of a tech demo that I'm putting together to teach myself how to do a number of things (as they occur to me), with the intention of creating something better-designed further down the road for a third party. I've used persistent before, with variables attached to settings in the preferences screen, but this particular code was simply to see if I could specifically use variables to tweak styles on the fly, as altered by the player during run-time. I shall, of course, try using persistent - which should at least stop it telling me that it's not defined. I'm trying to avoid setting up multiple hardcoded styles with specific shades, but if push comes to shove, I can do so - or simply use multiple versions of the image. But I'd far rather have the work done for me, given that there are at least two techniques in Ren'Py that have been specifically designed to do it!

I'm also trying to avoid using image manipulators, as they are specifically called out as deprecated in the documentation - which states that I should use matrixcolor transforms instead... without actually explaining how. This is the bit that I'd like to know the most because, thus far, image manipulators are the only thing that has worked :(

Thank you again, and any further advice would be much appreciated!
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
Very quick reply, without reading everything in detail...

default runs after init: have already completed. I'm a little surprised it complained they didn't exist, but I'm not really coding right now... just popping in occasionally to get my F95 fix - so I'll take your word for it that the screen: definition complained. And it sounds like you're already ahead of my next suggestion to try moving those default statements to a lower init level.

Both variables created within store. (via default) and persistent. can be tweaked at runtime - since their structures are both saved to disk (store=save game files, persistent=common persistent file). The only difference being that a player starting a new game for a 2nd time would have the variables within the store reset to their defaults, whereas variables stored within persistent persist and are effectively linked to the game rather than the player.

As a suggestion, you might want to try grabbing any recent game which has been unofficially ported to Android by the66. I think he adds code which tints the text window background to match each character's color= parameter. Android APK files are just ZIP files and can be easily unpacked (and then maybe also run through UnRen). Maybe I imagined it, but if the code is there - it sounds very similar to what you are trying to achieve.
 
  • Like
Reactions: Me666

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,363
15,278
I'd like to know how to use matrixcolor TintMatrix(Color()) properly, preferably in a way that lets the user change the tint on the fly with e.g.
Ok, so it's a transform, therefore it just works like any other transforms :
Code:
default tintColor = "#0F0"   # Green

transform myTint:
    matrixcolor TintMatrix( tintColor )

image myImg:
    "images/someimage.png"
    matrixcolor TintMatrix( tintColor )

screen myScreen():
    add "images/someimage.png" at myTint

label start:
    scene someimage at myTint
    "pause"

    show someimage at myTint
    "pause"
    hide someimage

    scene myImg
    "pause"

    show someimage
    "pause"
    hide someimage
    scene

    show screen myScreen
This is five different way to use a transform.

But when you'll try this, it will not works, because there's a little something, never mentioned in the Matrixcolor page of the documentation, and also counter intuitive since im.matrix.tint works fine without it, while Ren'py 7.4.4 SDK don't use it by default. As said in the part of the documentation regarding the matrixcolor transform property, it require GL2 to works.

Therefore, I added this:
Code:
init python:
    config.gl2 = True
And now it works fine.


Side note: The transform accept the tint color as a variable (like in my example), but the effect of a value change of this color will not apply for images already seen.
You'll have to hide the image, then show it again, for the tint to change.



Edit: Oops, I initially messed the formatting, sorry
 
Last edited:
  • Like
Reactions: Me666

Me666

Newbie
Mar 14, 2018
96
214
Thank you very much :)

If I get to a solution that behaves the way I have in mind, I shall post the key bits here for anyone interested