I am making a game using OpenGL (Visual C++, Windows) and i need to use multiple clipping planes. I use glScissor to clip a region of text within a GUI component (i.e. a label or textbox) and also to clip components within a container (i.e. window). How do i do both of these at the same time? Is it possible?
Here is a screenshot showing how i have my GUI:
EDIT: oh, i should mention how i am currently attempting to do it. See, i create an OpenGL display list for each GUI component (button, label, etc) and call that dl when i want to draw the component. I do this mainly because i only need to create the image when and if the component changes position or size. So i thought i could clip the text on a TextBox when i create the display list for it. And then when i draw the TextBox on the container in my screenshot, the image created by the dl would be clipped to the container. But that doesn't quite work.
Here is some of my code:
//// TextField.cpp ///////////////////
/* Updates the component's image when one of it's properties changes */
void TextField::update() {
// Create display lists to draw the image
createComponentDL(dlImg,img,x,y,width,height,divLeft,divRight);
const int textSize = (int)(height*TEXT_FIELD_SIZE);
const int textY = (int)(height/2.0f - textSize/2.0f);
// Clip text to component edge
clipRect(getAbsX()+TEXT_FIELD_PADDING_X, getAbsY(),
width-(2*TEXT_FIELD_PADDING_X), height);
buildList(dlText);
printText(x+TEXT_FIELD_PADDING_X, y+textY, text, font, textSize);
endList();
disableClip();
hasChanged = false;
}
void TextField::draw() {
if (hasChanged) update(); // Update image if need be
callList(dlImg);
callList(dlText);
int cxPos = x + getCharCoord(cursorPos);
int sxPos = x + getCharCoord(selectPos);
if (cxPos > width) cxPos = width;
if (sxPos > width) sxPos = width;
if (cursorPos == selectPos)
drawLine(cxPos, y + TEXT_FIELD_PADDING_Y,
cxPos, y + height - TEXT_FIELD_PADDING_Y); // Draw cursor
else {
setLogicOp(GL_INVERT);
if (cursorPos > selectPos) // Draw selection
fillRect(sxPos, y + TEXT_FIELD_PADDING_Y,
cxPos-sxPos, height-(2*TEXT_FIELD_PADDING_Y));
else
fillRect(cxPos, y + TEXT_FIELD_PADDING_Y,
sxPos-cxPos, height-(2*TEXT_FIELD_PADDING_Y));
setLogicOp(GL_COPY);
}
}
//// Container.cpp ////////////
void Container::draw() {
glPushMatrix();
// Clip to container bounds.
clipRect(getAbsX(), getAbsY()+2, width, height);
glTranslated(x + cX, y + cY, 0); // Draw relative to container pos
for (int i = 0; i < numComponents(); i++) {
components->draw(); //### Draw each component in this container ###
}
disableClip();
glPopMatrix();
if (scrollBar) {
glPushMatrix();
glTranslated(x, y, 0);
scrollBar->draw();
glPopMatrix();
}
}
/* Draws the currently active Window/Panel and any other visible */
/* components (i.e. a Panel behind another Panel) */
void Container::drawScreen() {
for (int i = MAX_SCREENS; i >= 0; i--) { // Draw first one last
if (Component::visible)
Component::visible->draw(); //### This draws the window shown in the screenshot ###
}
}
//// Graphics.h /////////////
inline void clipRect(int x, int y, int width, int height) {
glScissor(x, y, width, height);
glEnable(GL_SCISSOR_TEST);
}
inline void disableClip() { glDisable(GL_SCISSOR_TEST); }
The textboxes (TextFields) in my screenshot are components in the Container, they are drawn in Container::draw().
I currently draw the screen in the WinMain loop (until i find a better way of doing it):
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdLine, int wndState) {
MSG msg;
// Init stuff
...
loadGUIData();
createUIScreens();
while(!appQuit) {
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
if (msg.message==WM_QUIT) {
appQuit = true;
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else {
clearScreen();
Container::drawScreen(); // Draw the screen
SwapBuffers(hdc);
Sleep(20);
}
}
...
}
I haven't provided the code for the rest of my GUI (window code and stuff) but comments with ### explain what happens.
[Edited by - XTAL256 on June 20, 2008 7:50:52 PM]