This site requires JavaScript, please enable it in your browser!
Greenfoot back
Duta
Duta wrote ...

2012/3/8

Efficiency

Duta Duta

2012/3/8

#
/**
 * Gives the worlds background image a gradient between 2 colors.
 * Example call to this: createGradientBGImage(Color.RED, Color.BLUE);
 * This requires "import java.awt.Color;" and must be in a class that
 * extends greenfoot.World
 */
private void createGradientBGImage(Color left, Color right)
{
	int width = getWidth(),
		height = getHeight(),
		leftMult,
		rightMult,
		r, g, b;
	GreenfootImage img = new GreenfootImage(width, height);
	for(int x = 0; x < width; x++)
	{
		leftMult = 255 - (x*255/width);
		rightMult = 255 - leftMult;
		r = ((left.getRed()  *leftMult) + (right.getRed()  *rightMult))/510;
		g = ((left.getGreen()*leftMult) + (right.getGreen()*rightMult))/510;
		b = ((left.getBlue() *leftMult) + (right.getBlue() *rightMult))/510;
		Color c = new Color(r, g, b);
		for(int y = 0; y < height; y++)
			img.setColorAt(x, y, c);
	}
	setBackground(img);
}
Is there any way I can improve on this method's efficiency? Its not that it really needs it, I'm just wondering.
Morran Morran

2012/3/8

#
Maybe if you don't go for a perfectly smooth gradient? Like maybe just breaking the screen up into 10 or 20 or "n" parts, and calculating the value for the whole part?
Duta Duta

2012/3/8

#
I guess so. I think I might run some tests and see how long it takes to execute (to see if its worth it). Also if anyone is thinking about acually using this, on lines 19 through 21 it should be "/255" instead of "/510". I'll also test if replacing the small for(y) loop with a drawLine() will make an impact on the speed.
Duta Duta

2012/3/9

#
//Changing:
for(int y = 0; y < height; y++)
    img.setColorAt(x, y, c);
//to
img.setColor(c);
img.drawLine(x, 0, x, height);
Doing the above yielded, to be honest, staggering results. My first test ran the method posted above 10000 times (with some modifications to record the time), and its average execution time was 7.160ms... Once I'd changed the for() to drawLine(), I ran exactly the same test, and the average execution time was brought down to 0.929ms. Wow. EDIT: Here's the code I ran (Each time I ran the method "test1"):
/**
 * Gives the worlds background image a gradient between 2 colors.
 * Example call to this: createGradientBGImage(Color.RED, Color.BLUE);
 * This requires "import java.awt.Color;" and must be in a class that
 * extends greenfoot.World
 */
private int createGradientBGImage(Color left, Color right)
{
	long time = System.currentTimeMillis();
	int width = getWidth(),
		height = getHeight(),
		leftMult,
		rightMult,
		r, g, b;
	GreenfootImage img = new GreenfootImage(width, height);
	for(int x = 0; x < width; x++)
	{
		leftMult = 255 - (x*255/width);
		rightMult = 255 - leftMult;
		r = ((left.getRed()  *leftMult) + (right.getRed()  *rightMult))/255;
		g = ((left.getGreen()*leftMult) + (right.getGreen()*rightMult))/255;
		b = ((left.getBlue() *leftMult) + (right.getBlue() *rightMult))/255;
		Color c = new Color(r, g, b);
		//for(int y = 0; y < height; y++)
		//	img.setColorAt(x, y, c);
		img.setColor(c);
		img.drawLine(x, 0, x, height);
	}
	setBackground(img);
	return (int)(System.currentTimeMillis() - time);
}

public void test1()
{
	List<Integer> times = new ArrayList<Integer>();
	for(int i = 0; i < 10000; i++)
		times.add(createGradientBGImage(randomColor(), randomColor()));
	double time = 0.0;
	for(int t : times) time += t;
	time /= times.size();
	String exeTime = "" + time;
	if(exeTime.length() > 5) exeTime = exeTime.substring(0, 5);
	System.out.println("createGradientBGImage(...) execution time: " + exeTime + "ms");
}

static private Color randomColor()
{
	return new Color(Greenfoot.getRandomNumber(255), Greenfoot.getRandomNumber(255), Greenfoot.getRandomNumber(255));
}
danpost danpost

2012/3/9

