Beispiel #1
0
void Text3DOverlay::render(RenderArgs* args) {
    if (!_visible) {
        return; // do nothing if we're not visible
    }

    
    Q_ASSERT(args->_batch);
    auto& batch = *args->_batch;
    
    glm::quat rotation;
    
    if (_isFacingAvatar) {
        // rotate about vertical to face the camera
        rotation = args->_viewFrustum->getOrientation();
    } else {
        rotation = getRotation();
    }
    
    Transform transform;
    transform.setTranslation(getPosition());
    transform.setRotation(rotation);
    transform.setScale(getScale());
    
    batch.setModelTransform(transform);
    
    const float MAX_COLOR = 255.0f;
    xColor backgroundColor = getBackgroundColor();
    glm::vec4 quadColor(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR,
                        getBackgroundAlpha());
    
    glm::vec2 dimensions = getDimensions();
    glm::vec2 halfDimensions = dimensions * 0.5f;
    
    const float SLIGHTLY_BEHIND = -0.005f;
    
    glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
    glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
    DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, true, false, true);
    DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor);
    
    // Same font properties as textSize()
    float maxHeight = (float)_textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;
    
    float scaleFactor =  (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
    
    glm::vec2 clipMinimum(0.0f, 0.0f);
    glm::vec2 clipDimensions((dimensions.x - (_leftMargin + _rightMargin)) / scaleFactor,
                             (dimensions.y - (_topMargin + _bottomMargin)) / scaleFactor);
    
    transform.setTranslation(getPosition());
    transform.postTranslate(glm::vec3(-(halfDimensions.x - _leftMargin) , halfDimensions.y - _topMargin, 0.01f));
    transform.setScale(scaleFactor);
    batch.setModelTransform(transform);
    
    glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, getAlpha() };
    _textRenderer->draw(batch, 0, 0, _text, textColor);
    
    batch.setPipeline(DrawOverlay3D::getOpaquePipeline());
}
Beispiel #2
0
void CameraToolBox::render(int x, int y, bool boxed) {
    glEnable(GL_TEXTURE_2D);
    
    if (!_enabledTexture) {
        _enabledTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/face.svg");
    }
    if (!_mutedTexture) {
        _mutedTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/face-mute.svg");
    }
    
    const int MUTE_ICON_SIZE = 24;
    _iconBounds = QRect(x, y, MUTE_ICON_SIZE, MUTE_ICON_SIZE);
    float iconColor = 1.0f;
    if (!Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking)) {
        glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_enabledTexture));
    } else {
        glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_mutedTexture));
        
        // Make muted icon pulsate
        static const float PULSE_MIN = 0.4f;
        static const float PULSE_MAX = 1.0f;
        static const float PULSE_FREQUENCY = 1.0f; // in Hz
        qint64 now = usecTimestampNow();
        if (now - _iconPulseTimeReference > (qint64)USECS_PER_SECOND) {
            // Prevents t from getting too big, which would diminish glm::cos precision
            _iconPulseTimeReference = now - ((now - _iconPulseTimeReference) % USECS_PER_SECOND);
        }
        float t = (float)(now - _iconPulseTimeReference) / (float)USECS_PER_SECOND;
        float pulseFactor = (glm::cos(t * PULSE_FREQUENCY * 2.0f * PI) + 1.0f) / 2.0f;
        iconColor = PULSE_MIN + (PULSE_MAX - PULSE_MIN) * pulseFactor;
    }
    
    glm::vec4 quadColor(iconColor, iconColor, iconColor, 1.0f);

    glm::vec2 topLeft(_iconBounds.left(), _iconBounds.top());
    glm::vec2 bottomRight(_iconBounds.right(), _iconBounds.bottom());
    glm::vec2 texCoordTopLeft(1,1);
    glm::vec2 texCoordBottomRight(0,0);
    
    if (_boxQuadID == GeometryCache::UNKNOWN_ID) {
        _boxQuadID = DependencyManager::get<GeometryCache>()->allocateID();
    }

    DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor, _boxQuadID);
    
    glDisable(GL_TEXTURE_2D);
}
Beispiel #3
0
void Text3DOverlay::render(RenderArgs* args) {
    if (!_renderVisible || !getParentVisible()) {
        return; // do nothing if we're not visible
    }

    Q_ASSERT(args->_batch);
    auto& batch = *args->_batch;

    auto transform = getRenderTransform();
    batch.setModelTransform(transform);

    glm::u8vec3 backgroundColor = getBackgroundColor();
    glm::vec4 quadColor(toGlm(backgroundColor), getBackgroundAlpha());

    glm::vec2 dimensions = getDimensions();
    glm::vec2 halfDimensions = dimensions * 0.5f;

    const float SLIGHTLY_BEHIND = -0.001f;

    glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
    glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
    DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, quadColor.a < 1.0f, false, false, false);
    DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor, _geometryId);

    // Same font properties as textSize()
    float maxHeight = (float)_textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;

    float scaleFactor =  (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;

    glm::vec2 clipDimensions((dimensions.x - (_leftMargin + _rightMargin)) / scaleFactor,
                             (dimensions.y - (_topMargin + _bottomMargin)) / scaleFactor);

    transform.postTranslate(glm::vec3(-(halfDimensions.x - _leftMargin),
                                      halfDimensions.y - _topMargin, 0.001f));
    transform.setScale(scaleFactor);
    batch.setModelTransform(transform);

    glm::vec4 textColor = { toGlm(_color), getTextAlpha() };

    // FIXME: Factor out textRenderer so that Text3DOverlay overlay parts can be grouped by pipeline for a gpu performance increase.
    _textRenderer->draw(batch, 0, 0, getText(), textColor, glm::vec2(-1.0f), true);
}
Beispiel #4
0
void TextOverlay::render(RenderArgs* args) {
    if (!_visible) {
        return; // do nothing if we're not visible
    }

    const float MAX_COLOR = 255.0f;
    xColor backgroundColor = getBackgroundColor();
    glm::vec4 quadColor(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR,
        getBackgroundAlpha());

    int left = _bounds.left();
    int right = _bounds.right() + 1;
    int top = _bounds.top();
    int bottom = _bounds.bottom() + 1;

    glm::vec2 topLeft(left, top);
    glm::vec2 bottomRight(right, bottom);
    DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);

    // Same font properties as textSize()
    TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT);
    
    const int leftAdjust = -1; // required to make text render relative to left edge of bounds
    const int topAdjust = -2; // required to make text render relative to top edge of bounds
    int x = _bounds.left() + _leftMargin + leftAdjust;
    int y = _bounds.top() + _topMargin + topAdjust;
    
    float alpha = getAlpha();
    glm::vec4 textColor = {_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, alpha };
    QStringList lines = _text.split("\n");
    int lineOffset = 0;
    foreach(QString thisLine, lines) {
        if (lineOffset == 0) {
            lineOffset = textRenderer->calculateHeight(qPrintable(thisLine));
        }
        lineOffset += textRenderer->draw(x, y + lineOffset, qPrintable(thisLine), textColor);

        const int lineGap = 2;
        lineOffset += lineGap;
    }
}
Beispiel #5
0
void Text3DOverlay::render(RenderArgs* args) {
    if (!_visible) {
        return; // do nothing if we're not visible
    }

    glPushMatrix(); {
        glTranslatef(_position.x, _position.y, _position.z);
        glm::quat rotation;
        
        if (_isFacingAvatar) {
            // rotate about vertical to face the camera
            rotation = Application::getInstance()->getCamera()->getRotation();
        } else {
            rotation = getRotation();
        }
        
        glm::vec3 axis = glm::axis(rotation);
        glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);

        const float MAX_COLOR = 255.0f;
        xColor backgroundColor = getBackgroundColor();
        glm::vec4 quadColor(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR,
            getBackgroundAlpha());

        glm::vec2 dimensions = getDimensions();
        glm::vec2 halfDimensions = dimensions * 0.5f;
        
        const float SLIGHTLY_BEHIND = -0.005f;

        glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
        glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
        DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);
        
        // Same font properties as textSize()
        TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
        float maxHeight = (float)textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;
        
        float scaleFactor =  (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight; 

        glTranslatef(-(halfDimensions.x - _leftMargin), halfDimensions.y - _topMargin, 0.0f);

        glm::vec2 clipMinimum(0.0f, 0.0f);
        glm::vec2 clipDimensions((dimensions.x - (_leftMargin + _rightMargin)) / scaleFactor, 
                                 (dimensions.y - (_topMargin + _bottomMargin)) / scaleFactor);

        glScalef(scaleFactor, -scaleFactor, scaleFactor);
        enableClipPlane(GL_CLIP_PLANE0, -1.0f, 0.0f, 0.0f, clipMinimum.x + clipDimensions.x);
        enableClipPlane(GL_CLIP_PLANE1, 1.0f, 0.0f, 0.0f, -clipMinimum.x);
        enableClipPlane(GL_CLIP_PLANE2, 0.0f, -1.0f, 0.0f, clipMinimum.y + clipDimensions.y);
        enableClipPlane(GL_CLIP_PLANE3, 0.0f, 1.0f, 0.0f, -clipMinimum.y);
    
        glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, getAlpha() };
        textRenderer->draw(0, 0, _text, textColor);

        glDisable(GL_CLIP_PLANE0);
        glDisable(GL_CLIP_PLANE1);
        glDisable(GL_CLIP_PLANE2);
        glDisable(GL_CLIP_PLANE3);
        
    } glPopMatrix();
    
}
void
hwColorPerVertexShader::drawTheSwatch( MGeometryData* pGeomData,
									   unsigned int* pIndexing,
									   unsigned int  numberOfData,
									   unsigned int  indexCount )

