Jump to content

Recommended Posts

Posted (edited)

Is there a way to give text a gradient effect? Similar to the game's drawGradientRect() Method

Would I have to use openGL methods to achieve this and if so which ones?

 

Edit: Kinda related but is there a way to set the opacity of multiple objects being drawn on the screen? Example, I have 4 strings of text and I want to set all of their opacity to 50%

 

 

Edited by -TheLittleGuy
  • Like 1
Posted

The drawGradientRect method uses the following trick to render a gradient: The top two vertices of the quad are in one color, and the bottom two vertices are in another. Then, the shadeModel GL11.GL_SMOOTH is used, so that these colors are interpolated and create a gradient effect. To render a String, the drawString method calls the renderString method, which calls the renderStringAtPos method which ultimately calls the renderGlyph method, which calls the render method of the TexturedGlyph class. In that last render method, the color is set via the function parameters. If you created a custom TexturedGlyph that hat a render method with two colors as input, you could enable the above mentioned shadeModel to render a text with a gradient. It's a bit of work but seems definitely possible.

Just have a look at

net.minecraft.client.gui.fonts.TexturedGlyph::render

and

net.minecraftforge.fml.client.config.GuiUtils::drawGradientRect

PS: Since I'm currently working with 1.14, the class names (any maybe the function names) differ, but apart from that, everything I said should be applicable.

  • Like 1
  • Thanks 1
Posted
2 hours ago, deerangle said:

The drawGradientRect method uses the following trick to render a gradient: The top two vertices of the quad are in one color, and the bottom two vertices are in another. Then, the shadeModel GL11.GL_SMOOTH is used, so that these colors are interpolated and create a gradient effect. To render a String, the drawString method calls the renderString method, which calls the renderStringAtPos method which ultimately calls the renderGlyph method, which calls the render method of the TexturedGlyph class. In that last render method, the color is set via the function parameters. If you created a custom TexturedGlyph that hat a render method with two colors as input, you could enable the above mentioned shadeModel to render a text with a gradient. It's a bit of work but seems definitely possible.

Just have a look at


net.minecraft.client.gui.fonts.TexturedGlyph::render

and


net.minecraftforge.fml.client.config.GuiUtils::drawGradientRect

PS: Since I'm currently working with 1.14, the class names (any maybe the function names) differ, but apart from that, everything I said should be applicable.

It seems a bit different in 1.12.2. There doesnt seem to be a TexturedGlyph class.  After the renderStringAtPos method the method renderChar is called which then either calls renderDefaultChar or renderUnicodeChar

which is where the location of the actual glyphs are "cut out" from the font texture (default.png). The coloring of the text doesnt get set until the renderString method (§ codes excluded those seem to get set inside renderStringAtPos)

Posted

So after a little testing I came up with this (for 1.12.2):

I created a Subclass of FontRenderer called GradientFontRenderer. In this class, I override the method renderDefaultChar (you should probably override the unicode method too.) so that It uses the above mentioned shadeModel and has the correct vertex order. The code for this is the following, and creates a gradient from red to blue:

@Override
protected float renderDefaultChar(int ch, boolean italic) {
    float charXPos = ch % 16 * 8f;
    float charYPos = (ch / 16) * 8f;
    float italicOffset = italic ? 1f : 0f;
    bindTexture(this.locationFontTexture);
    int charWidth = this.charWidth[ch];
    float width = (float)charWidth - 0.01F;

    GlStateManager.shadeModel(GL11.GL_SMOOTH);
    GlStateManager.glBegin(GL11.GL_QUADS);

    GlStateManager.color(1.0f, 0.0f, 0.0f);
    GlStateManager.glTexCoord2f(charXPos / 128.0F, charYPos / 128.0F); // 0 0
    GlStateManager.glVertex3f(this.posX + italicOffset, this.posY, 0.0F);

    GlStateManager.color(0.0f, 0.0f, 1.0f);
    GlStateManager.glTexCoord2f(charXPos / 128.0F, (charYPos + 7.99F) / 128.0F); // 0 1
    GlStateManager.glVertex3f(this.posX - italicOffset, this.posY + 7.99F, 0.0F);

    GlStateManager.color(0.0f, 0.0f, 1.0f);
    GlStateManager.glTexCoord2f((charXPos + width - 1.0F) / 128.0F, (charYPos + 7.99F) / 128.0F); // 1 1
    GlStateManager.glVertex3f(this.posX + width - 1.0F - italicOffset, this.posY + 7.99F, 0.0F);

    GlStateManager.color(1.0f, 0.0f, 0.0f);
    GlStateManager.glTexCoord2f((charXPos + width - 1.0F) / 128.0F, charYPos / 128.0F); // 1 0
    GlStateManager.glVertex3f(this.posX + width - 1.0F + italicOffset, this.posY, 0.0F);

    GlStateManager.glEnd();
    GlStateManager.shadeModel(GL11.GL_FLAT);
    return (float)charWidth;
}

