Reputation: 779
I'm working on an application where I draw a circular progress indicator which slowly gets "filled", here you can see a couple of images. I'm using intermediate mode and I'm only drawing this circular shape by drawing the vertices at each frame update (see code below). When the circle fills up the border line between the white and gray is a bit flickery and I'm wondering how I can make it more smooth.
This is a concrete example, but in general I'm wondering how to get the smoothest motion even when using very simple lineair interpolation? When I look at the motion when I flip between pages on my iphone it's just so extremelly smooth which makes me wonder how I would achieve this on my (fast) mac?
Thanks
Roxlu
PhotoBoothCountdown::PhotoBoothCountdown(float fMillisDuration)
:duration(fMillisDuration)
,start_time(0)
{
setActionCommand("take_picture");
}
void PhotoBoothCountdown::update() {
if(start_time != 0) {
float cur = ofGetElapsedTimeMillis();
perc = (cur-start_time)/duration;
}
}
void PhotoBoothCountdown::draw() {
float resolution = 150;
int parts_filled = resolution * perc;
int parts_unfilled = (resolution - parts_filled);
float part_angle = TWO_PI/resolution;
//printf("filled: %i/%i/%i\n", parts_filled, parts_unfilled, (parts_filled+parts_unfilled));
float radius = 300.0f;
float width = 100;
float radius_inner = radius-width;
float center_x = ofGetWidth()/2;
float center_y = ofGetHeight()/2;
float angle = 0;
glBegin(GL_TRIANGLE_STRIP);
glColor4f(0.2f, 0.2f, 0.2f,0.9f);
for(int i = 0; i <= parts_filled; ++i) {
float cosa = cos(angle);
float sina = sin(angle);
glVertex2f(center_x + cosa * radius,center_y + sina * radius);
glVertex2f(center_x + cosa * radius_inner,center_y + sina * radius_inner);
angle += part_angle;
}
glEnd();
glBegin(GL_TRIANGLE_STRIP);
glColor4f(1.0f, 1.0f, 1.0f,0.9f);
angle -= part_angle;
for(int i = 0; i <= parts_unfilled; ++i) {
float cosa = cos(angle);
float sina = sin(angle);
glVertex2f(center_x + cosa * radius,center_y + sina * radius);
glVertex2f(center_x + cosa * radius_inner,center_y + sina * radius_inner);
angle += part_angle;
}
glEnd();
if(perc >= 1) {
printf("should fire");
fireEvent();
reset();
}
}
void PhotoBoothCountdown::start() {
start_time = ofGetElapsedTimeMillis();
end_time = start_time + duration;
}
void PhotoBoothCountdown::reset() {
start_time = 0;
end_time = 0;
perc = 0;
}
Upvotes: 0
Views: 3923
Reputation: 8783
The first thing I would do would be to simply draw a single circle, and store it in a display list (you could go for buffer objects, but none of the rest of this advice depends on that, and you're in immediate mode, so we'll stick with the simplest improvement). Draw your divided up circle, putting texture coordinates on each one that corresponds to the percent completion there. Apply a shader which is mostly boring, but has a uniform for the completeness; triangles with their texture coordinates <= that completeness get lit up. The rest stay grey. Then your drawing consists of setting the uniform, and calling the display list. Much faster.
Upvotes: 0
Reputation: 8733
It's hard to guess what you are asking about - a flickery, aliasing, smooth motion or drawing artifacts. Free thoughts after looking at your code
You assume that if float part_angle = TWO_PI/resolution;
then by summing up (angle += part_angle
) resolution
times you'll get TWO_PI
. Unfortunatelly this isn't true in floating point arithmetics. Also sin(TWO_PI) cos(TWO_PI) will not neccessarily return precise 0.0
and 1.0
values.
To improve drawing precission I would draw full grey circle and then a white one over it as neccessary. This would bring full grey circle at 100%
int parts_filled = resolution * perc;
. You can convert your percentage countdown so that it will use integral types or at least test it by printing out percent value and check out if it ever reaches 100%.Upvotes: 0