drawImage - Tiled?


#1

A quick and possibly dumb question, is there a way to draw a image which is repeated/tiled in an area? If not, I will create my own code and share here. :wink:

Wk


#2

Graphics::setTiledImageFill


#3

Oh man, I need to learn how to do better searches… :oops:

Thanks Jules.

Wk


#4

Actually, there’s nothing like this in the online manual. I couldn’t find it in Juce files either. I will check if there’s a newer Juce version, it could be that. :wink: (I’m using 1.50)

Wk


#5

Strange, there’s no newer version, so it seems I’m using the latest.

I did find “ImageBrush” which seems to be what I’m looking:

[code]/**
A Brush that fills areas with tiled repetitions of an image.

@see Brush, Graphics::setBrush, SolidColourBrush, GradientBrush

*/
class JUCE_API ImageBrush : public Brush[/code]

Wk


#6

http://www.rawmaterialsoftware.com/juce/api/classImageBrush.html


#7

Thanks, its what I mentioned above, I’m already using it. 8)

g.setBrush(backBrush); g.fillRect(0,0,getWidth(),getHeight());

Wk


#8

Here’s the code I created to draw a skinable square. It used 9 Images.

[code] if (Background[0] != 0)
{
if (backBrush[0] == 0)
{
backBrush[0] = new ImageBrush(Background[1],0,0,1.0f);
backBrush[1] = new ImageBrush(Background[3],0,0,1.0f);
backBrush[2] = new ImageBrush(Background[4],0,0,1.0f);
backBrush[3] = new ImageBrush(Background[5],getWidth()-Background[5]->getWidth(),0,1.0f);
backBrush[4] = new ImageBrush(Background[7],0,getHeight()-Background[7]->getHeight(),1.0f);
}

	g.setBrush(backBrush[2]);	// Middle ///
	g.fillRect(0,0,getWidth(),getHeight());

	g.setBrush(backBrush[0]);	// Top Middle //
	g.fillRect(0,0,getWidth(),Background[1]->getHeight());
	
	g.setBrush(backBrush[4]);	// Bottom Middle //
	g.fillRect(0,getHeight()-Background[7]->getHeight(),getWidth(),Background[7]->getHeight());

	g.setBrush(backBrush[1]);	// Left Middle //
	g.fillRect(0,Background[0]->getHeight(),Background[3]->getWidth(),getHeight()-Background[0]->getHeight()-Background[6]->getHeight());
	
	g.setBrush(backBrush[3]);	// Right Middle //
	g.fillRect(getWidth()-Background[5]->getWidth(),Background[2]->getHeight(),Background[5]->getWidth(),getHeight()-Background[2]->getHeight()-Background[8]->getHeight());

	g.drawImageAt(Background[0],0,0);
	g.drawImageAt(Background[2],getWidth()-Background[2]->getWidth(),0);
	g.drawImageAt(Background[6],0,getHeight()-Background[6]->getHeight());
	g.drawImageAt(Background[8],getWidth()-Background[8]->getWidth(),getHeight()-Background[8]->getHeight());
}[/code]

It uses Image Background[9] which are: TopLeft,TopMid,TopRight,MidLeft,MidMid,MidRight,BottLeft,BottMid,BottRight.

The Brush are:

ImageBrush* backBrush[5];

Wk


#9

If there’s a resize, just delete all backBrush variables and repaint, that’s all. Seems to be working here…

Wk


#10

Ah, yes, sorry - I’m in the middle of changing all the graphics context filling stuff, so don’t get carried away with ImageBrushes, as they’re going to be deprecated at some point in the future.

The new Graphics::setTiledImageFill method isn’t in the online docs yet, but is there in the headers if you’ve got the latest code. It does basically the same thing, but will allow more efficient rendering than is possible by using the abstract Brush classes.


#11

Thanks Jules. I just downloaded the latest version and I see it now in the header files. (I didn’t know how to download the daily/weekly files)

But now I wonder, the setBrush works correctly like I need, while setTiledImageFill doesn’t.

I want to create my own Background image which can be resized, so with any window size it will look correctly thanks to the 9 images as I’m using above.

Now, with setTiledImageFill, from what I understood, I only got to use One picture for the entire background, is that correct?