I'm sure you can expand on this code by adding parameters and auxiliary functions to control the gradient colors to your desire.

For instantiating the GradientFontRenderer, I just created an Instance in the constructor of my Gui class. You also need to call onResourceManagerReload to load the texture for the fontrenderer and all. This is the GuiScreen code:

public class TestGuiScreen extends GuiScreen {

    private GradientFontRenderer gradientFontRenderer;

    public TestGuiScreen() {
        Minecraft mc = Minecraft.getMinecraft();
        gradientFontRenderer = new GradientFontRenderer(mc.gameSettings, new ResourceLocation("textures/font/ascii.png"), mc.renderEngine, false);
        gradientFontRenderer.onResourceManagerReload(null);
    }

    public void render() {
        ScaledResolution res = new ScaledResolution(Minecraft.getMinecraft());
        this.width = res.getScaledWidth();
        this.height = res.getScaledHeight();
        int x = (this.width) / 2;
        int y = (this.height) / 2;
        drawHelloTextWithGradient(x, y-16, 0xFFFFFFFF, 0xFFFF0000);
    }

    private void drawHelloTextWithGradient(int x, int y, int topColor, int bottomColor) {
        drawRect(x-20, y-8, x+20, y+8, 0x7F000000);
        drawCenteredGradientString(gradientFontRenderer, "hello", x, y-4, topColor, bottomColor);
    }

    public void drawCenteredGradientString(GradientFontRenderer fontRendererIn, String text, int x, int y, int color, int colorBottom)
    {
        fontRendererIn.drawString(text, x - fontRendererIn.getStringWidth(text) / 2, y, color);
    }

}

Here is a screenshot of how it looks.

2019-11-23_23_32_17.png.48402de27839505a1f207babf16feb79.png

I hope this was helpful. If you have any further questions, just ask :D

  • Thanks 1
Posted

So I decided to make all the functions to render with any gradient, and here's the code (it only supports normal text, no italics, no bold, no formatting or coloring, no unicode, but you can add that with some extra work if you need it):

public class GradientFontRenderer extends FontRenderer {

    public GradientFontRenderer(GameSettings gameSettingsIn, ResourceLocation location, TextureManager textureManagerIn, boolean unicode) {
        super(gameSettingsIn, location, textureManagerIn, unicode);
    }

    public int drawGradientString(String text, float x, float y, int topColor, int bottomColor, boolean dropShadow)
    {
        enableAlpha();
        int i;

        if (dropShadow)
        {
            i = this.renderGradientString(text, x + 1.0F, y + 1.0F, topColor, bottomColor, true);
            i = Math.max(i, this.renderGradientString(text, x, y, topColor, bottomColor, false));
        }
        else
        {
            i = this.renderGradientString(text, x, y, topColor, bottomColor, false);
        }

        return i;
    }

    private int renderGradientString(String text, float x, float y, int topColor, int bottomColor, boolean dropShadow)
    {
        if (text == null)
        {
            return 0;
        }
        else
        {

            if ((topColor & -67108864) == 0)
            {
                topColor |= -16777216;
            }

            if ((bottomColor & -67108864) == 0)
            {
                bottomColor |= -16777216;
            }

            if (dropShadow)
            {
                topColor = (topColor & 16579836) >> 2 | topColor & -16777216;
                bottomColor = (bottomColor & 16579836) >> 2 | bottomColor & -16777216;
            }

            this.posX = x;
            this.posY = y;
            this.renderGradientStringAtPos(text, dropShadow, topColor, bottomColor);
            return (int)this.posX;
        }
    }

