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

    • that happens every time I enter a new dimension.
    • This is the last line before the crash: [ebwizardry]: Synchronising spell emitters for PixelTraveler But I have no idea what this means
    • What in particular? I barely used that mod this time around, and it's never been a problem in the past.
    • Im trying to build my mod using shade since i use the luaj library however i keep getting this error Reason: Task ':reobfJar' uses this output of task ':shadowJar' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed. So i try adding reobfJar.dependsOn shadowJar  Could not get unknown property 'reobfJar' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler. my gradle file plugins { id 'eclipse' id 'idea' id 'maven-publish' id 'net.minecraftforge.gradle' version '[6.0,6.2)' id 'com.github.johnrengelman.shadow' version '7.1.2' id 'org.spongepowered.mixin' version '0.7.+' } apply plugin: 'net.minecraftforge.gradle' apply plugin: 'org.spongepowered.mixin' apply plugin: 'com.github.johnrengelman.shadow' version = mod_version group = mod_group_id base { archivesName = mod_id } // Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17. java.toolchain.languageVersion = JavaLanguageVersion.of(17) //jarJar.enable() println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" minecraft { mappings channel: mapping_channel, version: mapping_version copyIdeResources = true runs { configureEach { workingDirectory project.file('run') property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' arg "-mixin.config=derp.mixin.json" mods { "${mod_id}" { source sourceSets.main } } } client { // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. property 'forge.enabledGameTestNamespaces', mod_id } server { property 'forge.enabledGameTestNamespaces', mod_id args '--nogui' } gameTestServer { property 'forge.enabledGameTestNamespaces', mod_id } data { workingDirectory project.file('run-data') args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') } } } sourceSets.main.resources { srcDir 'src/generated/resources' } repositories { flatDir { dirs './libs' } maven { url = "https://jitpack.io" } } configurations { shade implementation.extendsFrom shade } dependencies { minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" implementation 'org.luaj:luaj-jse-3.0.2' implementation fg.deobf("com.github.Virtuoel:Pehkui:${pehkui_version}") annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' minecraftLibrary 'luaj:luaj-jse:3.0.2' shade 'luaj:luaj-jse:3.0.2' } // Example for how to get properties into the manifest for reading at runtime. tasks.named('jar', Jar).configure { manifest { attributes([ 'Specification-Title' : mod_id, 'Specification-Vendor' : mod_authors, 'Specification-Version' : '1', // We are version 1 of ourselves 'Implementation-Title' : project.name, 'Implementation-Version' : project.jar.archiveVersion, 'Implementation-Vendor' : mod_authors, 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), "TweakClass" : "org.spongepowered.asm.launch.MixinTweaker", "TweakOrder" : 0, "MixinConfigs" : "derp.mixin.json" ]) } rename 'mixin.refmap.json', 'derp.mixin-refmap.json' } shadowJar { archiveClassifier = '' configurations = [project.configurations.shade] finalizedBy 'reobfShadowJar' } assemble.dependsOn shadowJar reobf { re shadowJar {} } publishing { publications { mavenJava(MavenPublication) { artifact jar } } repositories { maven { url "file://${project.projectDir}/mcmodsrepo" } } } my entire project:https://github.com/kevin051606/DERP-Mod/tree/Derp-1.0-1.20
  • Topics

×
×
  • Create New...

Important Information

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