Beispiel #1
0
void GLFont::String::draw(const GLFont::Vector& origin,GLContextData& contextData) const
	{
	/* Retrieve the context data item: */
	DataItem* dataItem=contextData.retrieveDataItem<DataItem>(this);
	
	/* Render a textured quad: */
	glPushAttrib(GL_TEXTURE_BIT);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D,dataItem->textureObjectId);
	glTexEnvMode(GLTexEnvEnums::TEXTURE_ENV,GLTexEnvEnums::BLEND);
	glTexEnvColor(GLTexEnvEnums::TEXTURE_ENV,foregroundColor);
	glColor(backgroundColor);
	Box offsetBox=box.offset(origin);
	glBegin(GL_QUADS);
	glNormal3f(0.0,0.0,1.0);
	glTexCoord(texCoord.getCorner(0));
	glVertex(offsetBox.getCorner(0));
	glTexCoord(texCoord.getCorner(1));
	glVertex(offsetBox.getCorner(1));
	glTexCoord(texCoord.getCorner(3));
	glVertex(offsetBox.getCorner(3));
	glTexCoord(texCoord.getCorner(2));
	glVertex(offsetBox.getCorner(2));
	glEnd();
	glBindTexture(GL_TEXTURE_2D,0);
	glPopAttrib();
	}
Beispiel #2
0
void QuadSetNode::glRenderAction(GLRenderState& renderState) const
	{
	/* Bail out if there are less than 4 points: */
	if(coord.getValue()==0||coord.getValue()->point.getNumValues()<4)
		return;
	
	/* Set up OpenGL state: */
	renderState.enableCulling(GL_BACK);
	
	/* Render the quad set: */
	size_t numPoints=coord.getValue()->point.getNumValues();
	glBegin(GL_QUADS);
	std::vector<Vector>::const_iterator qnIt=quadNormals.begin();
	for(size_t q=0;q+4<=numPoints;q+=4,++qnIt)
		{
		/* Get the quad's four corner points in counter-clockwise order: */
		Point ps[4];
		if(ccw.getValue())
			{
			for(size_t i=0;i<4;++i)
				ps[i]=coord.getValue()->point.getValue(q+i);
			}
		else
			{
			for(size_t i=0;i<4;++i)
				ps[i]=coord.getValue()->point.getValue(q+3-i);
			}
		
		if(pointTransform.getValue()!=0)
			{
			/* Transform the quad's corner points: */
			for(int i=0;i<4;++i)
				ps[i]=pointTransform.getValue()->transformPoint(ps[i]);
			}
		
		/* Draw the quad's front: */
		glNormal(*qnIt);
		for(int i=0;i<4;++i)
			{
			glTexCoord(quadTexCoords[i]);
			glVertex(ps[i]);
			}
		
		if(!solid.getValue())
			{
			/* Draw the quad's back: */
			glNormal(-*qnIt);
			for(int i=3;i>=0;--i)
				{
				glTexCoord(quadTexCoords[i]);
				glVertex(ps[i]);
				}
			}
		}
	glEnd();
	}
void GLLabel::draw(GLContextData& contextData) const
	{
	/* Try listing the label with a deferred renderer: */
	if(DeferredRenderer::addLabel(this))
		return;
	
	/* Retrieve the context data item: */
	DataItem* dataItem=contextData.retrieveDataItem<DataItem>(this);
	
	/* Save and set up OpenGL state: */
	GLbitfield attribPushMask=GL_TEXTURE_BIT;
	bool lightingOn=glIsEnabled(GL_LIGHTING);
	if(lightingOn)
		attribPushMask|=GL_LIGHTING_BIT;
	glPushAttrib(attribPushMask);
	glEnable(GL_TEXTURE_2D);
	if(lightingOn)
		{
		glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR);
		glTexEnvMode(GLTexEnvEnums::TEXTURE_ENV,GLTexEnvEnums::MODULATE);
		}
	else
		glTexEnvMode(GLTexEnvEnums::TEXTURE_ENV,GLTexEnvEnums::REPLACE);
	
	/* Bind the label texture: */
	glBindTexture(GL_TEXTURE_2D,dataItem->textureObjectId);
	
	/* Check if the texture object needs to be updated: */
	if(dataItem->version!=version)
		{
		/* Upload the string's texture image: */
		font->uploadStringTexture(*this,background,foreground);
		
		/* Update the texture version number: */
		dataItem->version=version;
		}
	
	/* Draw a textured quad: */
	glColor4f(1.0f,1.0f,1.0f,background[3]);
	glBegin(GL_QUADS);
	glNormal3f(0.0f,0.0f,1.0f);
	glTexCoord(textureBox.getCorner(0));
	glVertex(labelBox.getCorner(0));
	glTexCoord(textureBox.getCorner(1));
	glVertex(labelBox.getCorner(1));
	glTexCoord(textureBox.getCorner(3));
	glVertex(labelBox.getCorner(3));
	glTexCoord(textureBox.getCorner(2));
	glVertex(labelBox.getCorner(2));
	glEnd();
	
	/* Reset OpenGL state: */
	glBindTexture(GL_TEXTURE_2D,0);
	glPopAttrib();
	}
