How to add gradients to text

A place for Ren'Py tutorials and reusable Ren'Py code.
Forum rules
Do not post questions here!

This forum is for example code you want to show other people. Ren'Py questions should be asked in the Ren'Py Questions and Announcements forum.
Post Reply
Message
Author
User avatar
inkacorn
Newbie
Posts: 6
Joined: Thu Nov 30, 2023 3:44 pm
Projects: Married to a Fool, Mehkrow Meadows
Tumblr: inkacornn
itch: inkacorn
Contact:

How to add gradients to text

#1 Post by inkacorn »

Edit 3/14/23: Updated code and fixed text tag bug

Image
Image

This was heavily inspired by Wattson's Kinetic Text Tags which covers horizontal gradient text tags.

A drawback discovered with the original gradient tag was when using it on shorter words. With his suggestion to use shaders, this should fix that problem!

This will cover how to apply gradient shaders to character dialogue. Both specific text tags and overall dialogue.

Special thanks to udev3 on discord for helping with the code!


Create and Register Shaders

Code: Select all

init python:
    # Vertical gradient shader
    renpy.register_shader("vertical.gradient", variables="""
        uniform vec4 u_gradient_color_top;
        uniform vec4 u_gradient_color_bottom;
        uniform vec2 u_model_size;
        varying float v_gradient_done;
        attribute vec4 a_position;
    """, vertex_300="""
        v_gradient_done = a_position.y / u_model_size.y;
    """, fragment_300="""
        float gradient_done = v_gradient_done;
        gl_FragColor *= mix(u_gradient_color_top, u_gradient_color_bottom, gradient_done);
    """)

# Horizontal gradient shader
    renpy.register_shader("horizontal.gradient", variables="""
        uniform vec4 u_gradient_color_left;
        uniform vec4 u_gradient_color_right;
        uniform vec2 u_model_size;
        varying float v_gradient_done;
        attribute vec4 a_position;
    """, vertex_300="""
        v_gradient_done = a_position.x / u_model_size.x;
    """, fragment_300="""
        float gradient_done = v_gradient_done;
        gl_FragColor *= mix(u_gradient_color_left, u_gradient_color_right, gradient_done);
    """)
Shader Transforms*

Code: Select all

# Red to Blue Horizontal Gradient 
transform gradientRB:
    shader "horizontal.gradient"
    u_gradient_color_left (1.0, 0.0, 0.0, 1.0) # Red
    u_gradient_color_right (0.0, 0.0, 1.0, 1.0) # Blue

# White to Red Vertical Gradient 
transform gradientWR:
    shader "vertical.gradient"
    u_gradient_color_top (1.0, 1.0, 1.0, 1.0) # White
    u_gradient_color_bottom (1.0, 0.0, 0.0, 1.0) # Red


# We can repeat this process for multiple types of colors with the same shader
# Pink to Blue Horizontal Gradient 
transform gradientPB:
       shader "horizontal.gradient"
       u_gradient_color_left (0.84, 0.0, 0.44, 1.0) # Pink
       u_gradient_color_right (0.0, 0.0, 1.0, 1.0) # Blue
* A drawback with using shaders, (as far as I know) is that you will have to define the colors in each transform.

How to Apply as Text Tags

Code: Select all

#Creating the text tags
# BE SURE TO DOWNLOAD THE KINETIC TEXT TAGS FOR THE DISPTEXTSTYLE CLASS!!!