    private void renderGradientStringAtPos(String text, boolean shadow, int topColor, int bottomColor) {
        for (int i = 0; i < text.length(); ++i) {
            char c0 = text.charAt(i);
            int j = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000".indexOf(c0);

            float f1 = j == -1 ? 0.5f : 1f;
            boolean flag = (c0 == 0 || j == -1) && shadow;

            if (flag) {
                this.posX -= f1;
                this.posY -= f1;
            }

            float f = this.renderGradientChar(c0, topColor, bottomColor);

            if (flag) {
                this.posX += f1;
                this.posY += f1;
            }

            doDraw(f);
        }
    }

    private float renderGradientChar(char ch, int topColor, int bottomColor) {
        if (ch == 160) return 4.0F; // forge: display nbsp as space. MC-2595
        if (ch == ' ') {
            return 4.0F;
        } else {
            int i = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000".indexOf(ch);
            if (i != -1) {
                return this.renderGradientDefaultChar(i, topColor, bottomColor);
            } else {
                throw new RuntimeException("Unrecognized char: " + ch);
            }
        }
    }

    protected float renderGradientDefaultChar(int ch, int topColor, int bottomColor) {
        float topAlpha = ((topColor >> 24) & 0xFF) / 255f;
        float topRed = ((topColor >> 16) & 0xFF) / 255f;
        float topGreen = ((topColor >> 8) & 0xFF) / 255f;
        float topBlue = (topColor & 0xFF) / 255f;

        float bottomAlpha = ((bottomColor >> 24) & 0xFF) / 255f;
        float bottomRed = ((bottomColor >> 16) & 0xFF) / 255f;
        float bottomGreen = ((bottomColor >> 8) & 0xFF) / 255f;
        float bottomBlue = (bottomColor & 0xFF) / 255f;

        float charXPos = ch % 16 * 8f;
        float charYPos = (ch / 16) * 8f;
        bindTexture(this.locationFontTexture);
        int charWidth = this.charWidth[ch];
        float width = (float) charWidth - 0.01F;

        GlStateManager.shadeModel(GL11.GL_SMOOTH);
        GlStateManager.glBegin(GL11.GL_QUADS);

        GlStateManager.color(topRed, topGreen, topBlue, topAlpha);
        GlStateManager.glTexCoord2f(charXPos / 128.0F, charYPos / 128.0F); // 0 0
        GlStateManager.glVertex3f(this.posX, this.posY, 0.0F);

        GlStateManager.color(bottomRed, bottomGreen, bottomBlue, bottomAlpha);
        GlStateManager.glTexCoord2f(charXPos / 128.0F, (charYPos + 7.99F) / 128.0F); // 0 1
        GlStateManager.glVertex3f(this.posX, this.posY + 7.99F, 0.0F);

        GlStateManager.color(bottomRed, bottomGreen, bottomBlue, bottomAlpha);
        GlStateManager.glTexCoord2f((charXPos + width - 1.0F) / 128.0F, (charYPos + 7.99F) / 128.0F); // 1 1
        GlStateManager.glVertex3f(this.posX + width - 1.0F, this.posY + 7.99F, 0.0F);

        GlStateManager.color(topRed, topGreen, topBlue, topAlpha);
        GlStateManager.glTexCoord2f((charXPos + width - 1.0F) / 128.0F, charYPos / 128.0F); // 1 0
        GlStateManager.glVertex3f(this.posX + width - 1.0F, this.posY, 0.0F);

        GlStateManager.glEnd();
        GlStateManager.shadeModel(GL11.GL_FLAT);
        return (float) charWidth;
    }
}

Then change this code from above to the following:

public void drawCenteredGradientString(GradientFontRenderer fontRendererIn, String text, int x, int y, int color, int colorBottom)
{
    fontRendererIn.drawGradientString(text, x - fontRendererIn.getStringWidth(text) / 2, y, color, colorBottom, true);
}

And it should work.