void MouseCursorFaker::glRenderActionTransparent(GLContextData& contextData) const
	{
	/* Get the data item: */
	DataItem* dataItem=contextData.retrieveDataItem<DataItem>(this);
	
	/* Calculate the device's ray equation: */
	Ray deviceRay(device->getPosition(),device->getRayDirection());
	
	/* Find the nearest screen intersected by the device ray: */
	std::pair<VRScreen*,Scalar> fsResult=findScreen(deviceRay);
	if(fsResult.first!=0)
		{
		/* Calculate the cursor position on the screen: */
		Point cursorPos=deviceRay(fsResult.second);
		Vector x=fsResult.first->getScreenTransformation().getDirection(0)*cursorSize[0];
		Vector y=fsResult.first->getScreenTransformation().getDirection(1)*cursorSize[1];
		cursorPos-=x*cursorHotspot[0];
		cursorPos-=y*cursorHotspot[1];
		
		/* Draw the mouse cursor: */
		glPushAttrib(GL_DEPTH_BUFFER_BIT|GL_ENABLE_BIT);
		GLdouble depthRange[2];
		glGetDoublev(GL_DEPTH_RANGE,depthRange);
		glDepthRange(0.0,0.0);
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D,dataItem->textureObjectId);
		glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
		glEnable(GL_ALPHA_TEST);
		glAlphaFunc(GL_GEQUAL,0.5f);
		glDisable(GL_BLEND);
		glDepthMask(GL_TRUE);
		glBegin(GL_QUADS);
		glTexCoord(cursorTexCoordBox.getVertex(0));
		glVertex(cursorPos);
		glTexCoord(cursorTexCoordBox.getVertex(1));
		cursorPos+=x;
		glVertex(cursorPos);
		glTexCoord(cursorTexCoordBox.getVertex(3));
		cursorPos+=y;
		glVertex(cursorPos);
		glTexCoord(cursorTexCoordBox.getVertex(2));
		cursorPos-=x;
		glVertex(cursorPos);
		glEnd();
		glBindTexture(GL_TEXTURE_2D,0);
		glDepthRange(depthRange[0],depthRange[1]);
		glPopAttrib();
		}
	}
