Cairo multiple shapes in drawing area - c

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.

Related

Draw curves to make arrows in the Codename One GlassPane

In a CodenameOne App, I need to draw curved arrows in the GlassPane. The use of the GlassPane is not mandatory, however I've already used some layers in the ContentPane and some layers in the LayeredPane, so I suppose that the GlassPane is the best option to be sure that the arrows are "over" the app.
The arrows should be like the following ones:
I suppose that I can create an algorithm that decides the absolute X and Y coordinates of the "Start" and "End" points, more other few points (P0, P1, P2, etc.), that describes the curves. For example:
My problem is that I don't know how to do it. Usually I don't need low-level drawing in a Codename One app like in this case. Could you please show me a correct and complete code to do this drawing (assuming to know the coordinates of Start, End, P0, P1, etc.)? Thank you.
This is a bit hard to do by hand. I would suggest using SVG to draw an arrow like this by using a tool such as Sketch or a similar vector graphics tool. Then using flamingo to convert it to an image: https://www.codenameone.com/blog/flamingo-svg-transcoder.html
Alternatively you can handcode it with a GeneralPath e.g.:
GeneralPath gp = new GeneralPath();
// move to start of path
gp.move(x, y);
// draw the curve of the arrow, we use a control point around which
// the curve is drawn and curve to the destination of the line
gp.curveTo(contolX, controlY, destX, destY);
// Stroke defines how the shape is drawn it accepts the line width
// cap style, join style and miter limit
Stroke st = new Stroke(2, Stroke.CAP_SQUARE, Stroke.JOIN_MITER, 1);
// red
graphics.setColor(0xff00000);
// now we can draw the shape
graphics.drawShape(gp, st);

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...

Make objects move in Cairo

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.

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