Posted
2 hours ago, deerangle said:

So I decided to make all the functions to render with any gradient, and here's the code (it only supports normal text, no italics, no bold, no formatting or coloring, no unicode, but you can add that with some extra work if you need it):


public class GradientFontRenderer extends FontRenderer {

    public GradientFontRenderer(GameSettings gameSettingsIn, ResourceLocation location, TextureManager textureManagerIn, boolean unicode) {
        super(gameSettingsIn, location, textureManagerIn, unicode);
    }

    public int drawGradientString(String text, float x, float y, int topColor, int bottomColor, boolean dropShadow)
    {
        enableAlpha();
        int i;

        if (dropShadow)
        {
            i = this.renderGradientString(text, x + 1.0F, y + 1.0F, topColor, bottomColor, true);
            i = Math.max(i, this.renderGradientString(text, x, y, topColor, bottomColor, false));
        }
        else
        {
            i = this.renderGradientString(text, x, y, topColor, bottomColor, false);
        }

        return i;
    }

    private int renderGradientString(String text, float x, float y, int topColor, int bottomColor, boolean dropShadow)
    {
        if (text == null)
        {
            return 0;
        }
        else
        {

            if ((topColor & -67108864) == 0)
            {
                topColor |= -16777216;
            }

            if ((bottomColor & -67108864) == 0)
            {
                bottomColor |= -16777216;
            }

            if (dropShadow)
            {
                topColor = (topColor & 16579836) >> 2 | topColor & -16777216;
                bottomColor = (bottomColor & 16579836) >> 2 | bottomColor & -16777216;
            }

            this.posX = x;
            this.posY = y;
            this.renderGradientStringAtPos(text, dropShadow, topColor, bottomColor);
            return (int)this.posX;
        }
    }

    private void renderGradientStringAtPos(String text, boolean shadow, int topColor, int bottomColor) {
        for (int i = 0; i < text.length(); ++i) {
            char c0 = text.charAt(i);
            int j = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000".indexOf(c0);

            float f1 = j == -1 ? 0.5f : 1f;
            boolean flag = (c0 == 0 || j == -1) && shadow;

            if (flag) {
                this.posX -= f1;
                this.posY -= f1;
            }

            float f = this.renderGradientChar(c0, topColor, bottomColor);

            if (flag) {
                this.posX += f1;
                this.posY += f1;
            }

            doDraw(f);
        }
    }

    private float renderGradientChar(char ch, int topColor, int bottomColor) {
        if (ch == 160) return 4.0F; // forge: display nbsp as space. MC-2595
        if (ch == ' ') {
            return 4.0F;
        } else {
            int i = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000".indexOf(ch);
            if (i != -1) {
                return this.renderGradientDefaultChar(i, topColor, bottomColor);
            } else {
                throw new RuntimeException("Unrecognized char: " + ch);
            }
        }
    }

    protected float renderGradientDefaultChar(int ch, int topColor, int bottomColor) {
        float topAlpha = ((topColor >> 24) & 0xFF) / 255f;
        float topRed = ((topColor >> 16) & 0xFF) / 255f;
        float topGreen = ((topColor >> 8) & 0xFF) / 255f;
        float topBlue = (topColor & 0xFF) / 255f;

        float bottomAlpha = ((bottomColor >> 24) & 0xFF) / 255f;
        float bottomRed = ((bottomColor >> 16) & 0xFF) / 255f;
        float bottomGreen = ((bottomColor >> 8) & 0xFF) / 255f;
        float bottomBlue = (bottomColor & 0xFF) / 255f;

        float charXPos = ch % 16 * 8f;
        float charYPos = (ch / 16) * 8f;
        bindTexture(this.locationFontTexture);
        int charWidth = this.charWidth[ch];
        float width = (float) charWidth - 0.01F;

        GlStateManager.shadeModel(GL11.GL_SMOOTH);
        GlStateManager.glBegin(GL11.GL_QUADS);

        GlStateManager.color(topRed, topGreen, topBlue, topAlpha);
        GlStateManager.glTexCoord2f(charXPos / 128.0F, charYPos / 128.0F); // 0 0
        GlStateManager.glVertex3f(this.posX, this.posY, 0.0F);

        GlStateManager.color(bottomRed, bottomGreen, bottomBlue, bottomAlpha);
        GlStateManager.glTexCoord2f(charXPos / 128.0F, (charYPos + 7.99F) / 128.0F); // 0 1
        GlStateManager.glVertex3f(this.posX, this.posY + 7.99F, 0.0F);

        GlStateManager.color(bottomRed, bottomGreen, bottomBlue, bottomAlpha);
        GlStateManager.glTexCoord2f((charXPos + width - 1.0F) / 128.0F, (charYPos + 7.99F) / 128.0F); // 1 1
        GlStateManager.glVertex3f(this.posX + width - 1.0F, this.posY + 7.99F, 0.0F);

        GlStateManager.color(topRed, topGreen, topBlue, topAlpha);
        GlStateManager.glTexCoord2f((charXPos + width - 1.0F) / 128.0F, charYPos / 128.0F); // 1 0
        GlStateManager.glVertex3f(this.posX + width - 1.0F, this.posY, 0.0F);

        GlStateManager.glEnd();
        GlStateManager.shadeModel(GL11.GL_FLAT);
        return (float) charWidth;
    }
}

