LowLevelGraphicsSoftwareRenderer::getClipBounds() question


#1

I’m using LowLevelGraphicsSoftwareRenderer::getClipBounds() and noticed that I always have to add 1 in both x and y directions to the clip bounds. So, my question is: Are the clipping bounds coordinates all included, e.g. if the clipping bounds rectangle is (0,0,4,5), is the clipping region 5 pixels in width and 6 pixels in height?
Also, to what are the clipping bounds relative to? To the origin? Or to the (0,0) pixel in the bitmap that is used as rendering surface?


#2

It’s the same rectangle that is returned from Graphics::getClipBounds() - it’s in the user’s coordinate space, relative to the user’s current origin, not to the target rendering surface.

You shouldn’t have to add 1 though (?) For a rectangular clip region it’s trivial for it to return that value, so I don’t think it’s likely to be wrong… are you sure it’s not your own drawing code that’s out by 1 pixel?


#3

I’m probably missing something or doing something wrong, but I have to use .expanded(1,1) on the clip bounds (see last function in code). Furthermore, in a Slider’s value label, I get the text jumping around (translated by a few pixels), depending on if I am dragging the Slider or not. Weird. Can you check these few lines of code, please it’s where it all happens:

[code]// ------------------------------------------------------------------------------------------------------------------
ILRenderer::ILRenderer(const Image& imageToRenderOn,
const Point& origin,
const RectangleList& initialClip): originX(origin.getX()), originY(origin.getY()),
LowLevelGraphicsSoftwareRenderer(imageToRenderOn, origin, initialClip)
{
Image::BitmapData destData (imageToRenderOn, Image::BitmapData::readWrite);

buf=destData.getPixelPointer(0,0);
w=imageToRenderOn.getWidth();
h=imageToRenderOn.getHeight();
lineStride=destData.lineStride;
pixelStride=destData.pixelStride;

};
// ------------------------------------------------------------------------------------------------------------------
void ILRenderer::drawGlyph(int glyphNumber, const AffineTransform &t)
{
float x=t.getTranslationX();
float y=t.getTranslationY();

uint8 *p=buf;
x+=originX;
y+=originY;

float fh=getFont().getHeight()*fontHeightMultiplier;
y-=fh;

const String fontName=getFont().getTypefaceName();
ILRendererFontManager::ILFont *font=ILRendererFontManager::getInstance()->findFont(fontName);
if (font!=0)
{
	Rectangle<int> clipBounds = getSafeClipBounds();
	aggDrawGlyph(p, clipBounds, fontName, font->data, font->dataLen, fh, true, (double)x, double(y), lineStride, pixelStride, (uint32)glyphNumber, r, g, b);
}

}
// ------------------------------------------------------------------------------------------------------------------
void ILRenderer::setOrigin(int x, int y)
{
originX+=x;
originY+=y;
LowLevelGraphicsSoftwareRenderer::setOrigin(x,y);
}
// ------------------------------------------------------------------------------------------------------------------
Rectangle ILRenderer::getSafeClipBounds()
{
Rectangle clipBounds1(0,0,w,h);
Rectangle clipBounds2=getClipBounds().translated(originX, originY).expanded(1,1);
Rectangle clipBounds=clipBounds1.getIntersection(clipBounds2);
return clipBounds;
}[/code]


#4

It’s not safe to keep your own copy of the origin… The underlying context may have had a transformation applied, so you need to take that into account too.

But I’m surprised you’ve ignored my advice on how best to do this. Honestly, I think you’re approaching it in completely the wrong way - like I said earlier, it’d be much more sensible to tweak the existing edgetable rasteriser to handle the LCD edges. That’d solve the problem elegantly without any need for AGG, or special code-paths or subclasses for glyphs, etc.


#5

But then I wouldn’t have any vertical hinting! And it’s a must.
How do I retrieve the origin? There’s not getOrigin() function…


#6

I thought I explained this earlier. My suggestion was:

  1. Write a custom Typeface class that does the vertical hinting. (Actually, it’d probably be easier to just tweaking the existing one to draw hinted but horizontally stretched characters)
  2. Mod the renderer to do the LCD colour stuff.

Not much code required, and no need for any external libraries, etc. And it’d be far cleaner.

No, the origin is a write-only property because some subclasses (e.g. CoreGraphics renderer) have no accessor for it.


#7

Ok, I just added myself a function getOrigin(int &x, int &y) to JUCE’s LowLevelGraphicsSoftwareRenderer. Now it works. I don’t need to add 1 to the clipping bounds either anymore.
Since this is all about inheriting from LowLevelGraphicsSoftwareRenderer, could you please add that getOrigin() function (and the same for FillType, …) because when one inherits from that class, one needs these functions.

I mean, if LowLevelGraphicsSoftwareRenderer::SavedState’s declaration would be in LowLevelGraphicsSoftwareRenderer.h, that would make things easier! Sub-Classes could just access it. Also what’s the point of making the SavedState variable protected (and not private), if there’s no available declaration for it anyway? Nobody can ever use it.

All in all, I think putting the declaration of SavedState into the header file will solve all problems and make your class more extensible for the people that want to subclass it.