Make objects move in Cairo - c

I need to use Cairo to make geometric formulas move through the screen.
How does one "move" objects (like circles) in Cairo? I did try cairo_translate(cr, x, y) function but it seems to change the referential for all the objects and I don't know how to produce de "movement". In other frameworks I would increment the x value and change the speed with an appropriate clock() function to control FPS's, then I would paint the drawing area background and draw the object with new coordinates.
But I don't know how to produce this with Cairo and all documentation I can find does not mention how this is done.
This is the code I have:
genRandVector(numOfBalls);
/* creates big ball */
cairo_set_line_width(cr, 5);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_arc(cr, balls_MAP[0].x, balls_MAP[0].y, CONF.big_rad, 0, 2 * M_PI);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
cairo_fill(cr);
/* creates other balls */
int i;
cairo_close_path(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
for(i = 1; i < numOfBalls; i++) {
cairo_arc(cr, balls_MAP[i].x, balls_MAP[i].y, CONF.small_rad, 0, 2 * M_PI);
cairo_stroke_preserve(cr);
cairo_fill(cr);
cairo_close_path(cr);
}
And my circles are still. I would like to make all of them move randomly. I just don't know how to make them "move".

cairo doesn't animate things, and it doesn't have the concept of objects. Using cairo is more like using a paintbrush on a canvas: once you draw something onto the canvas, it's stuck there and you can't refer to it to change its properties at all, let alone move it around.
Therefore, to animate things drawn with cairo, you have to wipe the part of the canvas that's being animated and draw it again. How to do that depends on what toolkit you are using to display your graphics.
From the tags, I assume you are using GTK+. There are several methods of GtkWidget, such as gtk_widget_queue_draw() and gtk_widget_queue_draw_area(), that will schedule a redraw of your widget. Call this in a g_timeout_add() handler to schedule your animation. You'll get a drawing signal (the same one you're using already) for the portion of the GtkWidget that you chose to redraw (which you can get from within the draw handler with cairo_clip_extents()). Since the relevant portion of the canvas will be blanked already when you enter the draw handler, you can just start drawing your next frame.
You may wish to consider using a dedicated animation framework instead if your needs are sufficiently complicated. Clutter is one specifically designed to be used with GTK+, but there are also others.

Related

Stroke alignment in Cairo

