# 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);
glStencilFunc(GL_NEVER, 1, 0xFF);
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);  // draw 1s on test fail (always)

// draw stencil pattern

// 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
glVertex3f(x4, y4, 0.0f);
glVertex3f(x4, y1, 0.0f);
glVertex3f(x1, y1, 0.0f);
glVertex3f(x1, y4, 0.0f);
glEnd();

// 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 (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);

//     bordershadows drawn with GlStateManager and WorldRenderer
}
}


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

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

• afaik glClear is affected by the stencil test. If func is gl_never will it ever pass? Ie does your clear have intended effect? Afaik the value put in stencil is set with glclearstencil, not glstencilfunc/glstencilop. – Andreas Apr 26 '16 at 16:15

Happy new years, this will solve your problem:

float x1 = //left bound
float x2 = //right bound
float y1 = //up bound
float y2 = //down bound
ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
x1 *= sr.getScaleFactor();
y1 *= sr.getScaleFactor();
x2 *= sr.getScaleFactor();
y2 *= sr.getScaleFactor();
float temp;
if (y1 > y2) {
temp = y2;
y2 = y1;
y1 = temp;
}
GL11.glScissor((int)x1, (int)(Display.getHeight()-y2), (int)(x2-x1), (int)(y2-y1));
GL11.glEnable(GL11.GL_SCISSOR_TEST);

//DRAW TEXT THAT NEEDS TO BE CLIPPED OUTSIDE THE ABOVE SPECIFIED AREA

GL11.glDisable(GL11.GL_SCISSOR_TEST);