Then change this code from above to the following:


public void drawCenteredGradientString(GradientFontRenderer fontRendererIn, String text, int x, int y, int color, int colorBottom)
{
    fontRendererIn.drawGradientString(text, x - fontRendererIn.getStringWidth(text) / 2, y, color, colorBottom, true);
}

And it should work.

I actually do have a question: I changed the gradient to start from the left instead of the top however, the current method applies the gradient effect to the individual character. What would have to be changed in order to have the gradient be applied to the entire string? Where would the GL Functions go in that case? Where they are currently or would it have to go after the chars are "assembled" into the string? Ex: i have the string "Test String"  the start color is Green and the end color is Red, the first letter will start green and will fade to red by the time it gets to the last letter.

Posted

You would have to color different vertices differently based on the length they are through the string to have that type of gradient. You would need extra code to store the length of the string that you’re drawing and to use that data in the render char method

  • Like 1

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted

I've added a horizontal parameter to every gradient text function so that you can make horizontal and vertical gradients. This is the updated code:

public class GradientFontRenderer extends FontRenderer {

    private static final String charmap = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";

    public GradientFontRenderer(GameSettings gameSettingsIn, ResourceLocation location, TextureManager textureManagerIn, boolean unicode) {
        super(gameSettingsIn, location, textureManagerIn, unicode);
    }

    public int drawGradientString(String text, float x, float y, int topColor, int bottomColor, boolean dropShadow, boolean horizontal) {
        enableAlpha();
        int i;

        if (dropShadow) {
            i = this.renderGradientString(text, x + 1.0F, y + 1.0F, topColor, bottomColor, true, horizontal);
            i = Math.max(i, this.renderGradientString(text, x, y, topColor, bottomColor, false, horizontal));
        } else {
            i = this.renderGradientString(text, x, y, topColor, bottomColor, false, horizontal);
        }

        return i;
    }

    private int renderGradientString(String text, float x, float y, int startColor, int endColor, boolean dropShadow, boolean horizontal) {
        if (text == null) {
            return 0;
        } else {

            if ((startColor & -67108864) == 0) {
                startColor |= -16777216;
            }

            if ((endColor & -67108864) == 0) {
                endColor |= -16777216;
            }

            if (dropShadow) {
                startColor = (startColor & 16579836) >> 2 | startColor & -16777216;
                endColor = (endColor & 16579836) >> 2 | endColor & -16777216;
            }

            this.posX = x;
            this.posY = y;
            this.renderGradientStringAtPos(text, dropShadow, startColor, endColor, horizontal);
            return (int) this.posX;
        }
    }