{
	MHardwareRenderer *pRenderer = MHardwareRenderer::theRenderer();
	if( !pRenderer )	return;

	// Set the default background color
	{
		float r, g, b, a;
		MHWShaderSwatchGenerator::getSwatchBackgroundColor( r, g, b, a );
		glClearColor( r, g, b, a );
	}
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	{
		// Enable the blending to get the transparency to work
		//
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	}

	// Load in a sample background image
	if (mSampleImageId == 0)
	{
		mSampleImage = new MImage;
		MStatus rstatus = mSampleImage->readFromFile("C:\\temp\\maya.gif");
		if (rstatus == MStatus::kSuccess)			
		{
			unsigned int w, h;
			mSampleImage->getSize( w, h );
			if (w > 2 && h > 2 )
			{
				glGenTextures( 1, &mSampleImageId );
				if (mSampleImageId > 0)
				{
					glEnable(GL_TEXTURE_2D);
					glBindTexture ( GL_TEXTURE_2D, mSampleImageId );
					glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, 
						GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) mSampleImage->pixels() );
				}
			}
		}
		if (mSampleImage)
		{
			delete mSampleImage;
		}
	}

	// Overlay the background checker board
	//
	bool drawBackGround = ( mTranspBias > 0.0f );
	bool drawBackGroundTexture = (mSampleImageId != 0);
	if (drawBackGround)
	{
		if (drawBackGroundTexture)
		{
			glMatrixMode(GL_TEXTURE);
			glLoadIdentity();
			glMatrixMode(GL_MODELVIEW);

			glBindTexture(GL_TEXTURE_2D, mSampleImageId );

			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

			glEnable(GL_TEXTURE_2D);
		}

		unsigned int numberOfRepeats = 8;
		MColor quadColor( 0.5f, 0.5f, 0.5f, 1.0f );
		pRenderer->drawSwatchBackGroundQuads( quadColor, 
							drawBackGroundTexture, numberOfRepeats );
		
		if (drawBackGroundTexture)
			glDisable(GL_TEXTURE_2D);
		glEnable(GL_LIGHTING);
	}

	{
		// Set some example material
		//
		float ambient[4]  = { 0.1f, 0.1f, 0.1f, 1.0f };
		float diffuse[4]  = { 0.7f, 0.7f, 0.7f, 1.0f };
		float specular[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
		float emission[4] = { 0.0f, 0.0f, 0.0f, 1.0f };

		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,  ambient);
		glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emission );
		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular );
		glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0f);

		// Track diffuse color
		float swatchColor[4];
		float biasT = 1.0f - mTranspGain - mTranspBias;
		swatchColor[0] = (diffuse[0] * mColorGain[0]) + mColorBias[0];
		swatchColor[1] = (diffuse[1] * mColorGain[1]) + mColorBias[1];
		swatchColor[2] = (diffuse[2] * mColorGain[2]) + mColorBias[2];
		swatchColor[3] = (diffuse[3] * mTranspGain) + biasT;

		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, swatchColor );			
		glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);

		glEnable(GL_COLOR_MATERIAL);
		glColor4fv( swatchColor );
	}

	if (pGeomData)
	{
		glPushClientAttrib ( GL_CLIENT_VERTEX_ARRAY_BIT );

		if (mNormalsPerVertex >= 1)
		{
			glDisable(GL_LIGHTING);
			float *normalData = (float *)( pGeomData[1].data() );
			float * tangentData = (float *)( pGeomData[3].data() );
			float * binormalData = (float *)( pGeomData[4].data() );
			if (normalData && mNormalsPerVertex  == 1)
			{
				glEnableClientState(GL_COLOR_ARRAY);
				glColorPointer(3, GL_FLOAT, 0, normalData);
			}
			else if (tangentData && mNormalsPerVertex  == 2)
			{
				glEnableClientState(GL_COLOR_ARRAY);
				glColorPointer(3, GL_FLOAT, 0, tangentData);
			}
			else if (binormalData)
			{
				glEnableClientState(GL_COLOR_ARRAY);
				glColorPointer(3, GL_FLOAT, 0, binormalData);
			}
		}

		float *vertexData = (float *)( pGeomData[0].data() );
		if (vertexData)
		{
			glEnableClientState( GL_VERTEX_ARRAY );
			glVertexPointer ( 3, GL_FLOAT, 0, vertexData );
		}

		float *normalData = (float *)( pGeomData[1].data() );
		if (normalData)
		{
			glEnableClientState( GL_NORMAL_ARRAY );
			glNormalPointer (    GL_FLOAT, 0, normalData );
		}

		if (mSampleImageId > 0)
		{
			float *uvData = (float *) (pGeomData[2].data() );
			if (uvData)
			{
				glBindTexture ( GL_TEXTURE_2D, mSampleImageId );
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

				glEnable(GL_TEXTURE_2D);
				glEnableClientState( GL_TEXTURE_COORD_ARRAY );
				glTexCoordPointer( 2, GL_FLOAT, 0, uvData );

				glMatrixMode(GL_TEXTURE);
				glLoadIdentity();
				glScalef( 0.5f, 0.5f, 1 );
				//glTranslatef(0.5f, 0.5f, 0.0f);
				glRotatef( mTexRotateX, 1.0f, 0.0f, 0.0f);
				glRotatef( mTexRotateY, 0.0, 1.0f, 0.0f);
				glRotatef( mTexRotateZ, 0.0, 0.0f, 1.0f);
				glMatrixMode(GL_MODELVIEW);
			}
		}

		if (vertexData && normalData && pIndexing )
			glDrawElements ( GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, pIndexing );

		glPopClientAttrib();

		// Release data references
		pRenderer->dereferenceGeometry( pGeomData, numberOfData );

	}
	glDisable( GL_COLOR_MATERIAL );
	glDisable( GL_LIGHTING );
}
Beispiel #7
0
void ImageOverlay::render(RenderArgs* args) {
    if (!_isLoaded && _renderImage) {
        _isLoaded = true;
        _texture = DependencyManager::get<TextureCache>()->getTexture(_imageURL);
    }
    // If we are not visible or loaded, return.  If we are trying to render an
    // image but the texture hasn't loaded, return.
    if (!_visible || !_isLoaded || (_renderImage && !_texture->isLoaded())) {
        return;
    }

    auto geometryCache = DependencyManager::get<GeometryCache>();
    gpu::Batch& batch = *args->_batch;
    geometryCache->useSimpleDrawPipeline(batch);
    if (_renderImage) {
        batch.setResourceTexture(0, _texture->getGPUTexture());
    } else {
        batch.setResourceTexture(0, args->_whiteTexture);
    }

    const float MAX_COLOR = 255.0f;
    xColor color = getColor();
    float alpha = getAlpha();
    glm::vec4 quadColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);

    int left = _bounds.left();
    int right = _bounds.right() + 1;
    int top = _bounds.top();
    int bottom = _bounds.bottom() + 1;

    glm::vec2 topLeft(left, top);
    glm::vec2 bottomRight(right, bottom);

    batch.setModelTransform(Transform());

    // if for some reason our image is not over 0 width or height, don't attempt to render the image
    if (_renderImage) {
        float imageWidth = _texture->getWidth();
        float imageHeight = _texture->getHeight();
        if (imageWidth > 0 && imageHeight > 0) {
            QRect fromImage;
            if (_wantClipFromImage) {
                float scaleX = imageWidth / _texture->getOriginalWidth();
                float scaleY = imageHeight / _texture->getOriginalHeight();

                fromImage.setX(scaleX * _fromImage.x());
                fromImage.setY(scaleY * _fromImage.y());
                fromImage.setWidth(scaleX * _fromImage.width());
                fromImage.setHeight(scaleY * _fromImage.height());
            }
            else {
                fromImage.setX(0);
                fromImage.setY(0);
                fromImage.setWidth(imageWidth);
                fromImage.setHeight(imageHeight);
            }

            float x = fromImage.x() / imageWidth;
            float y = fromImage.y() / imageHeight;
            float w = fromImage.width() / imageWidth; // ?? is this what we want? not sure
            float h = fromImage.height() / imageHeight;

            glm::vec2 texCoordTopLeft(x, y);
            glm::vec2 texCoordBottomRight(x + w, y + h);
            glm::vec4 texcoordRect(texCoordTopLeft, w, h);

            DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
        } else {
            DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor);
        }
    } else {
        DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor);
    }
}
Beispiel #8
0
void ImageOverlay::render(RenderArgs* args) {
    if (!_isLoaded && _renderImage) {
        _isLoaded = true;
        _texture = DependencyManager::get<TextureCache>()->getTexture(_imageURL);
    }

    // If we are not visible or loaded, return.  If we are trying to render an
    // image but the texture hasn't loaded, return.
    if (!_visible || !_isLoaded || (_renderImage && !_texture->isLoaded())) {
        return;
    }

    if (_renderImage) {
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, _texture->getID());
    }

    const float MAX_COLOR = 255.0f;
    xColor color = getColor();
    float alpha = getAlpha();
    glm::vec4 quadColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);

    int left = _bounds.left();
    int right = _bounds.right() + 1;
    int top = _bounds.top();
    int bottom = _bounds.bottom() + 1;

    glm::vec2 topLeft(left, top);
    glm::vec2 bottomRight(right, bottom);

    // if for some reason our image is not over 0 width or height, don't attempt to render the image
    if (_renderImage) {
        float imageWidth = _texture->getWidth();
        float imageHeight = _texture->getHeight();
        if (imageWidth > 0 && imageHeight > 0) {
            QRect fromImage;
            if (_wantClipFromImage) {
                float scaleX = imageWidth / _texture->getOriginalWidth();
                float scaleY = imageHeight / _texture->getOriginalHeight();

                fromImage.setX(scaleX * _fromImage.x());
                fromImage.setY(scaleY * _fromImage.y());
                fromImage.setWidth(scaleX * _fromImage.width());
                fromImage.setHeight(scaleY * _fromImage.height());
            }
            else {
                fromImage.setX(0);
                fromImage.setY(0);
                fromImage.setWidth(imageWidth);
                fromImage.setHeight(imageHeight);
            }

            float x = fromImage.x() / imageWidth;
            float y = fromImage.y() / imageHeight;
            float w = fromImage.width() / imageWidth; // ?? is this what we want? not sure
            float h = fromImage.height() / imageHeight;

            glm::vec2 texCoordTopLeft(x, y);
            glm::vec2 texCoordBottomRight(x + w, y + h);

            DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
        } else {
            DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);
        }
        glDisable(GL_TEXTURE_2D);
    } else {
        DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);
    }
}