Processing doesn't draw complete curves using while loop - loops

I'm investigating possibilities that Processing gives regarding generative art, and I stumbled upon a problem:
I'd like to generate multiple Bezier curves using a while loop. However, the program skips parts of some curves, while others are drawn properly.
Here's a working example:
void setup() {
size(1000,500);
background(#ffffff);
}
float[] i_x = {1,1};
float[] i_y = {1,1};
void draw() {
while (i_y[0] < height)
{
bezier(0,i_y[0],100,height-100,width - 100,height-100,width, i_y[0]);
i_y[0] = i_y[0] * 1.1;
}
save("bezier.jpg");
}
And here is the output. As you can see, only few of the curves are drawn in their full shape.
Also, when I draw one of the 'broken' curves out of the loop, it works fine.
I'd appreciate any help. I'm having good time learning coding concepts with visual output that Processing provides.

It works as intended. Look what happens when you change the background color (great post btw, the working example made it good enough for me to want to debug it!):
If you're clever, you'll notice that the "inside" of the curve has a color. Except that for now it's white. That's why only the topmost are "invisible": you're drawing them one after the other, starting topmost, so every new curve eats the last one by painting over it, but only "inside the curve". See what happens when I apply some color to differentiate the fill and the background better:
Now that the problem is obvious, here's the answer: transparency.
while (y < height)
{
fill(0, 0, 0, 0); // this is the important line, you can keep your algo for the rest
bezier(0, y, offset, height-offset, width - offset, height-offset, width, y);
y *= 1.1;
}
Which gives us this result:
Have fun!

Related

Coloring only one color of bitmap in Allegro 5

I'm making a project in C, with Allegro 5 library. I got some skins for my snake, but I want to make something better, like user-styled skin. And I think the best way will be:
Make a white snake as that in image in post.
Color white to another color.
And now I'm looking for Allegro function to make it fast and easy.
What I got:
al_tinted_bitmap - it's also coloring eyes and tongue
al_get_pixel, put_pixel - but I must give x/y of white color, and that's really hard with bitmap like that (i mean... with square it will be easier)
So I think, I need a function or something like "get_pixel", but with specifying rgb(R, G, B), not X/Y.
What's should I try used to make it functional like that?
bitmap of snake
This question led to a nice discussion on the allegro forums Credits to Dizzy Egg for working out this example in full detail. I'll summarize the answer here for future reference.
A solution with al_tinted_bitmap is definitely possible, but I'd choose the get_pixel / put_pixel approach as you have a bit more control. It's not hard to replace pixels of one color with pixels of another color. Just loop over each pixel in the bitmap and do this:
color = al_get_pixel(snake_white, x, y);
if(color.r == 1.0 && color.g == 1.0 && color.b == 1.0) {
al_put_pixel(x, y, al_map_rgb(50, 255, 50)); //Choose your own colour!
}
else {
al_put_pixel(x, y, color);
}
The problem in this case is that you don't have just one color (white) but also shades of grey, due to anti-aliasing on the outlines of the snake. So what we can do instead, is check each pixel if the r, g, and b component are all non-zero. If they're all non-zero, then it's neither black, nor red (the tongue) nor yellow (the eyes). Then we multiply the grey-values with r,g,b components of our own choosing.
color = al_get_pixel(snake_white, x, y);
if(color.r >= 0.01 && color.g >= 0.01 && color.b >= 0.01) {
al_put_pixel(x, y, al_map_rgba_f(new_color.r * color.r, new_color.g * color.g, new_color.b * color.b, color.a));
}
else {
al_put_pixel(x, y, color);
}
You could make it smarter in a lot of ways, but it works well for the snake image. See the linked forum thread for the full code.

Get texture coordinates of mouse position in SDL2?

I have the strict requirement to have a texture with resolution (let's say) of 512x512, always (even if the window is bigger, and SDL basically scales the texture for me, on rendering). This is because it's an emulator of a classic old computer assuming a fixed texture, I can't rewrite the code to adopt multiple texture sizes and/or texture ratios dynamically.
I use SDL_RenderSetLogicalSize() for the purpose I've described above.
Surely, when this is rendered into a window, I can get the mouse coordinates (window relative), and I can "scale" back to the texture position with getting the real window size (since the window can be resized).
However, there is a big problem here. As soon as window width:height ratio is not the same as the texture's ratio (for example in full screen mode, since the ratio of modern displays would not match of the ratio I want to use), there are "black bars" at the sides or top/bottom. Which is nice, since I want always the same texture ratio, fixed, and SDL does it for me, etc. However I cannot find a way to ask SDL where is my texture rendered exactly inside the window based on the fixed ratio I forced. Since I need the position within the texture only, and the exact texture origin is placed by SDL itself, not by me.
Surely, I can write some code to figure out how those "black bars" would change the origin of the texture, but I can hope there is a more simple and elegant way to "ask" SDL about this, since surely it has the code to position my texture somewhere, so I can re-use that information.
My very ugly (can be optimized, and floating point math can be avoided I think, but as the first try ...) solution:
static void get_mouse_texture_coords ( int x, int y )
{
int win_x_size, win_y_size;
SDL_GetWindowSize(sdl_win, &win_x_size, &win_y_size);
// I don't know if there is more sane way for this ...
// But we must figure out where is the texture within the window,
// which can be changed since the fixed ratio versus the window ratio (especially in full screen mode)
double aspect_tex = (double)SCREEN_W / (double)SCREEN_H;
double aspect_win = (double)win_x_size / (double)win_y_size;
if (aspect_win >= aspect_tex) {
// side ratio correction bars must be taken account
double zoom_factor = (double)win_y_size / (double)SCREEN_H;
int bar_size = win_x_size - (int)((double)SCREEN_W * zoom_factor);
mouse_x = (x - bar_size / 2) / zoom_factor;
mouse_y = y / zoom_factor;
} else {
// top-bottom ratio correction bars must be taken account
double zoom_factor = (double)win_x_size / (double)SCREEN_W;
int bar_size = win_y_size - (int)((double)SCREEN_H * zoom_factor);
mouse_x = x / zoom_factor;
mouse_y = (y - bar_size / 2) / zoom_factor;
}
}
Where SCREEN_W and SCREEN_H are the dimensions of the my texture, quite misleading by names, but anyway. Input parameters x and y are the window-relative mouse position (reported by SDL). mouse_x and mouse_y are the result, the texture based coordinates. This seems to work nicely. However, is there any sane solution or a better one?
The code which calls the function above is in my event handler loop (which I call regularly, of course), something like this:
void handle_sdl_events ( void ) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_MOUSEMOTION:
get_mouse_texture_coords(event.motion.x, event.motion.y);
break;
[...]

cairo / xlib not updating window content

I am trying to learn how to use Cairo 2D drawing library with xlib surfaces.
I wrote a little test program that allows creating multiple windows. Each function may have a custom paint() function that is called regularly to add some graphics content to the window, or redraw it completely if desired. There is also an option to define mouse and key listener. The main routine checks for X events (to delegate them to mouse and key listener) and for timeout for periodic call of those paint() functions.
I tried with the 1.14.6 version of Cairo (that is currently available as package in Ubuntu 16.04), and the latest 1.15.12, but the results are the same.
The expected behavior of this demo is to open 3 windows. One will have random rectangles being added, another one random texts, and the third random circles.
In addition, clicking into windows should produce lines (connecting to mouse click, or randomly), and using arrow keys should draw a red line in the window with circles.
The circles and text seem to show up regularly as expected. All three windows should have white background, but two of them are black. And the worst, the window with rectangles does not get updated much (and it does not matter if it is the first window created or not, it is always the rectangles that do not show up properly).
They are only shown when the focus changes to or from that window - then the remaining rectangles that should have been drawn meanwhile suddenly appear.
I am calling cairo_surface_flush() on the surface of each window after adding any content, but that does not help. I also tried posting XEvents to that window of various kind (such as focus), they arrive, but rectangles do not show up.
Furthermore, even though drawing lines with mouse works fine, drawing line with key arrows suffers from the same problem - it is drawn, but not shown properly.
I am obviously wrong in some of my assumptions about what this library can do, but I am not sure where.
It seems that there are some two competing versions of drawing being shown, since it happens sometimes that one or two rectangles, or pieces of the red line are flashing. Some kind of strange buffering, caching?
It may just be some bug in my program, I do not know.
Another observation - the black background is because drawing white background happens before the window is shown, and thus those cairo_paint calls are somehow discarded. I do not know how to make the window appear earlier, it seems it appears only after some later changes on the screen.
I am stuck on this after a couple of desperate days, could you help me out at least in part, please?
The program is here: test_cairo.c
An example screenshot (with a broken red line drawn by keys, and rectangles not showing up properly): test_cairo.png
To compile (on Ubuntu 16.04 or similar system):
gcc -o test_cairo test_cairo.c -I/usr/include/cairo -lX11 -lcairo
X11 does not retain window content for you. When you get an Expose event, you have to repaint the area described by that event completely.
All three windows should have white background, but two of them are black.
You create your window with XCreateSimpleWindow, so their background attribute is set to black. The X11 server will fill exposed areas with black for you before sending an expose event. Since you do not tell cairo to draw a white background, the black stays.
Try this:
--- test_cairo.c.orig 2018-07-28 09:53:10.000000000 +0200
+++ test_cairo.c 2018-07-29 10:52:43.268867754 +0200
## -63,6 +63,7 ## static gui_mouse_callback mouse_callback
static cairo_t *windows[MAX_GUI_WINDOWS_COUNT];
static cairo_surface_t *surfaces[MAX_GUI_WINDOWS_COUNT];
+static cairo_surface_t *real_surfaces[MAX_GUI_WINDOWS_COUNT];
static Window x11windows[MAX_GUI_WINDOWS_COUNT];
static char *window_names[MAX_GUI_WINDOWS_COUNT];
## -79,7 +80,12 ## long long usec()
void repaint_window(int window_handle)
{
draw_callbacks[window_handle](windows[window_handle]);
- cairo_surface_flush(surfaces[window_handle]);
+
+ cairo_t *cr = cairo_create(real_surfaces[window_handle]);
+ cairo_set_source_surface(cr, surfaces[window_handle], 0, 0);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+ cairo_surface_flush(real_surfaces[window_handle]);
}
int gui_cairo_check_event(int *xclick, int *yclick, int *win)
## -149,7 +155,6 ## void draw_windows_title(int window_handl
sprintf(fullname, "Mikes - %d - [%s]", window_handle, context_names[current_context]);
else
sprintf(fullname, "Mikes - %s - [%s]", window_names[window_handle], context_names[current_context]);
- cairo_surface_flush(surfaces[window_handle]);
XStoreName(dsp, x11windows[window_handle], fullname);
}
## -179,20 +184,17 ## int gui_open_window(gui_draw_callback pa
}
if (window_handle < 0) return -1;
- surfaces[window_handle] = gui_cairo_create_x11_surface(&width, &height, window_handle);
+ real_surfaces[window_handle] = gui_cairo_create_x11_surface(&width, &height, window_handle);
+ surfaces[window_handle] = cairo_surface_create_similar(real_surfaces[window_handle], CAIRO_CONTENT_COLOR, width, height);
windows[window_handle] = cairo_create(surfaces[window_handle]);
mouse_callbacks[window_handle] = 0;
draw_callbacks[window_handle] = paint;
window_update_periods[window_handle] = update_period_in_ms;
window_names[window_handle] = 0;
-
- cairo_surface_flush(surfaces[window_handle]);
cairo_set_source_rgb(windows[window_handle], 1, 1, 1);
cairo_paint(windows[window_handle]);
-
- cairo_surface_flush(surfaces[window_handle]);
draw_callbacks[window_handle](windows[window_handle]);
## -201,7 +203,6 ## int gui_open_window(gui_draw_callback pa
else next_window_update[window_handle] = 0;
draw_windows_title(window_handle);
- cairo_surface_flush(surfaces[window_handle]);
window_in_use[window_handle] = 1;
return window_handle;
## -213,6 +214,7 ## void gui_close_window(int window_handle)
cairo_destroy(windows[window_handle]);
cairo_surface_destroy(surfaces[window_handle]);
+ cairo_surface_destroy(real_surfaces[window_handle]);
window_in_use[window_handle] = 0;
int no_more_windows = 1;
for (int i = 0; i < MAX_GUI_WINDOWS_COUNT; i++)

