Reputation: 930
I am making an application on Linux with GCC in which I've been loading my pictures from disk with PngLIB for some time now. I jumped from the standard xlib to the Xrender extension in order to make use of the anti-aliasing and alpha channel properties offered by this extension.
However, this extension offers a reduced set of primitives. In order to, for example, display a picture loaded from disk, I've been loading it with pnglib, and then make a call to XRenderFillRectangle, with the width and height of 1 pixel and the desired color for that pixel. However, as I increase the number of icons and pictures loaded from disk, it is easy to understand that I easily run into MILLIONS of calls to the primitive XRenderFillRectangle. Conclusion: The application takes, for now, around 20 seconds just to render all the stuff, and it is not even half of what I desire to render.
I am pretty sure that this approach I use is completely Wrong, and there must be another way! And I am also pretty sure that that's not the way Cairo or Java2D do it to generate the stuff.
So my question is: How can I prepare and put into a Picture of Xrender images that were generated by the application? Like for example, images loaded from disk?
Can the standard XPutImage function be applied on a Picture of Xrender? Shall I put the data into a Pixmap before generating the Picture? My approaches haven't worked so far.
PS: Please do not recommend me to use a Richer Library such as Cairo or Qt. I am making this question here now because, unfortunately, everytime I find a post regarding this situation, most people's answer is: Use Cairo. I really need to stay as low level as possible with this X11 system. Thank you very much.
Upvotes: 2
Views: 2488
Reputation: 25466
XRenderCreatePicture takes pixmap (or any drawable) as a parameter. In order to draw pixels using xrender, you need:
See libXRender documentation here
Example using node-x11:
var x11 = require('x11');
var Exposure = x11.eventMask.Exposure;
var width = 300;
var height = 300;
var rgb = {
data:new Buffer(width*height*4),
width: width,
height: height
};
var index;
for (var x = 0; x < rgb.width; ++x)
{
for (var y = 0; y < rgb.height; ++y)
{
index = (x + y*rgb.width)*4;
rgb.data[index] = parseInt(Math.sin(13*x/rgb.width)*255);
rgb.data[index+1] = parseInt(Math.cos(15*y/rgb.height)*255);
rgb.data[index+2] = parseInt(Math.cos(16*y/rgb.height)*255);
}
}
x11.createClient(function(err, display)
{
var X = display.client;
X.require('render', function(Render) {
var root = display.screen[0].root;
var win, picWin, pic, gc;
win = X.AllocID();
X.CreateWindow(
win, root,
0, 0, rgb.width, rgb.height,
0, 0, 0, 0,
{ eventMask: Exposure }
);
X.MapWindow(win);
gc = X.AllocID();
X.CreateGC(gc, win);
var rgbPixmap = X.AllocID();
X.CreatePixmap(rgbPixmap, win, 24, rgb.width, rgb.height);
X.PutImage(2, rgbPixmap, gc, rgb.width, rgb.height, 0, 0, 0, 24, rgb.data);
var rgbPicture = X.AllocID();
Render.CreatePicture(rgbPicture, rgbPixmap, Render.rgb24);
var winPicture = X.AllocID();
Render.CreatePicture(winPicture, win, Render.rgb24);
X.on('event', function(ev) {
if (ev.name == 'Expose')
Render.Composite(3, rgbPicture, 0, winPicture, 0, 0, 0, 0, 0, 0, rgb.width, rgb.height);
});
});
});
Upvotes: 3