Skip to main content
Bumped by Community user
Tweeted twitter.com/StackGameDev/status/792764582553128960
Bumped by Community user
Bumped by Community user
Bumped by Community user
added 198 characters in body
Source Link
@Override
public void drawTextBox() {
    if (this.getVisible()) {
        
        
        // trimmed: create x and y variables & draw border/background of textfield
        //     border/background drawn with GlStateManager and WorldRenderer
        
        
        // stencil code I found online
        glClear(GL_DEPTH_BUFFER_BIT);
        glEnable(GL_STENCIL_TEST);
        glColorMask(false, false, false, false);
        glDepthMask(false);
        glStencilFunc(GL_NEVER, 1, 0xFF);
        glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);  // draw 1s on test fail (always)
    
        // draw stencil pattern
        glStencilMask(0xFF);
        glClear(GL_STENCIL_BUFFER_BIT);  // needs mask=0xFF
        
        // X1 is just inside the left border
        // X4 is just inside the right border
        // Y1 is just inside the top border
        // Y4 is just inside the bottom border
        glBegin(GL_QUADS);
        glVertex3f(x4, y4, 0.0f);
        glVertex3f(x4, y1, 0.0f);
        glVertex3f(x1, y1, 0.0f);
        glVertex3f(x1, y4, 0.0f);
        glEnd();
    
        glColorMask(true, true, true, true);
        glDepthMask(true);
        glStencilMask(0x00);
        // draw where stencil's value is 0
        glStencilFunc(GL_EQUAL, 0, 0xFF);
        /* (nothing to draw) */
        // draw only where stencil's value is 1
        glStencilFunc(GL_EQUAL, 1, 0xFF);
        
        //offset drawing location of text
        GlStateManager.translate(-colViewOffset, -lineViewOffset * 10, 0.0);
        
        // main drawtext
        int xOff = hShadow ? 10 : 0;
        for (int lin = lineViewOffset; lin < lineViewOffset + height / 10 && lin < lines.size(); lin++) {
            fontRenderer.drawString(lines.get(lin), x, y + (lin) * 10, getEnabled() ? 0xE0E0E0 : 0x707070);
        }
        
        // draw text under vertical shadows
        if (vShadow) {
            if (lineViewOffset - 1 >= 0) {
                fontRenderer.drawString(lines.get(lineViewOffset - 1), x, y + lineViewOffset * 10 - 10, getEnabled() ? 0xE0E0E0 : 0x707070);
            }
            if (lineViewOffset + height / 10 < lines.size()) {
                fontRenderer.drawString(lines.get(lineViewOffset + height / 10), x, y + height + lineViewOffset * 10, getEnabled() ? 0xE0E0E0 : 0x707070);
            }
        }
        
        
        // trimmed: draw cursor
        
        
        GlStateManager.translate(colViewOffset, lineViewOffset * 10, 0.0);
        
        // disable stencils
        glDisable(GL_STENCIL_TEST);
        
        
        // trimmed: draw bordershadows
        //     bordershadows drawn with GlStateManager and WorldRenderer
    }
}
@Override
public void drawTextBox() {
    if (this.getVisible()) {
        
        
        // trimmed: create x and y variables & draw border/background of textfield
        //     border/background drawn with GlStateManager and WorldRenderer
        
        
        // stencil code I found online
        glClear(GL_DEPTH_BUFFER_BIT);
        glEnable(GL_STENCIL_TEST);
        glColorMask(false, false, false, false);
        glDepthMask(false);
        glStencilFunc(GL_NEVER, 1, 0xFF);
        glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);  // draw 1s on test fail (always)
    
        // draw stencil pattern
        glStencilMask(0xFF);
        glClear(GL_STENCIL_BUFFER_BIT);  // needs mask=0xFF
        
        glBegin(GL_QUADS);
        glVertex3f(x4, y4, 0.0f);
        glVertex3f(x4, y1, 0.0f);
        glVertex3f(x1, y1, 0.0f);
        glVertex3f(x1, y4, 0.0f);
        glEnd();
    
        glColorMask(true, true, true, true);
        glDepthMask(true);
        glStencilMask(0x00);
        // draw where stencil's value is 0
        glStencilFunc(GL_EQUAL, 0, 0xFF);
        /* (nothing to draw) */
        // draw only where stencil's value is 1
        glStencilFunc(GL_EQUAL, 1, 0xFF);
        
        //offset drawing location of text
        GlStateManager.translate(-colViewOffset, -lineViewOffset * 10, 0.0);
        
        // main drawtext
        int xOff = hShadow ? 10 : 0;
        for (int lin = lineViewOffset; lin < lineViewOffset + height / 10 && lin < lines.size(); lin++) {
            fontRenderer.drawString(lines.get(lin), x, y + (lin) * 10, getEnabled() ? 0xE0E0E0 : 0x707070);
        }
        
        // draw text under vertical shadows
        if (vShadow) {
            if (lineViewOffset - 1 >= 0) {
                fontRenderer.drawString(lines.get(lineViewOffset - 1), x, y + lineViewOffset * 10 - 10, getEnabled() ? 0xE0E0E0 : 0x707070);
            }
            if (lineViewOffset + height / 10 < lines.size()) {
                fontRenderer.drawString(lines.get(lineViewOffset + height / 10), x, y + height + lineViewOffset * 10, getEnabled() ? 0xE0E0E0 : 0x707070);
            }
        }
        
        
        // trimmed: draw cursor
        
        
        GlStateManager.translate(colViewOffset, lineViewOffset * 10, 0.0);
        
        // disable stencils
        glDisable(GL_STENCIL_TEST);
        
        
        // trimmed: draw bordershadows
        //     bordershadows drawn with GlStateManager and WorldRenderer
    }
}
@Override
public void drawTextBox() {
    if (this.getVisible()) {
        
        
        // trimmed: create x and y variables & draw border/background of textfield
        //     border/background drawn with GlStateManager and WorldRenderer
        
        
        // stencil code I found online
        glClear(GL_DEPTH_BUFFER_BIT);
        glEnable(GL_STENCIL_TEST);
        glColorMask(false, false, false, false);
        glDepthMask(false);
        glStencilFunc(GL_NEVER, 1, 0xFF);
        glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);  // draw 1s on test fail (always)
    
        // draw stencil pattern
        glStencilMask(0xFF);
        glClear(GL_STENCIL_BUFFER_BIT);  // needs mask=0xFF
        
        // X1 is just inside the left border
        // X4 is just inside the right border
        // Y1 is just inside the top border
        // Y4 is just inside the bottom border
        glBegin(GL_QUADS);
        glVertex3f(x4, y4, 0.0f);
        glVertex3f(x4, y1, 0.0f);
        glVertex3f(x1, y1, 0.0f);
        glVertex3f(x1, y4, 0.0f);
        glEnd();

        glColorMask(true, true, true, true);
        glDepthMask(true);
        glStencilMask(0x00);
        // draw where stencil's value is 0
        glStencilFunc(GL_EQUAL, 0, 0xFF);
        /* (nothing to draw) */
        // draw only where stencil's value is 1
        glStencilFunc(GL_EQUAL, 1, 0xFF);
        
        //offset drawing location of text
        GlStateManager.translate(-colViewOffset, -lineViewOffset * 10, 0.0);
        
        // main drawtext
        int xOff = hShadow ? 10 : 0;
        for (int lin = lineViewOffset; lin < lineViewOffset + height / 10 && lin < lines.size(); lin++) {
            fontRenderer.drawString(lines.get(lin), x, y + (lin) * 10, getEnabled() ? 0xE0E0E0 : 0x707070);
        }
        
        // draw text under vertical shadows
        if (vShadow) {
            if (lineViewOffset - 1 >= 0) {
                fontRenderer.drawString(lines.get(lineViewOffset - 1), x, y + lineViewOffset * 10 - 10, getEnabled() ? 0xE0E0E0 : 0x707070);
            }
            if (lineViewOffset + height / 10 < lines.size()) {
                fontRenderer.drawString(lines.get(lineViewOffset + height / 10), x, y + height + lineViewOffset * 10, getEnabled() ? 0xE0E0E0 : 0x707070);
            }
        }
        
        
        // trimmed: draw cursor
        
        
        GlStateManager.translate(colViewOffset, lineViewOffset * 10, 0.0);
        
        // disable stencils
        glDisable(GL_STENCIL_TEST);
        
        
        // trimmed: draw bordershadows
        //     bordershadows drawn with GlStateManager and WorldRenderer
    }
}
Source Link