Why doesn't this code draw a triangle?

I'm very new to OpenGL and I just wrote up a section of code using SDL 2 that to my knowledge should have drawn a triangle, but this code doesn't seem to work and so I am not done learning. I've got all the initialization code SDL 2 documentation says I need already written in, and the functions returned by dynamic loading ARE callable. When I execute this code instead of a triangle I get a black (but cleared) window. Why does this code not draw the triangle I want, and why is the window cleared to black by this code? I want to know the technical details behind mainly the first question so I can depend on it later.
(*main_context.glViewport)(0, 0, 100, 100);
(*main_context.glBegin)(GL_TRIANGLES);
(*main_context.glColor4d)(255, 255, 255, 255);
(*main_context.glVertex3d)(1, 1, -50);
(*main_context.glVertex3d)(1, 30, 1);
(*main_context.glVertex3d)(30, 1, 1);
(*main_context.glEnd)();
(*main_context.glFinish)();
(*main_context.glFlush)();
SDL_GL_SwapWindow(window);
Update:
I've revised my code to include different coordinates and I got the triangle to draw, but I cannot get it to draw when farther away. Why is that?
(*main_context.glVertex3d)(2, -1, 1); /* Works. */
(*main_context.glVertex3d)(2, -1, 3); /* Doesn't work. */
Unless you are setting up a projection and/or modelview matrix elsewhere in your code, it's using the default (identity matrix) transform, which is an orthographic projection with (-1, -1) at the bottom left and (1, 1) at the top right. glViewport only changes the portion of the default framebuffer being rendered to, it has no bearing on the projection whatsoever.
With an orthographic projection, the Z coordinate does not affect the screen-space position of a point, except that points outside the Z clipping planes will not be rendered. In this case, that's everything outside of -1 <= z <= 1. Given that one of your points is (1, 1, -50), this seems to be your problem.