    private void renderGradientStringAtPos(String text, boolean shadow, int startColor, int endColor, boolean horizontal) {
        float totalWidth = this.getStringWidth(text);
        float currentCountWidth = 0;

        for (int i = 0; i < text.length(); ++i) {
            char c0 = text.charAt(i);
            int j = charmap.indexOf(c0);

            float f1 = j == -1 ? 0.5f : 1f;
            boolean flag = (c0 == 0 || j == -1) && shadow;

            if (flag) {
                this.posX -= f1;
                this.posY -= f1;
            }

            float f;
            if (horizontal) {
                float nextCharWidth = this.getCharWidth(c0);
                float firstMix = currentCountWidth / totalWidth;
                float lastMix = (currentCountWidth + nextCharWidth) / totalWidth;
                int firstColor = colorMix(startColor, endColor, firstMix);
                int lastColor = colorMix(startColor, endColor, lastMix);
                f = this.renderGradientChar(c0, firstColor, lastColor, true);
                currentCountWidth += f;
            } else {
                f = this.renderGradientChar(c0, startColor, endColor, false);
            }

            if (flag) {
                this.posX += f1;
                this.posY += f1;
            }

            doDraw(f);
        }
    }

    private int colorMix(int startColor, int endColor, float mix) {
        float startAlpha = ((startColor >> 24) & 0xFF) / 255f;
        float startRed = ((startColor >> 16) & 0xFF) / 255f;
        float startGreen = ((startColor >> 8) & 0xFF) / 255f;
        float startBlue = (startColor & 0xFF) / 255f;

        float endAlpha = ((endColor >> 24) & 0xFF) / 255f;
        float endRed = ((endColor >> 16) & 0xFF) / 255f;
        float endGreen = ((endColor >> 8) & 0xFF) / 255f;
        float endBlue = (endColor & 0xFF) / 255f;

        int mixAlpha = (int) (((1 - mix) * startAlpha + mix * endAlpha) * 255);
        int mixRed = (int) (((1 - mix) * startRed + mix * endRed) * 255);
        int mixGreen = (int) (((1 - mix) * startGreen + mix * endGreen) * 255);
        int mixBlue = (int) (((1 - mix) * startBlue + mix * endBlue) * 255);

        return (mixAlpha << 24) | (mixRed << 16) | (mixGreen << 8) | mixBlue;
    }

    private float renderGradientChar(char ch, int startColor, int endColor, boolean horizontal) {
        if (ch == 160) return 4.0F; // forge: display nbsp as space. MC-2595
        if (ch == ' ') {
            return 4.0F;
        } else {
            int i = charmap.indexOf(ch);
            if (i != -1) {
                return this.renderGradientDefaultChar(i, startColor, endColor, horizontal);
            } else {
                throw new RuntimeException("Unrecognized char: " + ch);
            }
        }
    }

    protected float renderGradientDefaultChar(int ch, int startColor, int endColor, boolean horizontal) {
        float startAlpha = ((startColor >> 24) & 0xFF) / 255f;
        float startRed = ((startColor >> 16) & 0xFF) / 255f;
        float startGreen = ((startColor >> 8) & 0xFF) / 255f;
        float startBlue = (startColor & 0xFF) / 255f;

        float endAlpha = ((endColor >> 24) & 0xFF) / 255f;
        float endRed = ((endColor >> 16) & 0xFF) / 255f;
        float endGreen = ((endColor >> 8) & 0xFF) / 255f;
        float endBlue = (endColor & 0xFF) / 255f;

        float charXPos = ch % 16 * 8f;
        float charYPos = (ch / 16) * 8f;
        bindTexture(this.locationFontTexture);
        int charWidth = this.charWidth[ch];
        float width = (float) charWidth - 0.01F;

        GlStateManager.shadeModel(GL11.GL_SMOOTH);
        GlStateManager.glBegin(GL11.GL_QUADS);

        GlStateManager.color(startRed, startGreen, startBlue, startAlpha);
        GlStateManager.glTexCoord2f(charXPos / 128.0F, charYPos / 128.0F); // 0 0
        GlStateManager.glVertex3f(this.posX, this.posY, 0.0F);

        if (horizontal) {
            GlStateManager.color(startRed, startGreen, startBlue, startAlpha);
        } else {
            GlStateManager.color(endRed, endGreen, endBlue, endAlpha);
        }
        GlStateManager.glTexCoord2f(charXPos / 128.0F, (charYPos + 7.99F) / 128.0F); // 0 1
        GlStateManager.glVertex3f(this.posX, this.posY + 7.99F, 0.0F);

        GlStateManager.color(endRed, endGreen, endBlue, endAlpha);
        GlStateManager.glTexCoord2f((charXPos + width - 1.0F) / 128.0F, (charYPos + 7.99F) / 128.0F); // 1 1
        GlStateManager.glVertex3f(this.posX + width - 1.0F, this.posY + 7.99F, 0.0F);

        if (horizontal) {
            GlStateManager.color(endRed, endGreen, endBlue, endAlpha);
        } else {
            GlStateManager.color(startRed, startGreen, startBlue, startAlpha);
        }
        GlStateManager.glTexCoord2f((charXPos + width - 1.0F) / 128.0F, charYPos / 128.0F); // 1 0
        GlStateManager.glVertex3f(this.posX + width - 1.0F, this.posY, 0.0F);

        GlStateManager.glEnd();
        GlStateManager.shadeModel(GL11.GL_FLAT);
        return (float) charWidth;
    }
}