#
For one thing you could change lines 22 through 25 to
img.setColor(new Color(r, g, b));
img.drawLine(x,  0,  x, height);
taking care of a whole column of points in as much as one command, instead of iterating through a loop (width times). I do not know how your background looks after compiling, but I thought the results were pretty cool after I compiled a test scenario with a different way of producing the gradience. The code follows
GreenfootImage bg = new GreenfootImage(getWidth(), getHeight());
Color leftColor = Color.blue;
Color rightColor = Color.green;
for (int x = 0; x < getWidth(); x++)
{
    int alphaLeft = x * 255 / 600;
    int alphaRight = (getWidth() - 1 - x) * 255 / 600;
    GreenfootImage left = new GreenfootImage(1, getHeight());
    left.setColor(leftColor);
    left.fill();
    left.setTransparency(alphaLeft);
    GreenfootImage right = new GreenfootImage(1, getHeight());
    right.setColor(rightColor);
    right.fill();
    right.setTransparency(alphaRight);
    bg.drawImage(left, x, 0);
    bg.drawImage(right, x, 0);
}
setBackground(bg);
Duta Duta

2012/3/9

#
danpost wrote...
For one thing you could change lines 22 through 25 to
setColor(new Color(r, g, b));
img.drawLine(x,  0,  x, height);
taking care of a whole column of points in as much as one command, instead of iterating through a loop (width times). I do not know how your background looks after compiling, but I thought the results were pretty cool after I compiled a test scenario with a different way of producing the gradience. The code follows
GreenfootImage bg = new GreenfootImage(getWidth(), getHeight());
Color leftColor = Color.blue;
Color rightColor = Color.green;
for (int x = 0; x < getWidth(); x++)
{
    int alphaLeft = x * 255 / 600;
    int alphaRight = (getWidth() - 1 - x) * 255 / 600;
    GreenfootImage left = new GreenfootImage(1, getHeight());
    left.setColor(leftColor);
    left.fill();
    left.setTransparency(alphaLeft);
    GreenfootImage right = new GreenfootImage(1, getHeight());
    right.setColor(rightColor);
    right.fill();
    right.setTransparency(alphaRight);
    bg.drawImage(left, x, 0);
    bg.drawImage(right, x, 0);
}
setBackground(bg);
I'll put that code into greenfoot and have a play with it :) Also I guess when you started writing your post I hadn't posted either of my replies..?
danpost danpost

2012/3/9

#
Duta wrote...
Also I guess when you started writing your post I hadn't posted either of my replies..?
You are right! I probably should refresh before actually posting, 'cause most of that time went into testing my test scenario.
Duta Duta

2012/3/9

#
That's the difference between our methods
Duta Duta

2012/3/9

#
danpost wrote...
Duta wrote...
Also I guess when you started writing your post I hadn't posted either of my replies..?
You are right! I probably should refresh before actually posting, 'cause most of that time went into testing my test scenario.
I run into that problem a lot too, well, whenever I'm writing a long post that is. You're not the only one :)
danpost danpost

2012/3/9

#
Yeah, I thought so. Yours has more body in the middle, where mine is a bit more transparent (which I kinda like the looks of). Adjusting the trasparency range could produce the variants between the two.
danpost danpost

2012/3/9

#
How does mine stack up time-wise? I am guessing, maybe between 1.6 and 2.2.
Duta Duta

2012/3/9

#
I just ran the test on your method and it came out to an average time (remember all execution times are relative to my OS - they will be different in other circumstances) of 14.28ms. This, I assume, is because of all the layered transparencies (which was my original approach too). This isn't necessarily a bad thing, as this method is likely only to be called once in a running of a scenario so 13.3ms is neither here nor there in the scheme of things! As such it fundamentally comes down to which generated gradient you prefer the look of. EDIT: Then again, to really find out timings, if you ran the test on your computer aswell then it would be more reliable results than what it is currently (one machine being tested)
sp33dy sp33dy

2012/3/9

#
Haven't read all of the above, but will do at one stage. One thought. Have you thought about trying the Gradient fill that exists in the Graphics2D class? http://oreilly.com/catalog/java2d/chapter/ch04.html Ok, it means you'll have to access the actor's Graphics class, but it might be worth you comparing the speed at least? I'll have a read through this post later to see if there is anything I can throw in.
Duta Duta

2012/3/9

#
I'll give that link a read now - however this was mainly just as something to do - I mean sure using pre-created methods is great but I enjoy making stuff myself. I've never actually used (or even looked at the API of) Graphics2D, though I was aware it existed. I'll test the speed once I get home
sp33dy sp33dy

2012/3/9

#
Yep, I hear you Duta. I was just interested in the comparison. I've often been impressed with how fast some of the standard libraries are. In fact, I often wonder whether they are using special 'hidden' tricks.. :)
You need to login to post a reply.