OpenGL - maintaining aspect ratio upon window resize

I am drawing a polygon in a square window. When I resize the window, for instance by fullscreening, the aspect ratio is disturbed. From a reference I found one way of preserving the aspect ratio. Here is the code:
void reshape (int width, int height) {
float cx, halfWidth = width*0.5f;
float aspect = (float)width/(float)height;
glViewport (0, 0, (GLsizei) width, (GLsizei) height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(cx-halfWidth*aspect, cx+halfWidth*aspect, bottom, top, zNear, zFar);
glMatrixMode (GL_MODELVIEW);
}
Here, cx is the eye space center of the zNear plane in X. I request if someone could please explain how could I calculate this. I believe this should be the average of the initial first two arguments to glFrustum(). Am I right? Any help will be greatly appreciated.
It looks like what you want to do is maintain the field of view or angle of view when the aspect ratio changes. See the section titled 9.085 How can I make a call to glFrustum() that matches my call to gluPerspective()? of the OpenGL FAQ for details on how to do that. Here's the short version:
fov*0.5 = arctan ((top-bottom)*0.5 / near)
top = tan(fov*0.5) * near
bottom = -top
left = aspect * bottom
right = aspect * top
See the link for details.
The first two arguments are the X coordinates of the left and right clipping planes in eye space. Unless you are doing off-axis tricks (for example, to display uncentered projections across multiple monitors), left and right should have the same magnitude and opposite sign. Which would make your cx variable zero.
If you are having trouble understanding glFrustrum, you can always use gluPerspective instead, which has a somewhat simplified interface.

Resources