# This is Wattson's code!!!
init python:
    import random
    import math

    class DispTextStyle():
        custom_tags = ["sc"]
        accepted_tags = ["", "b", "s", "u", "i", "color", "alpha", "font",  "size", "outlinecolor", "plain", 'cps']
        custom_cancel_tags = ["/" + tag for tag in custom_tags]
        cancel_tags = ["/" + tag for tag in accepted_tags]
        def __init__(self):
            self.tags = {}

        # For setting style properties. Returns false if it accepted none of the tags
        def add_tags(self, char):
            tag, _, value = char.partition("=") # Separate the tag and its info
            # Add tag to dictionary if we accept it
            if tag in self.accepted_tags or tag in self.custom_tags:
                if value == "":
                    self.tags[tag] = True
                else:
                    self.tags[tag] = value
                return True
            # Remove mark tag as cleared if should no longer apply it
            if tag in self.cancel_tags or tag in self.custom_cancel_tags:
                tag = tag.replace("/", "")
                self.tags.pop(tag)
                return True
            return False # If we got any other tag, tell the function to let it pass

        # Applies all style properties to the string
        def apply_style(self, char):
            new_string = ""
            # Go through and apply all the tags
            new_string += self.start_tags()
            # Add the character in the middle
            new_string += char
            # Now close all the tags we opened
            new_string += self.end_tags()
            return new_string

        # Spits out start tags. Primarily used for SwapText
        def start_tags(self):
            new_string = ""
            # Go through the custom tags
            for tag in self.custom_tags:
                if tag in self.tags:
                    if self.tags[tag] == True:
                        new_string += "{" + tag + "}"
                    else:
                        new_string += "{" + tag + "=" +self.tags[tag] + "}"
            # Go through the standard tags
            for tag in self.accepted_tags:
                if tag in self.tags:
                    if self.tags[tag] == True:
                        new_string += "{" + tag + "}"
                    else:
                        new_string += "{" + tag + "=" +self.tags[tag] + "}"
            return new_string

        def end_tags(self):
            new_string = ""
            reversed_cancels = [tag for tag in self.custom_cancel_tags]
            reversed_cancels.reverse()
            for tag in reversed_cancels:
                temp = tag.replace("/", "")
                if temp in self.tags:
                    new_string += "{" + tag + "}"
            return new_string


init python:
    # Red to Blue Horizontal Gradient
    def RBGradient_tag(tag, argument, contents):
        new_list = [ ]
        my_style = DispTextStyle()
        for kind,text in contents:
            if kind == renpy.TEXT_TEXT:
                char_text = Text(my_style.apply_style(text))
                char_disp = gradientRB(char_text)
                new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
            elif kind == renpy.TEXT_TAG:
                if not my_style.add_tags(text):
                    new_list.append((kind, text))
            else:
                new_list.append((kind,text))
        return new_list
        
    # White to Red Vertical Gradient
    def RWGradient_tag(tag, argument, contents):
        new_list = [ ]
        my_style = DispTextStyle()
        for kind,text in contents:
            if kind == renpy.TEXT_TEXT:
                for char in text:
                    char_text = Text(my_style.apply_style(char))
                    char_disp = gradientRW(char_text)
                    new_list.append((renpy.TEXT_DISPLAYABLE, char_disp))
            elif kind == renpy.TEXT_TAG:
                if not my_style.add_tags(text):
                    new_list.append((kind, text))
            else:
                new_list.append((kind,text))
        return new_list
        
    # You can change the names of each tag to whatever you want
    config.custom_text_tags["gradient"] = RBgradient_tag
    
    config.custom_text_tags["Vgradient"] = WRgradient_tag
    
# script.rpy
label start:
# ...
    ralsei "I am the {gradient}PRINCE OF DARKNESS{/gradient}."
    ralsei "Kris... I remember you're, {Vgradient}SNOWGRAVES{/Vgradient}."
How to Apply to Certain Characters

Code: Select all

#Wherever your characters are defined

define ralsei = Character("{gradient}Ralsei{/gradient}", what_prefix="{gradient}", what_suffix="{/gradient}")
How to Apply to All Dialogue/Names

Code: Select all

# screens.rpy

screen say(who, what):
    style_prefix "say"

    window:
        id "window"

        if who is not None:

            window:
                id "namebox"
                style "namebox"
                text who id "who" at gradientRW # Applies our Red to White Gradient to ALL names
                
        # Please note, by doing this, you CANNOT use gradient text tags 
        text what id "what" at gradientRB # Applies our Red to Blue Gradient to ALL dialogue
If y'all have any questions or find something wrong with my code, please let me know! Hope this helps <3
Also known as the crazy jester lady
ImageImageImage

Post Reply

Who is online

Users browsing this forum: Google [Bot]