Many graphics packages allow the user to select where they would like to draw the border of a region around a shape; either along the inside, outside or centre of the shape. For example, this shows the same square with the border drawn along the centre, inside and outside respectively:
I could scale the path up/down based on the stroke's width, but I wanted to check if there was built-in support for this first.
I'm using Ruby, but if there's a C method for this, it's likely available in the Ruby bindings as well.
Is there a method to draw a stroke around the outside or inside of a path, rather than along the centre, in Cairo?
No, there is no such method built-in.
One could likely approximate this with a temporary surface that is later used as a mask. For example, to do "outside", you first fill a temporary surface with "transparent", then stroke with twice your desired line width some "opaque", and finally fill the shape with "transparent" to get rid of the inner part of the line width. The resulting surface can then be used as a mask.
"Inside" would be similar, but with an extra trick: Again, transparent surface and stroke with twice the line width. Now the outside part of this stroke needs to be removed. For this, one needs a path with a winding rule of even-odd. Add a surface-sized rectangle to this path inverts the path, thus allowing to remove everything outside via a fill.
For a non-zero winding rule... I do not have any immediate ideas (well, another temporary surface that is then inverted via a full-surface-paint with operator SUBTRACT?).
Sample code for drawing outside of the path (see comments):
static void draw_outside_of_path(cairo_t *cr) {
double line_width = cairo_get_line_width(cr);
cairo_pattern_t *mask;
cairo_push_group_with_content(cr, CAIRO_CONTENT_ALPHA);
cairo_set_line_width(cr, 2 * line_width);
cairo_set_source_rgba(cr, 0, 0, 0, 1);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_stroke_preserve(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_fill_preserve(cr);
mask = cairo_pop_group(cr);
cairo_mask(cr, mask);
cairo_pattern_destroy(mask);
}
For stroking inside a path, set the path as a clipping region, then stroke the path; any part of stroke that lies outside the clipping region will be unseen...

Cairo multiple shapes in drawing area

I'm trying to understand Cairo framework; but I don't know how to put more than one shape into the drawing area. All codes/tutorials I've seen are either too advanced or do not relate to this issue.
This is my code to draw a circle (I'm using C and gtk+3.0):
void draw(GtkWidget *this, cairo_t *cr, gpointer data) {
cairo_set_line_width(cr, 5);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_translate(cr, prog.width/2, prog.height/2);
cairo_arc(cr, 0, 0, 50, 0, 2 * M_PI);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
cairo_fill(cr);
}
I understand all but one thing: cairo_t *cr. From what I've been searching cr is a Context, but didn't quite grasped an intuitive idea of what it is about (maybe my question lies on this understanding?).
So, if I needed more circles near this one, how could I create them?
My try was using cairo_move_to(cr, x, y) and draw another shape but obviously it didn't work.
Thanks!
Yes, cairo_t is the type of a cairo context.
To draw on cairo, you set drawing parameters, a source which defines the color or image that gets drawn, and a path that specifies the shape that gets drawn, and then you call cairo_stroke() or cairo_fill() to do the actual drawing. After calling those, the path is reset (unless you use the _preserve versions of the functions), but everything else stays the same.
So to draw again, you just need to add more setup and drawing function calls after the first one.
cairo_move_to() does not actually move anything. What cairo_move_to() does is change the position of the "current point" of the path. Path components you add later, such as cairo_line_to(), will start at the current point and then set the current point to their end point.
In your case, you can draw multiple circles by adding a cairo_move_to() after the last line of your draw handler and then repeating the steps you used to draw the first circle.
cairo_arc() is different because you specify the center of the arc as the second and third arguments. To draw an arc somewhere else, you need to change those two arguments. (The current point does play a role in cairo_arc(); you'll need to see the documentation for information.)
The cairo documentation is the best place to start learning about cairo; it has lots of tutorials and samples.

Opengl Lighting and Normals

I'm currently experimenting with opengl and glut.
As i have like no idea what i'm doing i totally mess up with the lighting.
The complete compilable file can be found here: main.c
I have a display loop which currently operates like following:
glutDisplayFunc(also idle func):
glClear GL_COLOR_BUFFER_BIT and GL_DEPTH_BUFFER_BIT
switch to modelview matrix
load identity
first Rotate and then Translate according to my keyboard and mouse inputs for the camera
draw a ground with glNormal 0,1,0 and glMaterial on front and back,
which is encapsulated by push/popmatrix
pushmatrix
translate
glutSolidTeapod
popmatrix
do lighting related things, glEnable GL_LIGHTING and LIGHT0 and passing
float pos[] = {0.1,0.1,-0.1,0.1};
glLightfv( GL_LIGHT0, GL_POSITION, pos );
swap the buffers
the function associated with
glutReshapeFunc operates(this is from the lighthouse3d.com glut tutorial):
calculate the ratio of the screen
switch to projection matrix
loadidentity
set the viewport
set the perspective
switch to modelview matrix
However this all seems to work somehow,
but as i enable lighting, the normals seem to totally mess up.
My GL_LIGHT0 seems to stay as it should, as i can see the lightspot on the ground
not moving, as i move around
And the Teapods texture seem to move if i move my camera,
the teapod itself stands still.
Here is some visual material to explain it,
i apologize for my bad english : /
Link to YouTube video describing visually
You have a series of mistakes in your code:
You don't properly set the properties of your OpenGL window:
glutCreateWindow (WINTITLE);
glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
The glutInitDisplayMode will only affect any windows you create after that. You should swap those two lines.
You never enable the depth test. You should add glEnable(GL_DEPTH_TEST) after you created the windows. Not using the depth test expalins the weird "see-through" effect you get with the teapot.
You have the following code
glEnable (GL_CULL_FACE | GL_CULL_FACE_MODE);
This is wrong in two ways: the GLenums are not single bits, but just values. You cannot OR them together and expect anything useful to happen. I don't know if this particular call will enable something you don't expect or just generate an error.
The second issue here is that GL_CULL_FACE_MODE isn't even a valid enum to enable.
In your case, you either skip the CULL_FACE completely, or you should write
glEnable (GL_CULL_FACE);
glFrontFace(GL_CW);
The latter call changes the face orientation from OpenGL's default counterclokcwise rule to the clockwise one, as the GLUT teapot is defined that way. Interestingly, your floor is also drawn following that rule, so it will fit for your whole scene. At least for now.
You have not fully understood how GL's state machine works. You draw the scene and then set the lighting. But this will not have an effect on the already drawn objects. It just affects the next time you draw something, which will be in the next frame here. Now, the lighting of the fixed function pipeline works in eye space. That means that if you want a light source which is located at a fixed position in the world, and not in a fixed position relativ to the camera, you have to re-specify the light position, with the updated modelview matrix, everytime the camera moves. In your case, the light source will lag behind one frame when the camera moves. This is probably not noticeable, but still wrong in principle. You should reorder your display() function to
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
control (WALKSPEED, MOUSESPEED, mousein);
lightHandler();
drawhelpgrid(1, 20);
drawTeapod();
glutSwapBuffers();
With those changes, I can actually get the expected result of a lighted teapot on my system. But as I side note I feel obligded to warn you that almost all of your code relies on deprecated features of OpenGL. This stuff has been removed from modern versions of OpenGL. If you start learning OpenGL now, you should consider learning the modern programmable pipeline, and not some decades old obsolete stuff.

Draw pixel in C

I'm trying to draw triangle in C using opengl but without standard opengl functions for drawing triangles and lines. (I use ubuntu.)
I used Bresenham line drawing algoritm. I suppose, that the code of this algorithm itself is fine, because it draws tringle but it look like on following picture.
And I need to make it look like this
In the line drawing algorithm I draw the line pixel by pixel using following function:
void setPixel(int x, int y) {
glBegin(GL_POINTS);
glVertex2i(x,y);
glEnd();
glFlush();
}
Could you help me with the following? :
Why aren't the lines smooth?
Why is there a space between pixels?
Why aren't the lines thinner?
You may want to change point size with
glPointSize(1.0f); // or similar value
before glBegin call.
As stated by #Nemanja Boric, points aren't simple pixels.
One does usually draw such squares using glBegin(GL_QUADS), since the point size is limited.
If this is not a line drawing exercise, use glBegin(GL_LINE_LOOP);
glEnable(GL_LINE_SMOOTH); for smooth lines
glLineWidth(); to adjust the line width. However, with GL_LINE_SMOOTH enabled, the line looks thinner because of antialiasing.
First of all, do not use point primitives to represent pixels. If you have anti-aliasing enabled (GL_MULTISAMPLE or the older GL_POINT_SMOOTH), then they are not actually rectangular in nature.
Since you are using an older version of OpenGL here, you still have direct access to raster functions. That is, you can skip primitive assembly and draw relative to glRasterPos2i (...). glWindowPos2i (...) will even skip coordinate transform and let you draw directly in window coordinates without messing with projection/modelview matrices (assuming you have an OpenGL 1.4+ implementation).
Here is how you could accomplish the same thing as in your sample code:
void setPixel(int x, int y) {
const GLubyte color [] = { 255, 255, 255, 255 };
glWindowPos2i (x, y);
glDrawPixels (1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
glFlush();
}
If you don't have access to glWindowPos2i, then use an orthographic projection matrix equal to your window's dimensions and an identity modelview matrix and replace glWindowPos2i (...) with glRasterPos2i (...).
Neither solution will be high-performance, but at least you will not have to worry about things like point size, depth tests, etc.

OpenGL total beginner and 2D animation project?

I have installed GLUT and Visual Studio 2010 and found some tutorials on OpenGL basics (www.opengl-tutorial.org) and 2D graphics programming. I have advanced knowledge in C but no expirience with graphics programming...
For project (astronomy - time scales) , i must create one object in center of window and make other 5 objects (circles,dots...) to rotate around centered object with respect to some equations (i can implement them and solve). Equations is for calculating coordinates of that 5 objects and all of equations have parameter t (as time). For creating animation i will vary parameter t from 0 to 2pi with some step and get coordinates in different moments. If task was to print new coordinates of objects it would be easy to me but problem is how to make animation of graphics. Can i use some functions of OpenGL for rotation/translation ? How to make an object to move to desired location with coordinates determined by equation? Or i can redraw object in new coordinates every millisecond? First thing i thought was to draw all objects, calculate new coordinates, clear screen and draw all objects in new coordinates and repeat that infinitely..(it would be primitive but will work?)
Here is screen shot of that objects - http://i.snag.gy/ht7tG.jpg . My question is how to make animation by calculating new coordinates of objects each step and moving them to new location. Can i do that with basics in OpenGL and good knowledge of C and geometry? Any ideas from what to start? Thanks
Or i can redraw object in new coordinates every millisecond? First
thing i thought was to draw all objects, calculate new coordinates,
clear screen and draw all objects in new coordinates and repeat that
infinitely..
This is indeed the way to go. I would further suggest that you don't bother with shaders and vertex buffers as is the OpenGL 3/4 way. What would be easiest is called "immediate mode", deprecated by OpenGL 3/4 but available in 1/2/3. It's easy:
glPushMatrix(); //save modelview matrix
glTranslatef(obj->x, obj->y, obj->z); //move origin to object center
glBegin(GL_TRIANGLES); //start drawing triangles
glColor3f(1.0f, 0.0f, 0.0f); //a nice red one
glVertex3f(0.0, +0.6f, 0.0f);
glVertex3f(-0.4f, 0.0f, 0.0f);
glVertex3f(+0.4f, 0.0f, 0.0f); //almost equilateral
glEnd();
glPopMatrix(); //restore modelview matrix/origin
Do look into helper libraries glu (useful for setting up the camera / the projection matrix) and glut (should make it very easy to set up a window and basic controls and drawing).
It would probably take you longer to set it up (display a rotating triangle) than to figure out how to use it. In fact, here's some code to help you get started. Your first challenge could be to set up a 2D orthogonal projection matrix that projects along the Z-axis, so you can use the 2D functions (glVertex2).
First thing i thought was to draw all objects, calculate new coordinates, clear screen and draw all objects in new coordinates and repeat that infinitely..(it would be primitive but will work?)
That's exactly how it works. With GLUT, you set a display function that gets called when GLUT thinks it's time to draw a new frame. In this function, clear the screen, draw the objects and flush it to the screen. Then just instruct GLUT to draw another frame, and you're animating!
Might want to keep track of the time inbetween frames so you can animate things smoothly, but I'm sure you can figure that part out.
OpenGL is really just a drawing library. It doesn't do animation, that's up to you to implement. Clear/draw/flush is the commonly used approach for it though.
Note: with 'flush' I mean glFlush(), although GLUT in multi-buffer mode requires glutSwapBuffers()
The red book explains the proper way to draw models that can first be translated, rotated, scaled and so on: http://www.glprogramming.com/red/chapter03.html
Basically, you load the identity, perform transforms/rotations/scales (which one you want first matters - again the book explains it), draw the model as though it was at the origin at normal scale and it'll be placed in its new position. Then you can load identity and proceed with the next one. Every frame of an animation, you glClear() and recalculate/redraw everything. (It sounds expensive, but there's usually not much you can cache between draws).

Resources