switched to GPLv3 ONLY, because i don't trust FSF anymore
[amper.git] / utils / custom_ximage.d
blobdaa0db71f2e104f4e9f5483d41f9a852915617d0
1 module bmpx is aliced;
3 import arsd.color;
4 import arsd.simpledisplay;
5 import arsd.image;
7 import iv.cmdcon;
8 import iv.cmdcongl;
10 import iv.vfs;
12 import egfx.base;
13 import egfx.util;
14 import egfx.backx : XlibTCImage;
16 version = custom_img;
19 // ////////////////////////////////////////////////////////////////////////// //
20 // "simple" XImage methods
21 private extern(C) {
22 import core.stdc.config : c_long, c_ulong;
24 XImage* xxsimple_create_image (XDisplay* display, Visual* visual, uint depth, int format, int offset, ubyte* data, uint width, uint height, int bitmap_pad, int bytes_per_line) {
25 return XCreateImage(display, visual, depth, format, offset, data, width, height, bitmap_pad, bytes_per_line);
28 int xxsimple_destroy_image (XImage* ximg) {
29 if (ximg.data !is null) {
30 import core.stdc.stdlib : free;
31 free(ximg.data);
32 ximg.data = null;
34 ximg.width = ximg.height = 0;
35 return 0;
38 c_ulong xxsimple_get_pixel (XImage* ximg, int x, int y) {
39 if (ximg.data is null) return 0;
40 if (x < 0 || y < 0 || x >= ximg.width || y >= ximg.height) return 0;
41 auto buf = cast(const(uint)*)ximg.data;
42 return buf[y*ximg.width+x];
45 int xxsimple_put_pixel (XImage* ximg, int x, int y, c_ulong clr) {
46 if (ximg.data is null) return 0;
47 if (x < 0 || y < 0 || x >= ximg.width || y >= ximg.height) return 0;
48 auto buf = cast(uint*)ximg.data;
49 buf[y*ximg.width+x] = cast(uint)clr;
50 return 0;
53 XImage* xxsimple_sub_image (XImage* ximg, int x, int y, uint wdt, uint hgt) {
54 import core.stdc.stdlib : malloc, free;
55 import core.stdc.string : memset;
56 if (wdt < 1 || hgt < 1) return null;
57 XImage* res = cast(XImage*)malloc(XImage.sizeof);
58 if (res is null) return null;
59 memset(res, 0, XImage.sizeof);
60 ximageCreateSimple(*res, wdt, hgt);
61 foreach (immutable int dy; y..y+hgt) {
62 foreach (immutable int dx; x..x+wdt) {
63 uint clr = 0;
64 if (dx >= 0 && dy >= 0 && dx < ximg.width && dy < ximg.height) clr = cast(uint)ximg.f.get_pixel(ximg, dx, dy);
65 res.f.put_pixel(res, dx-x, dy-y, clr);
68 return res;
71 int xxsimple_add_pixel (XImage* ximg, c_long clr) {
72 if (ximg.data is null) return 0;
73 auto buf = cast(uint*)ximg.data;
74 foreach (ref uint v; buf[0..ximg.width*ximg.height]) v += cast(uint)clr;
75 return 0;
80 // ////////////////////////////////////////////////////////////////////////// //
81 // create "simple" XImage with allocated buffer
82 private void ximageCreateSimple (ref XImage handle, int width, int height) {
83 import core.stdc.stdlib : malloc;
85 if (width < 1) width = 1;
86 if (height < 1) height = 1;
88 auto data = malloc(width*height*4);
89 if (data is null) assert(0, "out of memory");
91 handle.width = width;
92 handle.height = height;
93 handle.xoffset = 0;
94 handle.format = ImageFormat.ZPixmap;
95 handle.data = data;
96 handle.byte_order = 0;
97 handle.bitmap_unit = 0;
98 handle.bitmap_bit_order = 0;
99 handle.bitmap_pad = 0;
100 handle.depth = 24;
101 handle.bytes_per_line = 0;
102 handle.bits_per_pixel = 0; // THIS MATTERS!
103 handle.red_mask = 0;
104 handle.green_mask = 0;
105 handle.blue_mask = 0;
107 handle.obdata = null;
108 handle.f.create_image = &xxsimple_create_image;
109 handle.f.destroy_image = &xxsimple_destroy_image;
110 handle.f.get_pixel = &xxsimple_get_pixel;
111 handle.f.put_pixel = &xxsimple_put_pixel;
112 handle.f.sub_image = &xxsimple_sub_image;
113 handle.f.add_pixel = &xxsimple_add_pixel;
117 // ////////////////////////////////////////////////////////////////////////// //
118 public struct XlibImage {
119 XImage handle;
121 @disable this (this);
123 this (MemoryImage aimg) {
124 if (aimg is null || aimg.width < 1 || aimg.height < 1) throw new Exception("can't create xlib image from empty MemoryImage");
125 create(aimg);
128 this (int wdt, int hgt) {
129 if (wdt < 1 || hgt < 1) throw new Exception("invalid xlib image");
130 create(new TrueColorImage(wdt, hgt));
133 ~this () { dispose(); }
135 @property bool valid () const pure nothrow @trusted @nogc { pragma(inline, true); return (handle.obdata !is null); }
137 @property int width () const pure nothrow @trusted @nogc { pragma(inline, true); return handle.width; }
138 @property int height () const pure nothrow @trusted @nogc { pragma(inline, true); return handle.height; }
140 void setup (MemoryImage aimg) {
141 dispose();
142 if (aimg is null || aimg.width < 1 || aimg.height < 1) throw new Exception("can't create xlib image from empty MemoryImage");
143 create(aimg);
146 private void create (MemoryImage ximg) {
147 handle.width = ximg.width;
148 handle.height = ximg.height;
149 handle.xoffset = 0;
150 handle.format = ImageFormat.ZPixmap;
151 handle.data = null;
152 handle.byte_order = 0;
153 handle.bitmap_unit = 0;
154 handle.bitmap_bit_order = 0;
155 handle.bitmap_pad = 0;
156 handle.depth = 24;
157 handle.bytes_per_line = 0;
158 handle.bits_per_pixel = 0; // THIS MATTERS!
159 handle.red_mask = 0;
160 handle.green_mask = 0;
161 handle.blue_mask = 0;
163 handle.obdata = *cast(void**)&ximg;
164 handle.f.create_image = &xx_create_image;
165 handle.f.destroy_image = &xx_destroy_image;
166 handle.f.get_pixel = &xx_get_pixel;
167 handle.f.put_pixel = &xx_put_pixel;
168 handle.f.sub_image = &xx_sub_image;
169 handle.f.add_pixel = &xx_add_pixel;
172 void dispose () {
173 // note: this calls free(rawData) for us
174 if (handle.obdata !is null) {
175 XDestroyImage(&handle);
176 handle.obdata = null;
180 // blit to window buffer
181 final void blitAt (SimpleWindow w, int destx, int desty) {
182 blitRect(w, destx, desty, GxRect(0, 0, width, height));
185 // blit to window buffer
186 final void blitRect (SimpleWindow w, int destx, int desty, GxRect srect) {
187 if (w is null || handle.obdata is null || w.closed) return;
188 XPutImage(w.impl.display, cast(Drawable)w.impl.buffer, w.impl.gc, &handle, srect.x0, srect.y0, destx, desty, srect.width, srect.height);
191 // blit to window
192 final void blitAtWin (SimpleWindow w, int destx, int desty) {
193 blitRectWin(w, destx, desty, GxRect(0, 0, width, height));
196 // blit to window
197 final void blitRectWin (SimpleWindow w, int destx, int desty, GxRect srect) {
198 if (w is null || handle.obdata is null || w.closed) return;
199 XPutImage(w.impl.display, cast(Drawable)w.impl.window, w.impl.gc, &handle, srect.x0, srect.y0, destx, desty, srect.width, srect.height);
202 static private extern(C):
203 import core.stdc.config : c_long, c_ulong;
205 XImage* xx_create_image (XDisplay* display, Visual* visual, uint depth, int format, int offset, ubyte* data, uint width, uint height, int bitmap_pad, int bytes_per_line) {
206 return XCreateImage(display, visual, depth, format, offset, data, width, height, bitmap_pad, bytes_per_line);
209 int xx_destroy_image (XImage* ximg) {
210 MemoryImage img = *cast(MemoryImage*)&ximg.obdata;
211 if (img !is null) ximg.obdata = null;
212 ximg.width = ximg.height = 0;
213 return 0;
216 c_ulong xx_get_pixel (XImage* ximg, int x, int y) {
217 MemoryImage img = *cast(MemoryImage*)&ximg.obdata;
218 if (img is null) return 0;
219 return img.getPixel(x, y).c2img;
222 int xx_put_pixel (XImage* ximg, int x, int y, c_ulong clr) {
223 MemoryImage img = *cast(MemoryImage*)&ximg.obdata;
224 if (img !is null && x >= 0 && y >= 0 && x < img.width && y < img.height) img.setPixel(x, y, img2c(cast(uint)clr));
225 return 0;
228 XImage* xx_sub_image (XImage* ximg, int x, int y, uint wdt, uint hgt) {
229 return xxsimple_sub_image(ximg, x, y, wdt, hgt);
232 int xx_add_pixel (XImage* ximg, c_long clr) {
233 //assert(0, "xx_add_pixel: alas!");
234 return 1;
239 // ////////////////////////////////////////////////////////////////////////// //
240 version(custom_img) {
241 __gshared XlibImage xlimg;
242 } else {
243 __gshared XlibTCImage xlimg;
247 // ////////////////////////////////////////////////////////////////////////// //
249 public struct EPixmapImpl {
250 Pixmap xpm;
251 private int mWidth, mHeight;
253 this (int wdt, int hgt) {
254 //if (width < 1 || height < 1) throw new Exception("invalid pixmap dimensions");
255 if (wdt < 1) wdt = 1;
256 if (hgt < 1) hgt = 1;
257 if (wdt > 1024) wdt = 1024;
258 if (hgt > 1024) hgt = 1024;
259 xpm = XCreatePixmap(glconCtlWindow.impl.display, cast(Drawable)glconCtlWindow.impl.window, wdt, hgt, 24);
260 mWidth = wdt;
261 mHeight = hgt;
264 this (ref XlibTCImage xtc) {
265 if (!xtc.valid) throw new Exception("can't create pixmap from empty xlib image");
266 int wdt = xtc.width;
267 int hgt = xtc.height;
268 if (wdt < 1) wdt = 1;
269 if (hgt < 1) hgt = 1;
270 if (wdt > 1024) wdt = 1024;
271 if (hgt > 1024) hgt = 1024;
272 xpm = XCreatePixmap(glconCtlWindow.impl.display, cast(Drawable)glconCtlWindow.impl.window, wdt, hgt, 24);
273 // source x, source y
274 XPutImage(glconCtlWindow.impl.display, cast(Drawable)xpm, glconCtlWindow.impl.gc, xtc.handle, 0, 0, 0, 0, wdt, hgt);
275 mWidth = wdt;
276 mHeight = hgt;
279 @disable this (this);
281 ~this () {
282 if (glconCtlWindow is null || glconCtlWindow.closed) { xpm = 0; return; }
283 if (xpm) {
284 XFreePixmap(glconCtlWindow.impl.display, xpm);
285 xpm = 0;
289 @property bool valid () const pure nothrow @trusted @nogc { pragma(inline, true); return (xpm != 0); }
291 @property int width () const pure nothrow @trusted @nogc { pragma(inline, true); return mWidth; }
292 @property int height () const pure nothrow @trusted @nogc { pragma(inline, true); return mHeight; }
294 // blit to window buffer
295 final void blitAt (SimpleWindow w, int x, int y) {
296 blitRect(w, x, y, GxRect(0, 0, width, height));
299 // blit to window buffer
300 final void blitRect (SimpleWindow w, int destx, int desty, GxRect srect) {
301 if (w is null || !xpm || w.closed) return;
302 XCopyArea(w.impl.display, cast(Drawable)xpm, cast(Drawable)w.impl.buffer, w.impl.gc, srect.x0, srect.y0, srect.width, srect.height, destx, desty);
307 public alias EPixmap = KRC!EPixmapImpl;
311 // ////////////////////////////////////////////////////////////////////////// //
312 public class BmpWindow : SimpleWindow {
313 this () {
314 sdpyWindowClass = "BMPVIEW_WINDOW";
315 super(800, 600, "Bitmap Viewer", OpenGlOptions.no, Resizability.allowResizing);
316 setMinSize(800, 60);
317 setupHandlers();
318 glconCtlWindow = this;
319 //glconResize(img.width, img.height);
320 glconCtlWindow.addEventListener((GLConScreenRepaintEvent evt) { redraw(true); });
321 glconCtlWindow.addEventListener((GLConDoConsoleCommandsEvent evt) {
322 scope(exit) if (!conQueueEmpty()) glconPostDoConCommands();
323 glconProcessEventMessage();
324 if (isQuitRequested) { glconCtlWindow.close(); return; }
328 void redraw (bool forceredraw) {
329 if (closed) return;
330 //xlimg.blitAtWin(this, 5, 8);
331 xlimg.blitAt(this, 5, 8);
332 glconDrawWindow = this;
333 glconDrawDirect = false;
334 glconDraw();
335 XCopyArea(this.impl.display, cast(Drawable)this.impl.buffer, cast(Drawable)this.impl.window, this.impl.gc, 0, 0, this.width, this.height, 0, 0);
336 flushGui();
339 protected void setupHandlers () {
340 handleExpose = delegate (int x, int y, int wdt, int hgt, int eventsLeft) {
341 if (eventsLeft == 0) redraw(false);
342 return true;
344 visibilityChanged = delegate (bool visible) {
345 //if (visible) createPixmap(); else freePixmap();
347 handleKeyEvent = delegate (KeyEvent event) {
348 scope(exit) if (!conQueueEmpty()) glconPostDoConCommands();
349 if (glconKeyEvent(event)) { glconPostScreenRepaint(); return; }
350 if (isQuitRequested) { close(); return; }
351 if ((event.modifierState&ModifierState.numLock) == 0) {
352 switch (event.key) {
353 case Key.Pad0: event.key = Key.Insert; break;
354 case Key.Pad1: event.key = Key.End; break;
355 case Key.Pad2: event.key = Key.Down; break;
356 case Key.Pad3: event.key = Key.PageDown; break;
357 case Key.Pad4: event.key = Key.Left; break;
358 //case Key.Pad5: event.key = Key.Insert; break;
359 case Key.Pad6: event.key = Key.Right; break;
360 case Key.Pad7: event.key = Key.Home; break;
361 case Key.Pad8: event.key = Key.Up; break;
362 case Key.Pad9: event.key = Key.PageUp; break;
363 case Key.PadEnter: event.key = Key.Enter; break;
364 case Key.PadDot: event.key = Key.Delete; break;
365 default: break;
367 } else {
368 if (event.key == Key.PadEnter) event.key = Key.Enter;
370 if (event.pressed) {
371 //conwriteln(event.toStr);
372 if (event == "C-Q") { close(); return; }
373 if (event == "Escape") { close(); return; }
377 handleMouseEvent = delegate (MouseEvent event) {
378 scope(exit) if (!conQueueEmpty()) glconPostDoConCommands();
379 if (isQuitRequested) { close(); return; }
382 handleCharEvent = delegate (dchar ch) {
383 scope(exit) if (!conQueueEmpty()) glconPostDoConCommands();
384 if (glconCharEvent(ch)) { glconPostScreenRepaint(); return; }
385 if (isQuitRequested) { close(); return; }
388 windowResized = delegate (int wdt, int hgt) {
389 scope(exit) if (!conQueueEmpty()) glconPostDoConCommands();
390 if (isQuitRequested) { close(); return; }
391 if (wdt < 1) wdt = 1;
392 if (hgt < 1) hgt = 1;
393 glconResize(wdt, hgt);
395 if (backbuf.width != wdt || backbuf.height != hgt) {
396 //createPixmap();
397 //backbuf = new Image(wdt, hgt);
398 //glconBackBuffer = this.backbuf;
401 redraw(false);
404 onFocusChange = delegate (bool focused) {};
409 void main (string[] args) {
410 version(none) {
411 import core.stdc.stdio;
413 printf("%u\n", XImage.sizeof);
415 printf("width: %u\n", XImage.width.offsetof);
416 printf("height: %u\n", XImage.height.offsetof);
417 printf("xoffset: %u\n", XImage.xoffset.offsetof);
418 printf("format: %u\n", XImage.format.offsetof);
419 printf("data: %u\n", XImage.data.offsetof);
420 printf("byte_order: %u\n", XImage.byte_order.offsetof);
421 printf("bitmap_unit: %u\n", XImage.bitmap_unit.offsetof);
422 printf("bitmap_bit_order: %u\n", XImage.bitmap_bit_order.offsetof);
423 printf("bitmap_pad: %u\n", XImage.bitmap_pad.offsetof);
424 printf("depth: %u\n", XImage.depth.offsetof);
425 printf("bytes_per_line: %u\n", XImage.bytes_per_line.offsetof);
426 printf("bits_per_pixel: %u\n", XImage.bits_per_pixel.offsetof);
427 printf("red_mask: %u\n", XImage.red_mask.offsetof);
428 printf("green_mask: %u\n", XImage.green_mask.offsetof);
429 printf("blue_mask: %u\n", XImage.blue_mask.offsetof);
430 printf("obdata: %u\n", XImage.obdata.offsetof);
431 printf("f: %u\n", XImage.f.offsetof);
432 printf("f.create_image: %u\n", XImage.f.offsetof+XImage.f.create_image.offsetof);
433 printf("f.destroy_image: %u\n", XImage.f.offsetof+XImage.f.destroy_image.offsetof);
434 printf("f.get_pixel: %u\n", XImage.f.offsetof+XImage.f.get_pixel.offsetof);
435 printf("f.put_pixel: %u\n", XImage.f.offsetof+XImage.f.put_pixel.offsetof);
436 printf("f.sub_image: %u\n", XImage.f.offsetof+XImage.f.sub_image.offsetof);
437 printf("f.add_pixel: %u\n", XImage.f.offsetof+XImage.f.add_pixel.offsetof);
440 glconAllowOpenGLRender = false;
441 if (args.length == 1) args ~= "EQMAIN.BMP";
443 concmd("r_console tan");
445 conProcessArgs!true(args);
446 conProcessQueue(int.max/4);
448 auto bmp = loadImageFromFile(VFile(args[1]));
449 auto win = new BmpWindow();
450 //glconCtlWindow = win;
452 xlimg.setup(bmp);
453 assert(xlimg.valid);
454 conwriteln("size: ", xlimg.width, "x", xlimg.height);
455 //xlimg.dispose();
456 //return;
459 auto xi = XlibTCImage(bmp);
460 conwriteln("size: ", xi.handle.width, "x", xi.handle.height);
461 conwriteln("xoffset: ", xi.handle.xoffset);
462 conwriteln("format: ", xi.handle.format);
463 conwriteln("byte_order: ", xi.handle.byte_order);
464 conwriteln("bitmap_unit: ", xi.handle.bitmap_unit);
465 conwriteln("bitmap_bit_order: ", xi.handle.bitmap_bit_order);
466 conwriteln("bitmap_pad: ", xi.handle.bitmap_pad);
467 conwriteln("depth: ", xi.handle.depth);
468 conwriteln("bytes_per_line: ", xi.handle.bytes_per_line);
469 conwriteln("bits_per_pixel: ", xi.handle.bits_per_pixel);
470 conwritefln!"red_mask: 0x%08x"(xi.handle.red_mask);
471 conwritefln!"green_mask: 0x%08x"(xi.handle.green_mask);
472 conwritefln!"blue_mask: 0x%08x"(xi.handle.blue_mask);
473 return;
477 flushGui();
478 win.eventLoop(0);
479 flushGui();
480 conProcessQueue(int.max/4);