Minecraft Modding - How do I use OpenGL stencil functions alongside the game's GlStateManager?

Note: I am using Minecraft Coder Pack 9.10 for game version 1.8.0 (official release).

I am trying to make a multiline text field similar to the game's original net.minecraft.client.gui.GuiTextField. I have a class extending GuiTextField and overriding almost all of the methods to provide multiline support. I have just about everything working the way it needs to except for rendering.

I want to render the text similarly to the swing JTextArea (where it sets a clip area then renders all the text) but I'm unsure how to do this, or if its even possible to do alongside the game's GlStateManager and WorldRenderer. After some googling I think what I'm looking for is OpenGL stencils. I made sure that the display is created with a pixel format that supports stencils (In net.minecraft.client.Minecraft I changed Display.create((new PixelFormat()).withDepthBits(24)); to Display.create((new PixelFormat()).withDepthBits(24).withStencilBits(8)); to make sure there is a stencil buffer), and have been playing around with a bit of code and so far I have gotten 2 results:

  1. All other buttons on my gui (which render after the textfield) render perfectly fine, just as they should. The text field and the dirt background drawn by GuiScreen.drawDefaultBackgroudn() are all blacked out even if the stencil rectangle I draw covers them completely.

  2. Everything renders just as it did before I had the stencil code.