So, am I right to say that only Brushes would do the correct thing in this case? I do worry that you will deprecate it, since it works perfectly for what I’m doing. But I understand, just need to find another way to do what I have in mind. :wink:

Wk


#12

…no, they have exactly the same capability. You’d just call setTiledImageFill instead of setBrush. It actually makes for more readable code, and avoids having to worry about deleting your brush objects (though in your example that’s clearly not a worry for you, as you seem to just be leaking them!)


#13

Oh, ok, I understand now, I will try it out. Thanks Jules. 8)

Wk


#14

Yeah, it works perfectly. Thanks again.

Here’s the new code. Maybe I will try to create a Macro for this, as its very handy. :wink:

[code]void FileTreeMain::paint (Graphics& g)
{
if (Background[0] != 0)
{
g.setTiledImageFill(*Background[4],0,0,1.0f); // Middle ///
g.fillRect(0,0,getWidth(),getHeight());

	g.setTiledImageFill(*Background[1],0,0,1.0f);	// Top Middle //
	g.fillRect(0,0,getWidth(),Background[1]->getHeight());
	
	g.setTiledImageFill(*Background[7],0,getHeight()-Background[7]->getHeight(),1.0f);	// Bottom Middle //
	g.fillRect(0,getHeight()-Background[7]->getHeight(),getWidth(),Background[7]->getHeight());

	g.setTiledImageFill(*Background[3],0,0,1.0f);	// Left Middle //
	g.fillRect(0,Background[0]->getHeight(),Background[3]->getWidth(),getHeight()-Background[0]->getHeight()-Background[6]->getHeight());
	
	g.setTiledImageFill(*Background[5],getWidth()-Background[5]->getWidth(),0,1.0f);	// Right Middle //
	g.fillRect(getWidth()-Background[5]->getWidth(),Background[2]->getHeight(),Background[5]->getWidth(),getHeight()-Background[2]->getHeight()-Background[8]->getHeight());

	g.drawImageAt(Background[0],0,0);
	g.drawImageAt(Background[2],getWidth()-Background[2]->getWidth(),0);
	g.drawImageAt(Background[6],0,getHeight()-Background[6]->getHeight());
	g.drawImageAt(Background[8],getWidth()-Background[8]->getWidth(),getHeight()-Background[8]->getHeight());
}

}[/code]

Wk


#15

And here’s the Macro.

// IMAGE must be "Image* image[9]" Nine Pictures in the following order: // (TopLeft,TopMid,TopRight,MidLeft,MidMid,MidRight,BottomLeft,BottomMid,BottomRight) #define skinDrawSquare(IMAGE,X,Y,WIDTH,HEIGHT); \ \ g.setTiledImageFill(*IMAGE[4],X,Y,1.0f); \ g.fillRect(X,Y,WIDTH,HEIGHT); \ \ g.setTiledImageFill(*IMAGE[1],X,Y,1.0f); \ g.fillRect(X,Y,WIDTH,IMAGE[1]->getHeight()); \ \ g.setTiledImageFill(*IMAGE[7],X,Y+HEIGHT-IMAGE[7]->getHeight(),1.0f); \ g.fillRect(X,Y+HEIGHT-IMAGE[7]->getHeight(),WIDTH,IMAGE[7]->getHeight()); \ \ g.setTiledImageFill(*IMAGE[3],X,Y,1.0f); \ g.fillRect(X,Y+IMAGE[0]->getHeight(),IMAGE[3]->getWidth(),HEIGHT-IMAGE[0]->getHeight()-IMAGE[6]->getHeight()); \ \ g.setTiledImageFill(*IMAGE[5],X+WIDTH-IMAGE[5]->getWidth(),Y,1.0f); \ g.fillRect(X+WIDTH-IMAGE[5]->getWidth(),Y+IMAGE[2]->getHeight(),IMAGE[5]->getWidth(),HEIGHT-IMAGE[2]->getHeight()-IMAGE[8]->getHeight()); \ \ g.drawImageAt(IMAGE[0],X,Y); \ g.drawImageAt(IMAGE[2],X+WIDTH-IMAGE[2]->getWidth(),Y); \ g.drawImageAt(IMAGE[6],X,Y+HEIGHT-IMAGE[6]->getHeight()); \ g.drawImageAt(IMAGE[8],X+WIDTH-IMAGE[8]->getWidth(),Y+HEIGHT-IMAGE[8]->getHeight());