Beispiel #5
0
void TextNode::glRenderAction(VRMLRenderState& renderState) const
{
    /* Retrieve the data item from the context: */
    DataItem* dataItem=renderState.contextData.retrieveDataItem<DataItem>(this);

    /* Set up OpenGL state: */
    glEnable(GL_TEXTURE_2D);
    glTexEnvMode(GLTexEnvEnums::TEXTURE_ENV,GLTexEnvEnums::MODULATE);
    glEnable(GL_ALPHA_TEST);
    glAlphaFunc(GL_GEQUAL,0.5f);
    glDisable(GL_CULL_FACE);
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);

    /* Draw the strings as texture-mapped quads: */
    for(size_t i=0; i<string.size(); ++i)
    {
        glBindTexture(GL_TEXTURE_2D,dataItem->textureObjectIds[i]);
        glBegin(GL_QUADS);
        glNormal3f(0.0f,0.0f,1.0f);
        glTexCoord(stringTexBox[i].getCorner(0));
        glVertex(stringBox[i].getCorner(0));
        glTexCoord(stringTexBox[i].getCorner(1));
        glVertex(stringBox[i].getCorner(1));
        glTexCoord(stringTexBox[i].getCorner(3));
        glVertex(stringBox[i].getCorner(3));
        glTexCoord(stringTexBox[i].getCorner(2));
        glVertex(stringBox[i].getCorner(2));
        glEnd();
    }

    /* Protect the texture objects: */
    glBindTexture(GL_TEXTURE_2D,0);

    /* Reset OpenGL state: */
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_FALSE);
    glEnable(GL_CULL_FACE);
    glDisable(GL_ALPHA_TEST);
    glDisable(GL_TEXTURE_2D);
}
// Send out a normal, texture coordinate, vertex coordinate, and an optional custom attribute.
void TParametricSurface::Vertex(vec2 domain)
{
    vec3 p0, p1, p2, p3;
    vec3 normal;
    float u = domain.u;
    float v = domain.v;

    Eval(domain, p0);
    vec2 z1(u + du/2, v);
    Eval(z1, p1);
    vec2 z2(u + du/2 + du, v);
    Eval(z2, p3);

    if (flipped) {
        vec2 z3(u + du/2, v - dv);
        Eval(z3, p2);
    } else {
        vec2 z4(u + du/2, v + dv);
        Eval(z4, p2);
    }

    const float epsilon = 0.00001f;

    vec3 tangent = p3 - p1;
    vec3 binormal = p2 - p1;
    normal = cross(tangent, binormal);
    if (normal.magnitude() < epsilon)
        normal = p0;
    normal.unitize();

    if (tangentLoc != -1)
    {
        if (tangent.magnitude() < epsilon)
            tangent = cross(binormal, normal);
        tangent.unitize();
        glVertexAttrib(tangentLoc, tangent);
    }

    if (binormalLoc != -1)
    {
        binormal.unitize();
        glVertexAttrib(binormalLoc, -binormal);
    }

    if (CustomAttributeLocation() != -1)
        glVertexAttrib1f(CustomAttributeLocation(), CustomAttributeValue(domain));

    glNormal(normal);
    glTexCoord(domain);
    glVertex(p0);
}
Beispiel #7
0
void GLFont::drawString(const GLFont::Vector& origin,const char* string) const
	{
	/* Calculate the string's texel width: */
	GLsizei stringWidth=calcStringWidth(string);
	
	/* Calculate the string's bounding box: */
	Box stringBox=calcStringBox(stringWidth);
	stringBox.doOffset(origin);
	
	/* Calculate the texture width: */
	GLsizei textureWidth;
	for(textureWidth=1;textureWidth<stringWidth;textureWidth<<=1)
		;
	
	/* Calculate the string's texture coordinates: */
	TBox stringTexCoord=calcStringTexCoords(stringWidth,textureWidth);
	
	/* Upload the string's texture image: */
	uploadStringTexture(string,backgroundColor,foregroundColor,stringWidth,textureWidth);
	
	/* Render a textured quad: */
	glPushAttrib(GL_TEXTURE_BIT);
	glEnable(GL_TEXTURE_2D);
	glTexEnvMode(GLTexEnvEnums::TEXTURE_ENV,GLTexEnvEnums::MODULATE);
	glColor4f(1.0f,1.0f,1.0f,backgroundColor[3]);
	glBegin(GL_QUADS);
	glNormal3f(0.0,0.0,1.0);
	glTexCoord(stringTexCoord.getCorner(0));
	glVertex(stringBox.getCorner(0));
	glTexCoord(stringTexCoord.getCorner(1));
	glVertex(stringBox.getCorner(1));
	glTexCoord(stringTexCoord.getCorner(3));
	glVertex(stringBox.getCorner(3));
	glTexCoord(stringTexCoord.getCorner(2));
	glVertex(stringBox.getCorner(2));
	glEnd();
	glPopAttrib();
	}