2019-11-24_10_23_33.png.431785ef4179a820f30edd88bbea722c.png

Pretty basic. It just linearly interpolates the colors for each char so that the gradient colors of each char match up.

Posted

You probably want to use hex instead of decimal for your color codes and masks.

-67108864 -> 0xFC000000

-16777216 -> 0xFF000000

16579836 -> 0xFCFCFC

It makes it a lot easier to understand as colours are packed 0x(AA)RRGGBBx

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted
1 minute ago, Cadiboo said:

You probably want to use hex instead of decimal for your color codes and masks.

-67108864 -> 0xFC000000

-16777216 -> 0xFF000000

16579836 -> 0xFCFCFC

It makes it a lot easier to understand as colours are packed 0x(AA)RRGGBBx

Since I copied most of the code for the GradientFontRenderer from the original FontRenderer, which is decompiled and therefore doesn't use hex literals, the color values are in decimal.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • When I first heard about Bitcoin back in 2018, I was skeptical. The idea of a decentralized, digital currency seemed too good to be true. But I was intrigued as I learned more about the technology behind it and its potential. I started small, investing just a few hundred dollars, dipping my toes into the cryptocurrency waters. At first, it was exhilarating to watch the value of my investment grow exponentially. I felt like I was part of the future, an early adopter of this revolutionary new asset. But that euphoria was short-lived. One day, I logged into my digital wallet only to find it empty - my Bitcoin had vanished without a trace. It turned out that the online exchange I had trusted had been hacked, and my funds were stolen. I was devastated, both financially and emotionally. All the potential I had seen in Bitcoin was tainted by the harsh reality that with decentralization came a lack of regulation and oversight. My hard-earned money was gone, lost to the ether of the digital world. This experience taught me a painful lesson about the price of trust in the uncharted territory of cryptocurrency. While the technology holds incredible promise, the risks can be catastrophic if you don't approach it with extreme caution. My Bitcoin investment gamble had failed, and I was left to pick up the pieces, wiser but poorer for having placed my faith in the wrong hands. My sincere appreciation goes to MUYERN TRUST HACKER. You are my hero in recovering my lost funds. Send a direct m a i l ( muyerntrusted ( @ ) mail-me ( . )c o m ) or message on whats app : + 1 ( 4-4-0 ) ( 3 -3 -5 ) ( 0-2-0-5 )
    • You could try posting a log (if there is no log at all, it may be the launcher you are using, the FAQ may have info on how to enable the log) as described in the FAQ, however this will probably need to be reported to/remedied by the mod author.
    • So me and a couple of friends are playing with a shitpost mod pack and one of the mods in the pack is corail tombstone and for some reason there is a problem with it, where on death to fire the player will get kicked out of the server and the tombstone will not spawn basically deleting an entire inventory, it doesn't matter what type of fire it is, whether it's from vanilla fire/lava, or from modded fire like ice&fire/lycanites and it's common enough to where everyone on the server has experienced at least once or twice and it doesn't give any crash log. a solution to this would be much appreciated thank you!
    • It is 1.12.2 - I have no idea if there is a 1.12 pack
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.