#16

And here’s an example of usage:

void FileTreeMain::paint (Graphics& g) { if (Background[0] != 0) { skinDrawSquare(Background,0,0,getWidth(),getHeight()); } }

Where Background is Image* Background[9];

Wk


#17

Here’s a Macro that will draw Transparent images, with an Opacity option:

[code]/*
Image* buttonIMAGE[9];

Starting from the Top-Left Corner. Its best that all images have the same size, or relative sizes.
0  1  2

3  4  5

6  7  8

*/
#define skinDrawSquare(IMAGE,X,Y,WIDTH,HEIGHT,OPACITY);

g.setTiledImageFill(*IMAGE[4],X+IMAGE[3]->getWidth(),Y+IMAGE[1]->getHeight(),OPACITY);
g.fillRect(X+IMAGE[3]->getWidth(),Y+IMAGE[1]->getHeight(),WIDTH-IMAGE[3]->getWidth()-IMAGE[5]->getWidth(),HEIGHT-IMAGE[1]->getHeight()-IMAGE[7]->getHeight());

g.setTiledImageFill(*IMAGE[1],X+IMAGE[0]->getWidth(),Y,OPACITY);
g.fillRect(X+IMAGE[0]->getWidth(),Y,WIDTH-IMAGE[0]->getWidth()-IMAGE[2]->getWidth(),IMAGE[1]->getHeight());

g.setTiledImageFill(*IMAGE[7],X+IMAGE[6]->getWidth(),Y+HEIGHT-IMAGE[7]->getHeight(),OPACITY);
g.fillRect(X+IMAGE[6]->getWidth(),Y+HEIGHT-IMAGE[7]->getHeight(),WIDTH-IMAGE[6]->getWidth()-IMAGE[8]->getWidth(),IMAGE[7]->getHeight());

g.setTiledImageFill(*IMAGE[3],X,Y+IMAGE[0]->getHeight(),OPACITY);
g.fillRect(X,Y+IMAGE[0]->getHeight(),IMAGE[3]->getWidth(),HEIGHT-IMAGE[0]->getHeight()-IMAGE[6]->getHeight());

g.setTiledImageFill(*IMAGE[5],X+WIDTH-IMAGE[5]->getWidth(),Y,OPACITY);
g.fillRect(X+WIDTH-IMAGE[5]->getWidth(),Y+IMAGE[2]->getHeight(),IMAGE[5]->getWidth(),HEIGHT-IMAGE[2]->getHeight()-IMAGE[8]->getHeight());

g.setTiledImageFill(*IMAGE[0],X,Y,OPACITY);
g.fillRect(X,Y,IMAGE[0]->getWidth(),IMAGE[0]->getHeight());

g.setTiledImageFill(*IMAGE[2],X+WIDTH-IMAGE[2]->getWidth(),Y,OPACITY);
g.fillRect(X+WIDTH-IMAGE[2]->getWidth(),Y,IMAGE[2]->getWidth(),IMAGE[2]->getHeight());

g.setTiledImageFill(*IMAGE[6],X,Y+HEIGHT-IMAGE[6]->getHeight(),OPACITY);
g.fillRect(X,Y+HEIGHT-IMAGE[6]->getHeight(),IMAGE[6]->getWidth(),IMAGE[6]->getHeight());

g.setTiledImageFill(*IMAGE[8],X+WIDTH-IMAGE[8]->getWidth(),Y+HEIGHT-IMAGE[8]->getHeight(),OPACITY);
g.fillRect(X+WIDTH-IMAGE[8]->getWidth(),Y+HEIGHT-IMAGE[8]->getHeight(),IMAGE[8]->getWidth(),IMAGE[8]->getHeight());[/code]


#18

out of curiosity, why a macro and not a static C function ?


#19

Ah, good question. Its just that I don’t know how I would do a static function for that. I’m pretty sure I could figure it out. :wink: Maybe someone could show to me how to do that? :mrgreen: I’m still learning, every day. :oops:

Wk


#20

Or a class that holds the images and has a “draw (Graphics& g)” method?