void GLLabel::DeferredRenderer::draw(void)
	{
	/* Bail out if no labels were gathered: */
	if(gatheredLabels.empty())
		return;
	
	/* Save and set up OpenGL state: */
	GLbitfield attribPushMask=GL_TEXTURE_BIT;
	bool lightingOn=glIsEnabled(GL_LIGHTING);
	if(lightingOn)
		attribPushMask|=GL_LIGHTING_BIT;
	glPushAttrib(attribPushMask);
	glEnable(GL_TEXTURE_2D);
	if(lightingOn)
		{
		glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR);
		glTexEnvMode(GLTexEnvEnums::TEXTURE_ENV,GLTexEnvEnums::MODULATE);
		}
	else
		glTexEnvMode(GLTexEnvEnums::TEXTURE_ENV,GLTexEnvEnums::REPLACE);
	
	/* Draw each gathered label: */
	for(std::vector<const GLLabel*>::iterator lIt=gatheredLabels.begin();lIt!=gatheredLabels.end();++lIt)
		{
		const GLLabel* l=*lIt;
		
		/* Retrieve the context data item: */
		GLLabel::DataItem* dataItem=contextData.retrieveDataItem<GLLabel::DataItem>(*lIt);
		
		/* Bind the label texture: */
		glBindTexture(GL_TEXTURE_2D,dataItem->textureObjectId);
		
		/* Check if the texture object needs to be updated: */
		if(dataItem->version!=l->version)
			{
			/* Upload the string's texture image: */
			l->font->uploadStringTexture(*l,l->background,l->foreground);
			
			/* Update the texture version number: */
			dataItem->version=l->version;
			}
		
		/* Draw a textured quad: */
		glColor4f(1.0f,1.0f,1.0f,l->background[3]);
		glBegin(GL_QUADS);
		glNormal3f(0.0f,0.0f,1.0f);
		glTexCoord(l->textureBox.getCorner(0));
		glVertex(l->labelBox.getCorner(0));
		glTexCoord(l->textureBox.getCorner(1));
		glVertex(l->labelBox.getCorner(1));
		glTexCoord(l->textureBox.getCorner(3));
		glVertex(l->labelBox.getCorner(3));
		glTexCoord(l->textureBox.getCorner(2));
		glVertex(l->labelBox.getCorner(2));
		glEnd();
		}
	
	/* Reset OpenGL state: */
	glBindTexture(GL_TEXTURE_2D,0);
	glPopAttrib();
	
	/* Clear the list of labels: */
	gatheredLabels.clear();
	}
void IndexedFaceSetNode::glRenderAction(VRMLRenderState& renderState) const
	{
	/* Retrieve the data item from the context: */
	DataItem* dataItem=renderState.contextData.retrieveDataItem<DataItem>(this);
	
	const TextureCoordinateNode* texCoordNode=dynamic_cast<const TextureCoordinateNode*>(texCoord.getPointer());
	const ColorNode* colorNode=dynamic_cast<const ColorNode*>(color.getPointer());
	const NormalNode* normalNode=dynamic_cast<const NormalNode*>(normal.getPointer());
	const CoordinateNode* coordNode=dynamic_cast<const CoordinateNode*>(coord.getPointer());
	
	/* Set up OpenGL: */
	if(ccw)
		glFrontFace(GL_CCW);
	else
		glFrontFace(GL_CW);
	if(solid)
		{
		glEnable(GL_CULL_FACE);
		glCullFace(GL_BACK);
		glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_FALSE);
		}
	else
		{
		glDisable(GL_CULL_FACE);
		glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
		}
	
	if(dataItem->vertexBufferObjectId!=0&&dataItem->indexBufferObjectId!=0)
		{
		/* Determine which parts of the vertex array to enable: */
		int vertexPartsMask=0;
		if(texCoordNode!=0)
			vertexPartsMask|=GLVertexArrayParts::TexCoord;
		if(colorNode!=0)
			vertexPartsMask|=GLVertexArrayParts::Color;
		if(normalNode!=0)
			vertexPartsMask|=GLVertexArrayParts::Normal;
		vertexPartsMask|=GLVertexArrayParts::Position;
		
		/* Draw the indexed triangle set: */
		GLVertexArrayParts::enable(vertexPartsMask);
		glBindBufferARB(GL_ARRAY_BUFFER_ARB,dataItem->vertexBufferObjectId);
		glVertexPointer(vertexPartsMask,static_cast<const Vertex*>(0));
		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,dataItem->indexBufferObjectId);
		glDrawElements(GL_TRIANGLES,dataItem->numTriangles*3,GL_UNSIGNED_INT,static_cast<const GLuint*>(0));
		glBindBufferARB(GL_ARRAY_BUFFER_ARB,0);
		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,0);
		GLVertexArrayParts::disable(vertexPartsMask);
		}
	else
		{
		/* Process all faces: */
		std::vector<int>::const_iterator texCoordIt=texCoordIndices.empty()?coordIndices.begin():texCoordIndices.begin();
		std::vector<int>::const_iterator colorIt=colorIndices.empty()?coordIndices.begin():colorIndices.begin();
		int colorCounter=0;
		std::vector<int>::const_iterator normalIt=normalIndices.empty()?coordIndices.begin():normalIndices.begin();
		int normalCounter=0;
		std::vector<int>::const_iterator coordIt=coordIndices.begin();
		while(coordIt!=coordIndices.end())
			{
			glBegin(GL_POLYGON);
			while(*coordIt>=0)
				{
				if(texCoordNode!=0)
					glTexCoord(texCoordNode->getPoint(*texCoordIt));
				if(colorNode!=0)
					{
					if(!colorPerVertex&&colorIndices.empty())
						glColor(colorNode->getColor(colorCounter));
					else
						glColor(colorNode->getColor(*colorIt));
					}
				if(normalNode!=0)
					{
					if(!normalPerVertex&&normalIndices.empty())
						glNormal(normalNode->getVector(normalCounter));
					else
						glNormal(normalNode->getVector(*normalIt));
					}
				glVertex(coordNode->getPoint(*coordIt));
				++texCoordIt;
				if(colorPerVertex)
					++colorIt;
				if(normalPerVertex)
					++normalIt;
				++coordIt;
				}
			glEnd();
			
			++texCoordIt;
			if(!colorPerVertex&&colorIndices.empty())
				++colorCounter;
			else
				++colorIt;
			if(!normalPerVertex&&normalIndices.empty())
				++normalCounter;
			else
				++normalIt;
			++coordIt;
			}
		}
	
	/* Reset OpenGL state: */
	if(!ccw)
		glFrontFace(GL_CCW);
	if(!solid)
		{
		glEnable(GL_CULL_FACE);
		glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_FALSE);
		}
	}