I have a feeling that the direct calls to the GL class are conflicting with the game's render managers but with the highly obfuscated code in the render manager I have no clue. (I also know that the game's GlStateManager has inner classes called StencilState and StencilFunc, but after some Java Searches in eclipse I can only find variable declarations/instantiations, but the vars are never referenced).

Here is the code I have so far to render the text field (irrelevant code trimmed):

@Override
public void drawTextBox() {
    if (this.getVisible()) {
        
        
        // trimmed: create x and y variables & draw border/background of textfield
        //     border/background drawn with GlStateManager and WorldRenderer
        
        
        // stencil code I found online
        glClear(GL_DEPTH_BUFFER_BIT);
        glEnable(GL_STENCIL_TEST);
        glColorMask(false, false, false, false);
        glDepthMask(false);
        glStencilFunc(GL_NEVER, 1, 0xFF);
        glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);  // draw 1s on test fail (always)
    
        // draw stencil pattern
        glStencilMask(0xFF);
        glClear(GL_STENCIL_BUFFER_BIT);  // needs mask=0xFF
        
        glBegin(GL_QUADS);
        glVertex3f(x4, y4, 0.0f);
        glVertex3f(x4, y1, 0.0f);
        glVertex3f(x1, y1, 0.0f);
        glVertex3f(x1, y4, 0.0f);
        glEnd();
    
        glColorMask(true, true, true, true);
        glDepthMask(true);
        glStencilMask(0x00);
        // draw where stencil's value is 0
        glStencilFunc(GL_EQUAL, 0, 0xFF);
        /* (nothing to draw) */
        // draw only where stencil's value is 1
        glStencilFunc(GL_EQUAL, 1, 0xFF);
        
        //offset drawing location of text
        GlStateManager.translate(-colViewOffset, -lineViewOffset * 10, 0.0);
        
        // main drawtext
        int xOff = hShadow ? 10 : 0;
        for (int lin = lineViewOffset; lin < lineViewOffset + height / 10 && lin < lines.size(); lin++) {
            fontRenderer.drawString(lines.get(lin), x, y + (lin) * 10, getEnabled() ? 0xE0E0E0 : 0x707070);
        }
        
        // draw text under vertical shadows
        if (vShadow) {
            if (lineViewOffset - 1 >= 0) {
                fontRenderer.drawString(lines.get(lineViewOffset - 1), x, y + lineViewOffset * 10 - 10, getEnabled() ? 0xE0E0E0 : 0x707070);
            }
            if (lineViewOffset + height / 10 < lines.size()) {
                fontRenderer.drawString(lines.get(lineViewOffset + height / 10), x, y + height + lineViewOffset * 10, getEnabled() ? 0xE0E0E0 : 0x707070);
            }
        }
        
        
        // trimmed: draw cursor
        
        
        GlStateManager.translate(colViewOffset, lineViewOffset * 10, 0.0);
        
        // disable stencils
        glDisable(GL_STENCIL_TEST);
        
        
        // trimmed: draw bordershadows
        //     bordershadows drawn with GlStateManager and WorldRenderer
    }
}

With everything I have right now this is what I get:

The multiline text field

What can I do to my code/the games render code to only draw text inside the white/gray rectangle bordering the textfield?