void MouseNavigationTool::display(GLContextData& contextData) const
{
    bool gotoScreenCoords=factory->showMouseCursor||(factory->showScreenCenter&&navigationMode!=IDLE&&navigationMode!=WIDGETING);
    const VRScreen* screen=0;
    ONTransform screenT;
    if(gotoScreenCoords)
    {
        /* Get a pointer to the screen the mouse is on: */
        if(mouseAdapter!=0&&mouseAdapter->getWindow()!=0)
            screen=mouseAdapter->getWindow()->getVRScreen();
        else
            screen=getMainScreen();
        screenT=screen->getScreenTransformation();

        /* Save and set up OpenGL state: */
        glPushAttrib(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ENABLE_BIT|GL_LINE_BIT|GL_TEXTURE_BIT);
        glDisable(GL_LIGHTING);

        /* Go to screen coordinates: */
        glPushMatrix();
        glMultMatrix(screenT);
    }

    if(factory->showScreenCenter&&navigationMode!=IDLE&&navigationMode!=WIDGETING)
    {
        /* Determine the screen containing the input device and find its center: */
        Scalar centerPos[2];
        if(mouseAdapter!=0)
            mouseAdapter->getWindow()->getWindowCenterPos(centerPos);
        else
        {
            centerPos[0]=getMainScreen()->getWidth()*Scalar(0.5);
            centerPos[1]=getMainScreen()->getHeight()*Scalar(0.5);
        }

        /* Calculate the endpoints of the screen's crosshair lines in screen coordinates: */
        Point l=Point(Scalar(0),centerPos[1],Scalar(0));
        Point r=Point(screen->getWidth(),centerPos[1],Scalar(0));
        Point b=Point(centerPos[0],Scalar(0),Scalar(0));
        Point t=Point(centerPos[0],screen->getHeight(),Scalar(0));

        /* Determine the crosshair colors: */
        Color bgColor=getBackgroundColor();
        Color fgColor;
        for(int i=0; i<3; ++i)
            fgColor[i]=1.0f-bgColor[i];
        fgColor[3]=bgColor[3];

        /* Draw the screen crosshairs: */
        glDepthFunc(GL_LEQUAL);
        glLineWidth(3.0f);
        glColor(bgColor);
        glBegin(GL_LINES);
        glVertex(l);
        glVertex(r);
        glVertex(b);
        glVertex(t);
        glEnd();
        glLineWidth(1.0f);
        glColor(fgColor);
        glBegin(GL_LINES);
        glVertex(l);
        glVertex(r);
        glVertex(b);
        glVertex(t);
        glEnd();
    }

    if(factory->showMouseCursor)
    {
        /* Get the data item: */
        DataItem* dataItem=contextData.retrieveDataItem<DataItem>(this);

        /* Calculate the mouse position: */
        Point mousePos=screenT.inverseTransform(currentPos);
        for(int i=0; i<2; ++i)
            mousePos[i]-=factory->mouseCursorHotspot[i]*factory->mouseCursorSize[i];

        /* Draw the mouse cursor: */
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D,dataItem->textureObjectId);
        glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
        glEnable(GL_ALPHA_TEST);
        glAlphaFunc(GL_GEQUAL,0.5f);
        glBegin(GL_QUADS);
        glTexCoord(mouseCursorTexCoordBox.getVertex(0));
        glVertex(mousePos[0],mousePos[1]);
        glTexCoord(mouseCursorTexCoordBox.getVertex(1));
        glVertex(mousePos[0]+factory->mouseCursorSize[0],mousePos[1]);
        glTexCoord(mouseCursorTexCoordBox.getVertex(3));
        glVertex(mousePos[0]+factory->mouseCursorSize[0],mousePos[1]+factory->mouseCursorSize[1]);
        glTexCoord(mouseCursorTexCoordBox.getVertex(2));
        glVertex(mousePos[0],mousePos[1]+factory->mouseCursorSize[1]);
        glEnd();
        glBindTexture(GL_TEXTURE_2D,0);
    }

    if(gotoScreenCoords)
    {
        /* Go back to physical coordinates: */
        glPopMatrix();

        /* Restore OpenGL state: */
        glPopAttrib();
    }
}
Beispiel #11
0
void ColorBar::draw(GLContextData& contextData) const
	{
	/* Retrieve the context data item: */
	DataItem* dataItem=contextData.retrieveDataItem<DataItem>(this);
	
	/* Draw parent class decorations: */
	Widget::draw(contextData);
	
	/* Draw the widget margin: */
	glColor(backgroundColor);
	glBegin(GL_TRIANGLE_FAN);
	glNormal3f(0.0f,0.0f,1.0f);
	glVertex(getInterior().getCorner(0));
	glVertex(getInterior().getCorner(1));
	for(int i=numTickMarks-1;i>=0;--i)
		{
		glVertex(tickMarks[i].labelBox.getCorner(1));
		glVertex(tickMarks[i].labelBox.getCorner(0));
		}
	glVertex(tickMarks[0].labelBox.getCorner(2));
	glVertex(tickMarkLabelBox.getCorner(2));
	glVertex(colorBarBox.getCorner(0));
	glVertex(colorBarBox.getCorner(2));
	glVertex(getInterior().getCorner(2));
	glEnd();
	glBegin(GL_TRIANGLE_FAN);
	glVertex(getInterior().getCorner(3));
	glVertex(getInterior().getCorner(2));
	glVertex(colorBarBox.getCorner(2));
	glVertex(colorBarBox.getCorner(3));
	glVertex(colorBarBox.getCorner(1));
	glVertex(tickMarkLabelBox.getCorner(3));
	glVertex(tickMarks[numTickMarks-1].labelBox.getCorner(3));
	glVertex(tickMarks[numTickMarks-1].labelBox.getCorner(1));
	glVertex(getInterior().getCorner(1));
	glEnd();
	
	/* Draw the spaces between the tick mark labels: */
	glBegin(GL_QUADS);
	for(int i=1;i<numTickMarks;++i)
		{
		glVertex(tickMarks[i-1].labelBox.getCorner(3));
		glVertex(tickMarks[i-1].labelBox.getCorner(1));
		glVertex(tickMarks[i].labelBox.getCorner(0));
		glVertex(tickMarks[i].labelBox.getCorner(2));
		}
	glEnd();
	
	/* Draw the border between tick marks and tick mark labels: */
	glBegin(GL_QUAD_STRIP);
	GLfloat tickBot=tickMarkLabelBox.origin[1]+tickMarkLabelBox.size[1];
	glVertex(tickMarkLabelBox.getCorner(2));
	glVertex(tickMarks[0].labelBox.getCorner(2));
	glVertex3f(tickMarkLabelBox.origin[0]+tickMarkWidth,tickBot,tickMarkLabelBox.origin[2]);
	glVertex(tickMarks[0].labelBox.getCorner(3));
	for(int i=1;i<numTickMarks-1;++i)
		{
		GLfloat x=colorBarBox.origin[0]+colorBarBox.size[0]*GLfloat(i)/GLfloat(numTickMarks-1);
		glVertex3f(x-tickMarkWidth*0.5f,tickBot,tickMarkLabelBox.origin[2]);
		glVertex(tickMarks[i].labelBox.getCorner(2));
		glVertex3f(x+tickMarkWidth*0.5f,tickBot,tickMarkLabelBox.origin[2]);
		glVertex(tickMarks[i].labelBox.getCorner(3));
		}
	glVertex3f(tickMarkLabelBox.origin[0]+tickMarkLabelBox.size[0]-tickMarkWidth,tickBot,tickMarkLabelBox.origin[2]);
	glVertex(tickMarks[numTickMarks-1].labelBox.getCorner(2));
	glVertex(tickMarkLabelBox.getCorner(3));
	glVertex(tickMarks[numTickMarks-1].labelBox.getCorner(3));
	glEnd();
	
	/* Draw the spaces between tick marks: */
	glBegin(GL_QUADS);
	GLfloat tickTop=colorBarBox.origin[1];
	glVertex(colorBarBox.getCorner(0));
	glVertex3f(tickMarkLabelBox.origin[0]+tickMarkWidth,tickBot,tickMarkLabelBox.origin[2]);
	for(int i=1;i<numTickMarks-1;++i)
		{
		GLfloat x=colorBarBox.origin[0]+colorBarBox.size[0]*GLfloat(i)/GLfloat(numTickMarks-1);
		glVertex3f(x-tickMarkWidth*0.5f,tickBot,tickMarkLabelBox.origin[2]);
		glVertex3f(x,tickTop,colorBarBox.origin[2]);
		glVertex3f(x,tickTop,colorBarBox.origin[2]);
		glVertex3f(x+tickMarkWidth*0.5f,tickBot,tickMarkLabelBox.origin[2]);
		}
	glVertex3f(tickMarkLabelBox.origin[0]+tickMarkLabelBox.size[0]-tickMarkWidth,tickBot,tickMarkLabelBox.origin[2]);
	glVertex(colorBarBox.getCorner(1));
	glEnd();
	
	/* Draw the tick marks: */
	glBegin(GL_TRIANGLES);
	glColor(foregroundColor);
	glVertex(tickMarkLabelBox.getCorner(2));
	glVertex3f(tickMarkLabelBox.origin[0]+tickMarkWidth,tickBot,tickMarkLabelBox.origin[2]);
	glVertex(colorBarBox.getCorner(0));
	for(int i=1;i<numTickMarks-1;++i)
		{
		GLfloat x=colorBarBox.origin[0]+colorBarBox.size[0]*GLfloat(i)/GLfloat(numTickMarks-1);
		glVertex3f(x-tickMarkWidth*0.5f,tickBot,tickMarkLabelBox.origin[2]);
		glVertex3f(x+tickMarkWidth*0.5f,tickBot,tickMarkLabelBox.origin[2]);
		glVertex3f(x,tickTop,colorBarBox.origin[2]);
		}
	glVertex3f(tickMarkLabelBox.origin[0]+tickMarkLabelBox.size[0]-tickMarkWidth,tickBot,tickMarkLabelBox.origin[2]);
	glVertex(tickMarkLabelBox.getCorner(3));
	glVertex(colorBarBox.getCorner(1));
	glEnd();
	
	/* Set up OpenGL state for color bar rendering: */
	GLboolean lightingEnabled=glIsEnabled(GL_LIGHTING);
	if(lightingEnabled)
		glDisable(GL_LIGHTING);
	GLboolean texture1DEnabled=glIsEnabled(GL_TEXTURE_1D);
	if(!texture1DEnabled)
		glEnable(GL_TEXTURE_1D);
	GLboolean texture2DEnabled=glIsEnabled(GL_TEXTURE_2D);
	if(texture2DEnabled)
		glDisable(GL_TEXTURE_2D);
	GLboolean texture3DEnabled=glIsEnabled(GL_TEXTURE_3D);
	if(texture3DEnabled)
		glDisable(GL_TEXTURE_3D);
	
	/* Upload the color map as a 1D texture: */
	glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_BASE_LEVEL,0);
	glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MAX_LEVEL,0);
	glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexImage1D(GL_TEXTURE_1D,0,GL_RGBA8,256,0,GL_RGBA,GL_FLOAT,colorMap->getColors());
	glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
	
	GLint matrixMode;
	glGetIntegerv(GL_MATRIX_MODE,&matrixMode);
	if(matrixMode!=GL_TEXTURE)
		glMatrixMode(GL_TEXTURE);
	glPushMatrix();
	glLoadIdentity();
	glScaled(1.0/(valueMax-valueMin),1.0,1.0);
	glTranslated(-valueMin,0.0,0.0);
	
	/* Draw the color bar: */
	glBegin(GL_TRIANGLE_FAN);
	glColor4f(1.0f,1.0f,1.0f,1.0f);
	glTexCoord1d(valueMin);
	glVertex(colorBarBox.getCorner(2));
	glVertex(colorBarBox.getCorner(0));
	for(int i=1;i<numTickMarks-1;++i)
		{
		GLfloat x=colorBarBox.origin[0]+colorBarBox.size[0]*GLfloat(i)/GLfloat(numTickMarks-1);
		glTexCoord1d(valueMin+(valueMax-valueMin)*double(i)/double(numTickMarks-1));
		glVertex3f(x,tickTop,colorBarBox.origin[2]);
		}	
	glTexCoord1d(valueMax);
	glVertex(colorBarBox.getCorner(1));
	glVertex(colorBarBox.getCorner(3));
	glEnd();
	
	/* Reset OpenGL state: */
	glPopMatrix();
	if(matrixMode!=GL_TEXTURE)
		glMatrixMode(matrixMode);
	if(texture3DEnabled)
		glEnable(GL_TEXTURE_3D);
	if(texture2DEnabled)
		glEnable(GL_TEXTURE_2D);
	if(!texture1DEnabled)
		glDisable(GL_TEXTURE_1D);
	if(lightingEnabled)
		glEnable(GL_LIGHTING);
	
	/* Draw the tick mark labels: */
	glPushAttrib(GL_TEXTURE_BIT);
	GLint lightModelColorControl;
	glGetIntegerv(GL_LIGHT_MODEL_COLOR_CONTROL,&lightModelColorControl);
	glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR);
	glEnable(GL_TEXTURE_2D);
	for(int i=0;i<numTickMarks;++i)
		{
		glBindTexture(GL_TEXTURE_2D,dataItem->textureObjectIds[i]);
		if(dataItem->tickMarksVersion!=tickMarksVersion) // Have the tick marks changed?
			{
			/* Upload the tick mark label string texture again: */
			font->uploadStringTexture(tickMarks[i].label,backgroundColor,foregroundColor);
			}
		glTexEnvMode(GLTexEnvEnums::TEXTURE_ENV,GLTexEnvEnums::MODULATE);
		glColor4f(1.0f,1.0f,1.0f,backgroundColor[3]);
		glBegin(GL_QUADS);
		glNormal3f(0.0f,0.0f,1.0f);
		glTexCoord(tickMarks[i].labelTexCoords.getCorner(0));
		glVertex(tickMarks[i].labelBox.getCorner(0));
		glTexCoord(tickMarks[i].labelTexCoords.getCorner(1));
		glVertex(tickMarks[i].labelBox.getCorner(1));
		glTexCoord(tickMarks[i].labelTexCoords.getCorner(3));
		glVertex(tickMarks[i].labelBox.getCorner(3));
		glTexCoord(tickMarks[i].labelTexCoords.getCorner(2));
		glVertex(tickMarks[i].labelBox.getCorner(2));
		glEnd();
		}
	dataItem->tickMarksVersion=tickMarksVersion;
	glBindTexture(GL_TEXTURE_2D,0);
	glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,lightModelColorControl);
	glPopAttrib();
	}